agent: project context replaces the goal, and a turn asks for one thing - #952
Open
spashii wants to merge 1 commit into
Open
agent: project context replaces the goal, and a turn asks for one thing#952spashii wants to merge 1 commit into
spashii wants to merge 1 commit into
Conversation
Two changes to what the assistant puts in front of a host. The goal leaves the agent's surface. proposeGoal and readGoal are gone, and setup now lands on project context through the existing proposeProjectUpdate. Project context is the one thing setup establishes. The server, the revision collection, the BFF endpoints and the frontend section are untouched: the goal is deprecated later, not now, and old chats still render the goal cards they persisted. Retiring a tool is not the same as renaming one. TOOL_NAME_RENAMES maps old names to new so replayed histories do not hit the Vertex 400 on an unregistered function name, and a retired tool has no successor to map onto. So RETIRED_TOOL_NAMES and _strip_retired_tool_calls drop those calls and their paired results at the same replay boundary, before the history reaches Vertex. Transient only: the stored chat is untouched. One thing per turn. A single turn was shipping a steps chip, a three-field proposal, a portal link, a navigation card, a question, a participant link and a QR code. The prompt now holds a turn to one card, never a card paired with a question, and setup to a sequence rather than a dump. And a card never gets placed in words. #843 deleted one hardcoded "below" and the model kept saying it, most recently announcing a shortcut "below" that rendered above. Positional words about a card are now banned outright, and the prompt-rules test pins the ban. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two changes to what a host actually sees in the chat. Both came from Sameer watching one turn do five things at once.
1. Project context is the thing setup establishes, not a goal
His words: "remove the project goal related tools and in the prompts as well, project context should be the thing that is set... we will later deprecate it."
What the host experiences. Setup used to end on a goal proposal, a separate object with its own card, its own revision history and its own place in the product. Now setup ends where the host already lives: the project context field they can see and edit in project settings. Same one-question-at-a-time conversation, same convergent close, but the thing it produces is the context every later answer, transcript and artifact is read against, written back in their own words.
What changed in the agent.
proposeGoalandreadGoalare gone: the tools, their entries intoolsandUI_TOOLS, their line in the tool-taxonomy comment, theget_project_goalclient method and its response type, and every prompt passage that named a goal. Setup lands onproposeProjectUpdatewith thecontextfield, which was already in the editable whitelist (ProjectUpdatein the BFF), so nothing new was built. The interviewing skill and the agent README follow the same rename.What deliberately did not change. The server, the
project_goal_revisioncollection, the BFF endpoints andProjectGoalSectionin the frontend are all untouched. The goal itself is deprecated later, not now. The frontend still parsesproposeGoalresults, so a chat that once proposed a goal still renders that card exactly as it did.The replay-compatibility question, and why this is safe
agent.pycarriesTOOL_NAME_RENAMESwith a warning that Vertex 400s when a replayed tool call or tool result names a function that is no longer registered. That is not a guess:echo/docs/plans/smart-loop-briefs/wave32-tool-renames.mdrecords it as "learned from live Vertex 400s" when six tools were renamed in #837.The map maps old names to new. A retired tool has no successor to be renamed onto, so the map cannot save it, and deleting the tools on their own would have sent a
proposeGoalfunctionCall to Vertex from every chat that ever ran setup.So the same replay boundary now knows about retirement:
RETIRED_TOOL_NAMESlistsproposeGoalandreadGoal._strip_retired_tool_callsdrops those calls from assistant turns and drops the tool results paired with them, by name and by the id of the call it removed, so no result is left orphaned.This is safer than the alternatives. A stub tool kept registered would keep the goal on the model's surface, which is the thing being removed. An entry in the renames map would have to point at some other tool and would lie about what happened. Dropping the call means Vertex never sees the name at all, so the fix holds whether or not Vertex validates names in a given release.
It is transient by construction: the stripping happens on the list handed to the model inside
call_model, and only the new response is returned to state. The stored chat is unchanged and the frontend renders old cards from what it persisted.Live re-verification against Vertex was not possible here (the local ADC needs an interactive reauth), so the mechanism is pinned by tests instead: a history containing
proposeGoalandreadGoalcalls plus their results reaches the model with neither name present, with the surviving calls untouched.2. One thing per turn
He sent a screenshot of a single assistant turn carrying a steps chip, a project-update proposal for three fields, a portal-link chip, a navigation card, and a message holding an explanation, a question, a participant link and a QR code. His reaction: "look at how many things there are! we should take it one by one" and "so many actions for a user!!!"
What the host experiences. One decision at a time. A turn either proposes something or asks something, and the next turn carries whatever is left. A proposal and a navigation shortcut arriving together used to mean the host handled the first and quietly lost the second.
A new prompt section holds the line:
sendProgressUpdateis the stated exception, since a status line while the assistant works is not a decision.Two existing passages that licensed stacking were reconciled rather than left to contradict it: an insight draft is a card and now waits for a free turn, and the canvas fork question may not ride along with a card.
And the "below" bug in the same screenshot
The message said "I have added a quick shortcut to your Overview page below" while the navigation card rendered above it. #843 already removed one hardcoded "below" and the model kept doing it, because the prompt still described cards by position: the canvas section said "directly above or below your message depending on the interface layout", and the tags section said "the host sees the tag proposal below your message".
Both are gone. Positional words about a card are now forbidden outright: below, above, beneath, underneath, at the bottom, at the top, on the right. The assistant refers to a card by what it is ("the suggestion", "the shortcut", "the proposed changes") and never by where it sits, because the frontend decides that and the model cannot know it.
The prompt-rules test now pins this in both directions: the ban has to be stated, and no instruction anywhere may place a card relative to the message again. That is deliberate, since this exact rule regressed once already.
Tests
echo/agent: 133 passed.cd echo/server && uv run ruff check .passes, and ruff is clean overecho/agenttoo.Changed rather than deleted:
test_system_prompt_contains_conversational_and_research_directives: the goal assertions become assertions on the context close, plus"goal" not in promptso the word cannot come back. New assertions pin one-card-per-turn, no-card-with-a-question, and the positional-word ban.test_goal_tools_read_and_return_pure_proposalbecomestest_setup_tools_read_methodologies_and_retire_the_goal_tools: it keeps the methodologies coverage and asserts the goal tools are off the model's surface.test_agent_graph.py: retired calls and their results stripped from a replayed history, a result dropped by call id when it carries no name, a full graph invocation proving the model never sees a retired name, and a guard that retired names are neither registered nor in the renames map.One thing to know
The server still injects
Project Goal:into the first message of every chat (_build_initial_agent_prompt_content). The prompt no longer explains that line, which is correct while the goal is only deprecated on the agent side, but it is the loose end to close when the goal is deprecated for real.🤖 Generated with Claude Code