perf: preserve conversation prefixes across agent turns
This commit is contained in:
1 parent
1440a1f508
commit
f1bb5d02aa
19 files changed
+552
-205
No files matched your search
@@ -18,9 +18,9 @@ Executes autonomous reactive mobile workflows through OpenAI Responses.
|
||||
|
||||
Conversation shape (shared with the Pro operator, history redesign §3.2):
|
||||
the prompt is built every turn from a session :class:`TranscriptLedger` —
|
||||
a byte-stable system prefix, the committed earlier turns (append-only; old UI
|
||||
lists stripped at depth 1, screenshots resolved to visual summaries at depth
|
||||
K, long spans chunk-compressed), and a fresh tail carrying the current
|
||||
a byte-stable system prefix, the committed earlier turns (append-only within
|
||||
a context phase; old observations and long spans compacted together only at
|
||||
pressure thresholds), and a fresh tail carrying the current
|
||||
observation under a ``# CURRENT OBSERVATION [T+mm:ss]`` header. Actions run
|
||||
synchronously and their tool messages already carry the outcome; only a turn
|
||||
whose action failed ends with an ``--- Action Execution Result (T+mm:ss) ---``
|
||||
@@ -30,7 +30,7 @@ session recording.
|
||||
|
||||
Per-turn notices on the tail (the reasoning reminder after a silent turn, the
|
||||
no-tool-call nudge, the final-turn warning, the user-guidance wrapper) are
|
||||
marked ephemeral: the ledger's scrub edge deletes them once the message leaves
|
||||
marked ephemeral: the ledger's compaction pass deletes them when it rewrites
|
||||
the recent window, so they never reach the frozen history or a chunk capsule.
|
||||
The verbatim body of a user instruction is the exception: it stays in the
|
||||
active window until its turn is chunked, whose user lines then carry it on.
|
||||
@@ -83,7 +83,12 @@ from artemis.llm.router import ModelEndpoint
|
||||
from artemis.llm.structured import ParseFailure, parse_structured
|
||||
from artemis.mcp.action_executor import McpActionExecutor
|
||||
from artemis.mcp.observation import DeviceObservationError, require_observation
|
||||
from artemis.memory.transcript import PRO_UI_LIST_MARKER, TranscriptLedger, mark_ephemeral
|
||||
from artemis.memory.transcript import (
|
||||
OBSERVATION_SCOPE_RULE,
|
||||
PRO_UI_LIST_MARKER,
|
||||
TranscriptLedger,
|
||||
mark_ephemeral,
|
||||
)
|
||||
from artemis.services.llm import (
|
||||
RobustChatModelWrapper,
|
||||
acomplete,
|
||||
@@ -272,6 +277,8 @@ class FlashRunner:
|
||||
image_scrub_depth_relaxed=getattr(cfg, "image_scrub_depth_relaxed", None),
|
||||
context_budget_tokens=getattr(cfg, "context_budget_tokens", None),
|
||||
start_ratio=getattr(cfg, "start_ratio", None),
|
||||
soft_ratio=getattr(cfg, "soft_ratio", 0.7),
|
||||
hard_ratio=getattr(cfg, "hard_ratio", 0.9),
|
||||
session_start=session_start if isinstance(session_start, (int, float)) else None,
|
||||
)
|
||||
if engine is not None:
|
||||
@@ -1247,7 +1254,13 @@ class FlashRunner:
|
||||
"""Installs the static prefix and captures the initial device state."""
|
||||
ledger = self._build_ledger()
|
||||
ledger.set_static_prefix(
|
||||
[SystemMessage(content=self._render_system_prompt(tools_declaration))]
|
||||
[
|
||||
SystemMessage(
|
||||
content=self._render_system_prompt(tools_declaration)
|
||||
+ "\n"
|
||||
+ OBSERVATION_SCOPE_RULE
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
# Capture Initial State (Screenshot + UI Tree)
|
||||
@@ -1369,7 +1382,7 @@ class FlashRunner:
|
||||
)
|
||||
pending_notices = []
|
||||
|
||||
# S + F + A + tail: chunk compression and the scrub edge advance here.
|
||||
# S + F + A + tail: history changes only at a compaction boundary.
|
||||
messages = ledger.render([tail])
|
||||
turn_base = len(messages) - 1
|
||||
current_tools = report_only_tools if is_final else self._get_tools()
|
||||
@@ -1427,7 +1440,7 @@ class FlashRunner:
|
||||
# ratio — only from a provider measurement, never from the
|
||||
# estimate (same as the Pro operator).
|
||||
ledger.record_prompt_tokens(
|
||||
step_token_usage.get("prompt_tokens"),
|
||||
step_token_usage.get("prompt_tokens") if measured else None,
|
||||
messages=messages[:-1] if measured else None,
|
||||
)
|
||||
|
||||
|
||||
Reference in new issue
Block a user