Adding
This commit is contained in:
@@ -477,19 +477,80 @@ def extract_prompt_text(body: dict, path: str) -> str:
|
||||
return body.get("prompt", "")
|
||||
|
||||
|
||||
def _human_prefix(text: str, max_chars: int = 1000) -> str:
|
||||
"""
|
||||
Extract the human-written prefix of a user message, stopping before any
|
||||
agent-framework context injection (EXTRAS, tool results, structured sections).
|
||||
|
||||
Agent Zero (and similar frameworks) append structured context to the user
|
||||
message after a blank line followed by a section marker. We only want the
|
||||
user's actual words — the first paragraph before any such marker.
|
||||
|
||||
Markers we stop at:
|
||||
\\n\\n[ — Agent Zero [EXTRAS], [context], [solutions], …
|
||||
\\n\\n< — XML-wrapped context blocks
|
||||
\\n--- — horizontal rule separators
|
||||
\\n# or \\n## — markdown headings injected by the framework
|
||||
"""
|
||||
# Structural section delimiters injected by agent frameworks
|
||||
for delim in ("\n\n[", "\n\n<", "\n---", "\n[EXTRAS]", "\n[context]"):
|
||||
idx = text.find(delim)
|
||||
if 0 < idx < max_chars:
|
||||
return text[:idx].strip()
|
||||
return text[:max_chars].strip()
|
||||
|
||||
|
||||
def _is_internal_subcall(user_text: str, sys_text: str = "") -> bool:
|
||||
"""
|
||||
Heuristic: returns True if this looks like an agent-internal sub-call
|
||||
(memory extraction, consolidation, keyword search) rather than a main
|
||||
user-facing turn. We skip recollection injection for these.
|
||||
|
||||
Signals checked in order:
|
||||
1. User message is a JSON/array literal → memory operation payload
|
||||
2. System message is very short → utility prompt, not a full agent
|
||||
personality (Agent Zero's main system prompt is typically >5 000 chars;
|
||||
memory sub-call prompts are usually <1 500 chars)
|
||||
3. System message contains memory-task keywords in the first 200 chars
|
||||
"""
|
||||
# Signal 1: JSON payload
|
||||
if user_text.strip().startswith(("{", "[")):
|
||||
return True
|
||||
|
||||
if sys_text:
|
||||
# Signal 2: system prompt suspiciously short for a real agent call
|
||||
if len(sys_text) < 1500:
|
||||
return True
|
||||
|
||||
# Signal 3: task-oriented system message (memory ops, keyword extraction…)
|
||||
sys_head = sys_text[:200].lower()
|
||||
task_markers = (
|
||||
"extract keyword", "consolidat", "search for similar",
|
||||
"rate the similarity", "memorize", "memory content",
|
||||
)
|
||||
if any(m in sys_head for m in task_markers):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def _last_user_message_text(body: dict, path: str) -> str:
|
||||
"""
|
||||
Extract only the last user message for the write path.
|
||||
Agent responses, thinking traces, and system prompts are excluded —
|
||||
they are noise for concept discovery.
|
||||
Extract only the human-written prefix of the last user message.
|
||||
Agent Zero and similar frameworks append large context sections (EXTRAS,
|
||||
solutions, tool results) after the user's actual words. We stop at the
|
||||
first structural delimiter so that domain tokens in the injected context
|
||||
don't spuriously trigger recollection.
|
||||
"""
|
||||
if path in ("/api/chat", "/v1/chat/completions", "/v1/messages"):
|
||||
messages = body.get("messages", [])
|
||||
last_user = next((m for m in reversed(messages) if m.get("role") == "user"), None)
|
||||
if last_user:
|
||||
return " ".join(_extract_text_strings(last_user.get("content", "")))
|
||||
raw = " ".join(_extract_text_strings(last_user.get("content", "")))
|
||||
return _human_prefix(raw)
|
||||
return ""
|
||||
return body.get("prompt", "")
|
||||
raw = body.get("prompt", "")
|
||||
return _human_prefix(raw)
|
||||
|
||||
|
||||
def _last_assistant_message_text(body: dict, path: str) -> str:
|
||||
@@ -891,11 +952,20 @@ async def process_prompt(
|
||||
if not agent_name:
|
||||
agent_name, _ = _extract_agent_name(body, hdrs) # body already cleaned by route handler
|
||||
|
||||
# Last user message — primary source for recollection reads.
|
||||
# Last user message — human-written prefix only (strips agent framework context).
|
||||
user_text = _last_user_message_text(body, path)
|
||||
if not user_text.strip():
|
||||
return body
|
||||
|
||||
# Skip injection for internal agent sub-calls (memory extraction,
|
||||
# consolidation, keyword search). These are detected by:
|
||||
# - user message being a JSON payload, OR
|
||||
# - system message being very short (utility prompt, not a full agent), OR
|
||||
# - system message starting with memory-task keywords.
|
||||
raw_sys_text = _system_message_text(body, path)
|
||||
if _is_internal_subcall(user_text, raw_sys_text):
|
||||
return body
|
||||
|
||||
# 1. Scan user message for explicit relationship cues (fast, regex-only).
|
||||
for cue in scan_cues(user_text):
|
||||
await enqueue_cue(cue)
|
||||
@@ -912,9 +982,8 @@ async def process_prompt(
|
||||
# Concepts grounding the agent's persona or project context rank higher
|
||||
# in the recollection block for the entire session.
|
||||
session_boost_ids: set[int] = set()
|
||||
sys_text = _system_message_text(body, path)
|
||||
if sys_text:
|
||||
for tok in tokenize(sys_text):
|
||||
if raw_sys_text:
|
||||
for tok in tokenize(raw_sys_text):
|
||||
row = cache.soas_by_token.get(tok)
|
||||
if row and row.saliency > 0.0:
|
||||
session_boost_ids.add(row.id)
|
||||
|
||||
Reference in New Issue
Block a user