fix(contextual): narrow tool palette + forbid legacy read tools
Smoke trace 0b46841484ba7d024ed9f8d5ac8b1df0 showed the agent defaulting to list_projects + get_project for a 'summarize project Nexus' query, returning a shallow row without aiSummary or tasks/notes. The legacy read tools were exposed via *PROJECT_TOOLS / *TASK_TOOLS spreading. Now _contextual_tools exposes exactly: - get_page_details (sole read; supports per-entity + list views) - create_task, update_task - create_note - create_timeline Prompt rule 2 explicitly forbids the legacy reads, and the test asserts they are excluded from the palette. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -396,7 +396,7 @@ _CONTEXTUAL_SYSTEM_PROMPT = """You are adiuvAI's contextual assistant. The user
|
||||
|
||||
Rules:
|
||||
1. Base context (current view summary) is provided every turn. Treat it as ground truth for ids and names; never invent them.
|
||||
2. When the user asks about details not in the base context (e.g. "what tasks are blocking the launch milestone"), call `get_page_details` for the relevant entity before answering. Don't guess.
|
||||
2. ALL reads go through `get_page_details`. The legacy tools `list_projects`, `get_project`, `list_tasks`, `get_task`, `list_notes`, `get_note` are NOT available in this channel — do not attempt to call them. To find an entity by name, call `get_page_details({entityType: 'projects_all' | 'tasks_all' | 'timeline_all'})` to list, then `get_page_details({entityType: '<type>', entityId})` for the full snapshot.
|
||||
3. When the user requests an action that creates or updates an entity:
|
||||
- If the current view is a project and no project is specified, use the current project automatically.
|
||||
- If the current view is the global Tasks / Projects / Timeline list and no project is specified, ASK before attaching to any project. Don't silently create orphan entities.
|
||||
@@ -606,25 +606,21 @@ async def get_page_details(
|
||||
def _contextual_tools(user_id: str, trace_id: str | None) -> list[Any]:
|
||||
"""Return the tool palette for the contextual sidebar agent.
|
||||
|
||||
Includes get_page_details, entity-create/update tools, and memory tools.
|
||||
Note-edit tools (propose_note_edit) are intentionally excluded — next sprint.
|
||||
Read ops go through get_page_details only — legacy list_*/get_* tools
|
||||
return shallow snapshots and cause the agent to under-answer (see
|
||||
smoke trace 0b46841484ba7d024ed9f8d5ac8b1df0). Writes are limited
|
||||
to entity creation + task update; note edits are next-sprint.
|
||||
"""
|
||||
from app.agents.note_agent import create_note, list_notes, get_note # noqa: PLC0415
|
||||
from app.agents.task_agent import create_task, update_task, list_tasks # noqa: PLC0415
|
||||
from app.agents.timeline_agent import create_timeline, list_timelines # noqa: PLC0415
|
||||
from app.agents.project_agent import PROJECT_TOOLS # noqa: PLC0415
|
||||
from app.agents.note_agent import create_note # noqa: PLC0415
|
||||
from app.agents.task_agent import create_task, update_task # noqa: PLC0415
|
||||
from app.agents.timeline_agent import create_timeline # noqa: PLC0415
|
||||
|
||||
return [
|
||||
get_page_details,
|
||||
create_task,
|
||||
update_task,
|
||||
list_tasks,
|
||||
create_note,
|
||||
list_notes,
|
||||
get_note,
|
||||
create_timeline,
|
||||
list_timelines,
|
||||
*PROJECT_TOOLS,
|
||||
*_memory_tools(user_id, trace_id),
|
||||
]
|
||||
|
||||
|
||||
@@ -74,3 +74,12 @@ async def test_run_contextual_stream_includes_scope_block(monkeypatch):
|
||||
|
||||
# Note edit tools must NOT be exposed.
|
||||
assert "propose_note_edit" not in names, "propose_note_edit must be excluded"
|
||||
|
||||
# Legacy read tools must be excluded — they return shallow snapshots and
|
||||
# cause the agent to under-answer (see trace 0b46841484ba7d024ed9f8d5ac8b1df0).
|
||||
assert "list_projects" not in names, "list_projects must be excluded (legacy read)"
|
||||
assert "get_project" not in names, "get_project must be excluded (legacy read)"
|
||||
assert "list_tasks" not in names, "list_tasks must be excluded (legacy read)"
|
||||
assert "get_task" not in names, "get_task must be excluded (legacy read)"
|
||||
assert "list_notes" not in names, "list_notes must be excluded (legacy read)"
|
||||
assert "get_note" not in names, "get_note must be excluded (legacy read)"
|
||||
|
||||
Reference in New Issue
Block a user