fix(tool-goal): scope the wrap-up no-more-tools clause to the current run
The injected instruction persists as a durable user message, so an unscoped 'Do not call any more tools.' stays in every later request's history. Scope it: '...in this run; further work waits for the user's next instruction.' A/B probes on deepseek-v4-pro show the scoped wording is non-inferior in-turn (4/4 zero tool calls, closing quality unchanged) and next-turn tool use is unaffected under both wordings; the scoped form states the instruction's actual lifetime.
This commit is contained in:
@@ -24,7 +24,7 @@ export function renderWrapupContext(objective: string, blockedReason?: string):
|
||||
+ 'verified, and point to the concrete results (files, commits, or other artifacts). '
|
||||
+ GROUNDING
|
||||
+ 'Note anything the user should review or do next. Address the user directly. Do not '
|
||||
+ 'call any more tools.\n'
|
||||
+ "call any more tools in this run; further work waits for the user's next instruction.\n"
|
||||
+ '</goal_complete>'
|
||||
: '<goal_blocked>\n'
|
||||
+ heading
|
||||
@@ -34,7 +34,8 @@ export function renderWrapupContext(objective: string, blockedReason?: string):
|
||||
+ 'blocking condition and what you tried, and say exactly what you need from the user to '
|
||||
+ 'continue. '
|
||||
+ GROUNDING
|
||||
+ 'Address the user directly. Do not call any more tools.\n'
|
||||
+ 'Address the user directly. Do not call any more tools in this run; further work '
|
||||
+ "waits for the user's next instruction.\n"
|
||||
+ '</goal_blocked>'
|
||||
return [{ type: 'text', text }]
|
||||
}
|
||||
|
||||
@@ -377,7 +377,7 @@ describe('goal tool state transitions', () => {
|
||||
if (block?.type !== 'text') throw new Error('expected one text wrap-up block')
|
||||
expect(block.text).toContain('<goal_complete>')
|
||||
expect(block.text).toContain('"pause cleanly"')
|
||||
expect(block.text).toContain('Do not call any more tools.')
|
||||
expect(block.text).toContain("Do not call any more tools in this run; further work waits for the user's next instruction.")
|
||||
})
|
||||
|
||||
it('completes without a wrap-up instruction under direct human authority', async () => {
|
||||
@@ -578,7 +578,7 @@ describe('goal tool state transitions', () => {
|
||||
if (block?.type !== 'text') throw new Error('expected one text wrap-up block')
|
||||
expect(block.text).toContain('<goal_blocked>')
|
||||
expect(block.text).toContain('The required credential is still unavailable.')
|
||||
expect(block.text).toContain('Do not call any more tools.')
|
||||
expect(block.text).toContain("Do not call any more tools in this run; further work waits for the user's next instruction.")
|
||||
})
|
||||
|
||||
it('lets direct human authority block before the model threshold', async () => {
|
||||
|
||||
Reference in New Issue
Block a user