mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
fix(agent): give the orchestrator direct memory tools so recall/store don't over-delegate (#4764)
This commit is contained in:
@@ -751,6 +751,28 @@ mod tests {
|
||||
"orchestrator must have read-only direct tool `{direct}`"
|
||||
);
|
||||
}
|
||||
// Direct memory surface (#4762): recall/store are the product's
|
||||
// core and must be first-class direct tools, not a sub-agent
|
||||
// spawn — a trivial recall or a single "remember this" must not
|
||||
// pay a blocking agentic round-trip (over-delegation, #4744) that
|
||||
// can hang or return a 0-char result with persistence unconfirmed.
|
||||
// Deep tree walks / reconciliation still delegate to
|
||||
// `retrieve_memory` / `manage_profile_memory`.
|
||||
for direct in ["memory_recall", "memory_store", "save_preference"] {
|
||||
assert!(
|
||||
tools.iter().any(|t| t == direct),
|
||||
"orchestrator must have direct memory tool `{direct}` (#4762)"
|
||||
);
|
||||
}
|
||||
// Memory-protocol close-out (#4116): a direct `memory_store` write
|
||||
// obliges an `update_memory_md` index reconcile, so the tool that
|
||||
// performs it must be in scope — otherwise the protocol's guidance
|
||||
// is unsatisfiable and MEMORY.md (loaded here) drifts from the store.
|
||||
assert!(
|
||||
tools.iter().any(|t| t == "update_memory_md"),
|
||||
"orchestrator must have `update_memory_md` to reconcile MEMORY.md \
|
||||
after a direct memory_store (#4762)"
|
||||
);
|
||||
}
|
||||
ToolScope::Wildcard => panic!("orchestrator must have named tool allowlist"),
|
||||
}
|
||||
|
||||
@@ -231,6 +231,36 @@ named = [
|
||||
"web_search_tool",
|
||||
"web_fetch",
|
||||
"http_request",
|
||||
# Direct memory surface (#4762). Recall/store are the product's core and must
|
||||
# be first-class DIRECT tools, not a sub-agent spawn: a trivial "what is my Q3
|
||||
# OKR" recall or a "remember my Q3 OKR" write should not pay a blocking
|
||||
# agentic round-trip (over-delegation, #4744) that can hang or — as observed —
|
||||
# spawn `manage_profile_memory` which did 0 tool calls and returned a 0-char
|
||||
# result, leaving the write's persistence unconfirmed. `memory_recall` reads
|
||||
# the same store `memory_store` writes, so store→recall closes the loop inline
|
||||
# with a real confirmation. Deep tree walks / reconciliation / people-graph /
|
||||
# persona edits still delegate to `retrieve_memory` (agent_memory) and
|
||||
# `manage_profile_memory` (profile_memory_agent) below. These are memory-store
|
||||
# writes, NOT file/shell mutation — the "no write tools" rule (below) is about
|
||||
# editing files and running commands, which stays out.
|
||||
"memory_recall",
|
||||
"memory_store",
|
||||
"save_preference",
|
||||
# Memory-protocol close-out (#4116). A successful `memory_store` is a durable
|
||||
# write, so the memory-protocol middleware appends a "call `update_memory_md`
|
||||
# to keep the MEMORY.md index in sync" note to the tool result and warns at run
|
||||
# end if the index was never reconciled. Since the orchestrator now takes the
|
||||
# direct-store path itself, it must own that closing step too — otherwise the
|
||||
# guidance is unsatisfiable and MEMORY.md (which this agent loads,
|
||||
# `omit_memory_md = false`) drifts from the store. `update_memory_md` is locked
|
||||
# to the MEMORY.md / SKILL.md workspace index files (enum-gated, symlink-hardened),
|
||||
# NOT a general file-editor: it is the index-sync counterpart of `memory_store`,
|
||||
# so it belongs in the same memory bucket as the writes above — the "no write
|
||||
# tools" rule (below) is about editing arbitrary files (`edit` / `file_write` /
|
||||
# `apply_patch`) and running commands, which stay out. `save_preference` writes
|
||||
# to the preference store and is deliberately NOT part of the MEMORY.md wiki, so
|
||||
# it needs no reconcile.
|
||||
"update_memory_md",
|
||||
# Managed file-storage transfer surface for passing artifacts/attachments
|
||||
# between chat, users, and workers. Storage lifecycle mutators
|
||||
# (`storage_set_visibility`, `storage_delete_file`) stay out of the broad
|
||||
|
||||
@@ -23,7 +23,8 @@ Follow this sequence for every user message:
|
||||
- **Do this even if remembered context could plausibly answer.** The user wants the live source of truth, not a stale summary.
|
||||
- If the relevant toolkit is **not** in **Connected Integrations**, call `composio_connect { toolkit: "<slug>" }` **directly** to raise an **inline connect card** so the user can authorize in one click, then continue the task once it returns `connected: true`. Do **not** refuse based on the Connected Integrations list (that is only what is *already* connected, not what is *connectable*), do **not** make "go to Settings → Connections" your first move, and do **not** silently fall back to memory retrieval (see "Connecting external services" below).
|
||||
3. **Can I solve this with direct tools?**
|
||||
- Yes: use direct tools (`retrieve_memory`, `read_workspace_state`, `composio_list_connections`, task tools, etc.).
|
||||
- Yes: use direct tools (`memory_recall`, `read_workspace_state`, `composio_list_connections`, task tools, etc.).
|
||||
- **Memory is direct work.** Recalling a fact (`memory_recall`), storing a fact (`memory_store`), or saving a preference (`save_preference`) needs **no sub-agent** — call the direct tool and confirm the result. After a `memory_store` write, follow the memory protocol and call `update_memory_md` (targeting `MEMORY.md`) to keep the index in sync with the store; `save_preference` writes the preference store and needs no such reconcile. Reserve the `retrieve_memory` and `manage_profile_memory` **delegates** for genuinely deep work: multi-hop memory-tree walks, ingest/index into the long-term tree, reconciling overlapping notes, people-graph/alias management, or persona edits. Do **not** spawn a sub-agent for a single recall or a single "remember this".
|
||||
- **Quick lookups are direct work.** Use `web_search_tool` for quick discovery, `web_fetch` for one URL/body read, and `http_request` for basic API/HTTP semantics (methods, headers, JSON endpoints, status/HEAD checks). Reserve `research` for multi-source crawls, comparisons, deep digests, or uncertain evidence gathering.
|
||||
- **Read-only file lookups are direct work.** Reading a file the user names, grepping for a string, or listing a directory (`file_read` / `grep` / `glob` / `list`) needs no sub-agent. Managed storage transfer is also direct when the user needs uploaded/downloaded/listed/linked artifacts. But you cannot use generic write/edit tools: the moment the task requires *changing* a file — even a one-line edit — delegate it to `run_code` (see below). Never promise an edit you cannot make yourself.
|
||||
- **Listing conversation threads is direct work.** "List / show my recent threads (or conversations)" is a single `thread_list` call you make yourself — do **not** delegate it to `retrieve_memory` / a memory sub-agent. Memory retrieval walks the *memory tree* (ingested facts), which is the wrong tool for enumerating chat threads. Reserve `retrieve_memory` for questions about remembered content, not the thread index.
|
||||
|
||||
Reference in New Issue
Block a user