simbiot-harness/venv/lib/python3.12/site-packages/strands/agent/agent_result.py
Simbiot Harness b60439152b Simbiot Harness v0.1: тактовая лестница на Strands + CQRS/ES-спина
- harness/es.py: append-only event store + проекции (образец — кооп-портал)
- harness/levels.py: уровни 1с/1м/1ч/1д, контекст ∝ масштабу
- harness/scheduler.py: уровневые потоки, идемпотентные тики, absorbed-стабы
- harness/isolated_runner.py + _llm_worker.py: LLM-тик в сабпроцессе
  (глобальный asyncio-рантайм Strands не переживает 2+ create_harness)
- cli.py: init/task/tasks/status/events + requeue (написан самим минутным агентом)
- 9router: отдельный ключ sk-simbiot, модель auto (glm-5.3 первым)
2026-09-29 15:28:50 +00:00

137 lines
5 KiB
Python

"""Agent result handling for SDK.
This module defines the AgentResult class which encapsulates the complete response from an agent's processing cycle.
"""
from collections.abc import Sequence
from dataclasses import dataclass
from typing import Any, cast
from pydantic import BaseModel
from ..experimental.checkpoint import Checkpoint
from ..interrupt import Interrupt
from ..telemetry.metrics import EventLoopMetrics
from ..types.content import Message
from ..types.session import decode_bytes_values, encode_bytes_values
from ..types.streaming import StopReason
@dataclass
class AgentResult:
"""Represents the last result of invoking an agent with a prompt.
Attributes:
stop_reason: The reason why the agent's processing stopped.
message: The last message generated by the agent.
metrics: Performance metrics collected during processing.
state: Additional state information from the event loop.
interrupts: List of interrupts if raised by user.
structured_output: Parsed structured output when structured_output_model was specified.
checkpoint: Checkpoint captured when the agent paused for durable execution.
Populated only when stop_reason == "checkpoint". See
strands.experimental.checkpoint for usage.
"""
stop_reason: StopReason
message: Message
metrics: EventLoopMetrics
state: Any
interrupts: Sequence[Interrupt] | None = None
structured_output: BaseModel | None = None
checkpoint: Checkpoint | None = None
@property
def context_size(self) -> int | None:
"""Most recent context size in tokens from the last LLM call.
Returns:
The total prompt the model processed on the most recent cycle, including cached tokens, or
None if no data is available.
"""
return self.metrics.latest_context_size
@property
def projected_context_size(self) -> int | None:
"""Projected context size for the next model call.
Returns:
The projected token count (total prompt including cached tokens plus generated output), or
None if no data is available.
"""
return self.metrics.projected_context_size
def __str__(self) -> str:
"""Return a string representation of the agent result.
Priority order:
1. Interrupts (if present) → stringified list of interrupt dicts
2. Structured output (if present) → JSON string
3. Text content from message → concatenated text blocks
Returns:
String representation based on the priority order above.
"""
if self.interrupts:
return str([interrupt.to_dict() for interrupt in self.interrupts])
if self.structured_output:
return self.structured_output.model_dump_json()
content_array = self.message.get("content", [])
result = ""
for item in content_array:
if isinstance(item, dict):
if "text" in item:
result += item.get("text", "") + "\n"
elif "citationsContent" in item:
citations_block = item["citationsContent"]
if "content" in citations_block:
for content in citations_block["content"]:
if isinstance(content, dict) and "text" in content:
result += content.get("text", "") + "\n"
return result
@classmethod
def from_dict(cls, data: dict[str, Any]) -> "AgentResult":
"""Rehydrate an AgentResult from persisted JSON.
Args:
data: Dictionary containing the serialized AgentResult data
Returns:
AgentResult instance
Raises:
TypeError: If the data format is invalid
"""
if data.get("type") != "agent_result":
raise TypeError(f"AgentResult.from_dict: unexpected type {data.get('type')!r}")
message = cast(Message, decode_bytes_values(data.get("message")))
stop_reason = cast(StopReason, data.get("stop_reason"))
checkpoint_data = data.get("checkpoint")
checkpoint = Checkpoint.from_dict(checkpoint_data) if checkpoint_data else None
return cls(
message=message,
stop_reason=stop_reason,
metrics=EventLoopMetrics(),
state={},
checkpoint=checkpoint,
)
def to_dict(self) -> dict[str, Any]:
"""Convert this AgentResult to JSON-serializable dictionary.
Binary values in ``message`` (for example Converse ``redactedContent`` blobs)
are base64-encoded with the same helpers used by session persistence.
Returns:
Dictionary containing serialized AgentResult data
"""
return {
"type": "agent_result",
"message": encode_bytes_values(self.message),
"stop_reason": self.stop_reason,
"checkpoint": self.checkpoint.to_dict() if self.checkpoint else None,
}