fix: improve cross-device evidence, request diagnostics and prompt efficiency
This commit is contained in:
1 parent
621f30e437
commit
a66803651a
60 files changed
+3097
-160
No files matched your search
@@ -295,7 +295,16 @@ class OperatorNode:
|
||||
kwargs_to_pass.update(extra_kwargs)
|
||||
await component(builder, state, self.ctx, **kwargs_to_pass)
|
||||
|
||||
return builder.build()
|
||||
messages = builder.build()
|
||||
if getattr(state, "structured_decisions", None):
|
||||
from langchain_core.messages import HumanMessage
|
||||
|
||||
# The legacy prompt has no preceding AI tool calls. Deliver the
|
||||
# same evidence as observations, without orphan function outputs.
|
||||
for results in self._plugin_result_messages(state.last_execution_result).values():
|
||||
for result in results:
|
||||
messages.append(HumanMessage(content=result.content))
|
||||
return messages
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Transcript prompt path (M2, flag agent.memory.transcript.enabled)
|
||||
@@ -358,6 +367,11 @@ class OperatorNode:
|
||||
pass
|
||||
return ledger
|
||||
|
||||
def _plugin_result_messages(self, report: Any) -> dict[str, list[BaseMessage]]:
|
||||
from artemis.plugins.results import plugin_result_messages
|
||||
|
||||
return plugin_result_messages(report, self.ctx.data_engine)
|
||||
|
||||
async def _build_prompt_transcript(
|
||||
self,
|
||||
state: State,
|
||||
@@ -385,7 +399,15 @@ class OperatorNode:
|
||||
# 1. S region: rendered exactly once per session.
|
||||
if not ledger.has_static_prefix:
|
||||
static_text = render_transcript_static_system(self.prompts, self.ctx, state)
|
||||
ledger.set_static_prefix([SystemMessage(content=static_text)])
|
||||
prefix = []
|
||||
if getattr(self.ctx, "exploration_id", None):
|
||||
from artemis.exploration.runtime import exploration_prompt
|
||||
|
||||
prefix.append(exploration_prompt(self.ctx))
|
||||
if getattr(self.ctx, "plugins", None):
|
||||
prefix.append(self.ctx.plugins.prompt())
|
||||
prefix.append(static_text)
|
||||
ledger.set_static_prefix([SystemMessage(content="\n".join(prefix))])
|
||||
|
||||
# 2. F region cold start: an empty ledger over an existing step record
|
||||
# trail means the process restarted — freeze the compiled history once.
|
||||
@@ -423,10 +445,21 @@ class OperatorNode:
|
||||
ledger.commit_staged(
|
||||
step_key=getattr(state, "current_step_id", None),
|
||||
validator_result=validator_result,
|
||||
tool_results=self._plugin_result_messages(validator_result),
|
||||
)
|
||||
|
||||
# 4. Current tail: observation + plan recitation + injected components.
|
||||
builder = PromptBuilder()
|
||||
guidance = None
|
||||
if getattr(self.ctx, "exploration_id", None):
|
||||
from artemis.exploration.runtime import exploration_messages
|
||||
|
||||
# Guidance belongs at the append-only tail, never before the
|
||||
# reusable rules/history. Assistant progress does not change it.
|
||||
guidance = exploration_messages(self.ctx)[1].content
|
||||
if guidance != getattr(self, "_last_exploration_guidance", None):
|
||||
builder.add_human_content(guidance)
|
||||
self._pending_exploration_guidance = guidance
|
||||
builder.add_human_content(f"# CURRENT OBSERVATION [{ledger.elapsed_label()}]")
|
||||
components = [
|
||||
(PlanRecitationPromptComponent(), {}),
|
||||
@@ -468,6 +501,24 @@ class OperatorNode:
|
||||
mark_ephemeral(tail, builder.ephemeral_indices)
|
||||
|
||||
messages = ledger.render([tail])
|
||||
# Compaction can remove the original guidance message. Restore the
|
||||
# exact current instructions once at the new tail, without changing
|
||||
# the reusable prefix or relying on a lossy history capsule.
|
||||
if guidance is not None and not any(
|
||||
guidance
|
||||
in (
|
||||
message.content
|
||||
if isinstance(message.content, str)
|
||||
else "\n".join(
|
||||
block.get("text", "") for block in message.content if isinstance(block, dict)
|
||||
)
|
||||
)
|
||||
for message in messages
|
||||
if isinstance(message, HumanMessage)
|
||||
):
|
||||
tail_content.append({"type": "text", "text": guidance})
|
||||
tail.content = tail_content
|
||||
self._pending_exploration_guidance = guidance
|
||||
self._transcript_turn_tail = tail
|
||||
return messages
|
||||
|
||||
@@ -482,6 +533,9 @@ class OperatorNode:
|
||||
if ledger is not None:
|
||||
base = next(i for i, message in enumerate(messages) if message is tail)
|
||||
ledger.stage_turn(messages[base:])
|
||||
if hasattr(self, "_pending_exploration_guidance"):
|
||||
self._last_exploration_guidance = self._pending_exploration_guidance
|
||||
del self._pending_exploration_guidance
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to stage transcript turn: {e}")
|
||||
|
||||
@@ -547,7 +601,7 @@ class OperatorNode:
|
||||
t
|
||||
for t in traced_tools
|
||||
if not t.name.startswith("plug_")
|
||||
and t.name not in {"plugin_load", "plugin_read_file"}
|
||||
and t.name not in {"plugin_load", "plugin_read_file", "plugin_read_result"}
|
||||
]
|
||||
traced_tools.extend(plugins.langchain_tools())
|
||||
bound_llm = active_llm.bind_tools(tools=traced_tools)
|
||||
@@ -903,6 +957,9 @@ class OperatorNode:
|
||||
not plan_gate_bounced
|
||||
and iteration < max_iterations - 1
|
||||
and len(action_calls) == 1
|
||||
and not (
|
||||
plugins and plugins.is_read_only(normalize_name(action_calls[0]["name"]))
|
||||
)
|
||||
and not getattr(state, "open_incident", None)
|
||||
and self._plan_changed_this_turn() is False
|
||||
):
|
||||
@@ -1151,14 +1208,16 @@ class OperatorNode:
|
||||
active_background_tasks=active_background_tasks,
|
||||
newly_finished_tasks=newly_finished_tasks,
|
||||
)
|
||||
if getattr(self.ctx, "plugins", None):
|
||||
if self._transcript_turn_tail is None and getattr(self.ctx, "plugins", None):
|
||||
from langchain_core.messages import SystemMessage
|
||||
|
||||
messages.insert(0, SystemMessage(content=self.ctx.plugins.prompt()))
|
||||
if getattr(self.ctx, "exploration_id", None):
|
||||
if self._transcript_turn_tail is None and getattr(self.ctx, "exploration_id", None):
|
||||
from artemis.exploration.runtime import exploration_messages
|
||||
|
||||
messages[0:0] = exploration_messages(self.ctx)
|
||||
rules, guidance = exploration_messages(self.ctx)
|
||||
messages.insert(0, rules)
|
||||
messages.append(guidance)
|
||||
|
||||
# 8. Invoke LLM Loop
|
||||
new_subagent_calls = []
|
||||
@@ -1310,7 +1369,7 @@ class OperatorNode:
|
||||
|
||||
plugins = get_plugin_runtime(self.ctx)
|
||||
if plugins and tool_name in plugins.bindings:
|
||||
return [{"action": tool_name, "args": args}], None
|
||||
return [{"action": tool_name, "args": args, "tool_call_id": tc["id"]}], None
|
||||
|
||||
# Get device resolution fallbacks
|
||||
width = 1080
|
||||
|
||||
Reference in new issue
Block a user