Merge pull request #3680 from Tibsfox/fix/restore-tools-after-discuss
fix(gsd): restore full tool set after discuss flow scoping
This commit is contained in:
commit
218e53addd
2 changed files with 72 additions and 0 deletions
|
|
@ -295,8 +295,10 @@ async function dispatchWorkflow(
|
|||
// "Grammar is too complex" when the combined tool schema is too large.
|
||||
// Discuss flows only need a small subset of GSD tools — strip the heavy
|
||||
// planning/execution/completion tools to keep the grammar within limits.
|
||||
let savedTools: string[] | null = null;
|
||||
if (unitType?.startsWith("discuss-")) {
|
||||
const currentTools = pi.getActiveTools();
|
||||
savedTools = currentTools;
|
||||
// Keep all non-GSD tools (builtins, other extensions) and only the
|
||||
// GSD tools on the discuss allowlist.
|
||||
const scopedTools = currentTools.filter(
|
||||
|
|
@ -322,6 +324,13 @@ async function dispatchWorkflow(
|
|||
},
|
||||
{ triggerTurn: true },
|
||||
);
|
||||
|
||||
// Restore full tool set after the message is queued. The LLM turn has
|
||||
// already captured the scoped set — restoring prevents the narrowed
|
||||
// tools from leaking into subsequent dispatches (#3628).
|
||||
if (savedTools) {
|
||||
pi.setActiveTools(savedTools);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
* Regression test for #3628 — restore tool set after discuss flow scoping
|
||||
*
|
||||
* The discuss flow narrows the active tool set to avoid "grammar too complex"
|
||||
* errors. Without restoring after sendMessage, the narrowed tools leaked into
|
||||
* subsequent dispatches, breaking plan/execute flows.
|
||||
*
|
||||
* The fix saves the full tool set before scoping and restores it after
|
||||
* sendMessage returns.
|
||||
*/
|
||||
|
||||
import { describe, it } from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { resolve } from 'node:path'
|
||||
|
||||
const src = readFileSync(
|
||||
resolve(process.cwd(), 'src', 'resources', 'extensions', 'gsd', 'guided-flow.ts'),
|
||||
'utf-8',
|
||||
)
|
||||
|
||||
describe('restore tools after discuss flow scoping (#3628)', () => {
|
||||
it('savedTools is declared before the discuss scoping block', () => {
|
||||
// savedTools must be declared before the discuss-* check
|
||||
const savedToolsDecl = src.indexOf('let savedTools')
|
||||
const discussCheck = src.indexOf('if (unitType?.startsWith("discuss-"))')
|
||||
assert.ok(savedToolsDecl !== -1, 'savedTools variable must be declared')
|
||||
assert.ok(discussCheck !== -1, 'discuss-* type check must exist')
|
||||
assert.ok(
|
||||
savedToolsDecl < discussCheck,
|
||||
'savedTools must be declared before the discuss scoping block',
|
||||
)
|
||||
})
|
||||
|
||||
it('savedTools captures current tools inside the discuss block', () => {
|
||||
const discussCheck = src.indexOf('if (unitType?.startsWith("discuss-"))')
|
||||
assert.ok(discussCheck !== -1)
|
||||
|
||||
// Look for savedTools assignment within the discuss block
|
||||
const blockAfter = src.slice(discussCheck, discussCheck + 500)
|
||||
assert.ok(
|
||||
blockAfter.includes('savedTools = currentTools'),
|
||||
'savedTools must be assigned from currentTools inside the discuss block',
|
||||
)
|
||||
})
|
||||
|
||||
it('savedTools is restored after sendMessage', () => {
|
||||
// Find the sendMessage call
|
||||
const sendMsg = src.indexOf('triggerTurn: true')
|
||||
assert.ok(sendMsg !== -1, 'sendMessage with triggerTurn must exist')
|
||||
|
||||
// After sendMessage, savedTools should be restored via setActiveTools
|
||||
const afterSend = src.slice(sendMsg, sendMsg + 500)
|
||||
assert.ok(
|
||||
afterSend.includes('if (savedTools)'),
|
||||
'savedTools restoration guard must exist after sendMessage',
|
||||
)
|
||||
assert.ok(
|
||||
afterSend.includes('setActiveTools(savedTools)'),
|
||||
'setActiveTools(savedTools) must be called to restore the full tool set',
|
||||
)
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Reference in a new issue