mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-19 18:45:15 +02:00
multi_agent_chat/main_agent: one specialist per task; advertise write_todos for multi-turn plans
This commit is contained in:
parent
379cc992f4
commit
6b60d324a3
4 changed files with 42 additions and 16 deletions
|
|
@ -9,27 +9,36 @@ simulate one with the other.
|
||||||
the workspace KB).
|
the workspace KB).
|
||||||
- `scrape_webpage` — fetch the body of a specific public URL.
|
- `scrape_webpage` — fetch the body of a specific public URL.
|
||||||
- `update_memory` — curate persistent memory (see `<memory_protocol>`).
|
- `update_memory` — curate persistent memory (see `<memory_protocol>`).
|
||||||
|
- `write_todos` — maintain a structured plan when the turn series spans
|
||||||
|
multiple specialists or steps. Mark each item
|
||||||
|
`in_progress` **before** the `task` call that handles it, `completed`
|
||||||
|
once the call returns. Skip for single-step requests.
|
||||||
|
|
||||||
**You have NO filesystem tools.** Any read, write, edit, move, rename, or
|
**You have NO filesystem tools.** Any read, write, edit, move, rename, or
|
||||||
search inside the user's workspace goes through `task(knowledge_base, …)` —
|
search inside the user's workspace goes through `task(knowledge_base, …)` —
|
||||||
never via `write_file`, `ls`, or any direct file operation.
|
never via `write_file`, `ls`, or any direct file operation.
|
||||||
|
|
||||||
### 2. `task(<specialist>, …)` — specialist subagents
|
### 2. `task(<specialist>, …)` — specialist subagents
|
||||||
Use `task` for anything beyond the four direct tools above. See
|
Use `task` for anything beyond the direct tools above. See
|
||||||
`<specialists>` for the live roster.
|
`<specialists>` for the live roster.
|
||||||
|
|
||||||
Rules for `task`:
|
Rules for `task`:
|
||||||
- **One `task` call per turn.** Bundle related work for the same specialist
|
- **One specialist per `task` call.** A single `task` invocation must
|
||||||
into a single invocation — the parent graph can't coordinate human
|
describe work that one specialist can do end-to-end. Never bundle work
|
||||||
approvals across parallel subagents.
|
for two specialists into one task prompt — the specialist you route to
|
||||||
|
will silently drop the other half.
|
||||||
|
- **One `task` call per turn.** If the user's request spans multiple
|
||||||
|
specialists, handle them one at a time across consecutive turns: invoke
|
||||||
|
the first this turn, return, then invoke the next on your next turn (no
|
||||||
|
user input required between). Use `write_todos` to keep the plan alive
|
||||||
|
across those turns.
|
||||||
|
- Within a single specialist, bundle every related step into the same task
|
||||||
|
prompt (read + write + summary go together).
|
||||||
- Put the **full instructions inside the task prompt** — the specialist
|
- Put the **full instructions inside the task prompt** — the specialist
|
||||||
cannot see this thread.
|
cannot see this thread.
|
||||||
- Don't claim to already know what a specialist's source contains; invoke
|
- Don't claim to already know what a specialist's source contains; invoke
|
||||||
the specialist and use what it returns.
|
the specialist and use what it returns.
|
||||||
|
|
||||||
Parallelism applies to **direct tool calls** (e.g. two `web_search` calls
|
|
||||||
for independent queries can go in parallel). It does **not** apply to `task`.
|
|
||||||
|
|
||||||
<example>
|
<example>
|
||||||
user: "Save these meeting notes to my KB: …"
|
user: "Save these meeting notes to my KB: …"
|
||||||
→ task(knowledge_base, "Save the meeting notes below to a new document
|
→ task(knowledge_base, "Save the meeting notes below to a new document
|
||||||
|
|
@ -54,4 +63,22 @@ user: "Find my Q2 roadmap and summarise the milestones."
|
||||||
and summarise its milestones. Use glob or grep if the path isn't
|
and summarise its milestones. Use glob or grep if the path isn't
|
||||||
obvious from the workspace tree.")
|
obvious from the workspace tree.")
|
||||||
</example>
|
</example>
|
||||||
|
|
||||||
|
<example>
|
||||||
|
user: "Create a ClickUp ticket and a Linear ticket for the new feature flag."
|
||||||
|
→ This turn:
|
||||||
|
write_todos([
|
||||||
|
{content: "Create ClickUp ticket for feature flag rollout", status: "in_progress"},
|
||||||
|
{content: "Create Linear ticket for feature flag rollout", status: "pending"},
|
||||||
|
])
|
||||||
|
task(clickup, "Create a ClickUp ticket titled 'Feature flag rollout'
|
||||||
|
in the default list. Description: <…>. Tell me the ticket URL.")
|
||||||
|
→ Next turn:
|
||||||
|
write_todos([
|
||||||
|
{content: "Create ClickUp ticket for feature flag rollout", status: "completed"},
|
||||||
|
{content: "Create Linear ticket for feature flag rollout", status: "in_progress"},
|
||||||
|
])
|
||||||
|
task(linear, "Create a Linear ticket titled 'Feature flag rollout'
|
||||||
|
in the default team. Description: <…>. Tell me the ticket URL.")
|
||||||
|
</example>
|
||||||
</routing>
|
</routing>
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,5 @@
|
||||||
thread, so include all context and constraints, plus what you need
|
thread, so include all context and constraints, plus what you need
|
||||||
back. The specialist will respond in its own format — don't dictate
|
back. The specialist will respond in its own format — don't dictate
|
||||||
one.
|
one.
|
||||||
- Rules:
|
- Routing rules (when to call, how often, how to scope) live in
|
||||||
- One `task` call per turn. Bundle related work for the same specialist
|
`<routing>`.
|
||||||
into one invocation; the parent graph cannot coordinate human
|
|
||||||
approvals across parallel subagents.
|
|
||||||
- Don't claim to already know what a specialist's source contains;
|
|
||||||
invoke it and use what it returns.
|
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,8 @@ from __future__ import annotations
|
||||||
from langchain.agents.middleware import TodoListMiddleware
|
from langchain.agents.middleware import TodoListMiddleware
|
||||||
|
|
||||||
|
|
||||||
def build_todos_mw() -> TodoListMiddleware:
|
def build_todos_mw(*, system_prompt: str | None = None) -> TodoListMiddleware:
|
||||||
return TodoListMiddleware()
|
"""Pass ``system_prompt=""`` to suppress the upstream prompt append. We use a custom system prompt in the main agent."""
|
||||||
|
if system_prompt is None:
|
||||||
|
return TodoListMiddleware()
|
||||||
|
return TodoListMiddleware(system_prompt=system_prompt)
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@ def build_main_agent_deepagent_middleware(
|
||||||
stack: list[Any] = [
|
stack: list[Any] = [
|
||||||
build_busy_mutex_mw(flags),
|
build_busy_mutex_mw(flags),
|
||||||
build_otel_mw(flags),
|
build_otel_mw(flags),
|
||||||
build_todos_mw(),
|
build_todos_mw(system_prompt=""),
|
||||||
memory_mw,
|
memory_mw,
|
||||||
build_anonymous_doc_mw(
|
build_anonymous_doc_mw(
|
||||||
filesystem_mode=filesystem_mode, anon_session_id=anon_session_id
|
filesystem_mode=filesystem_mode, anon_session_id=anon_session_id
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue