Each proposed step now dispatches the serial agent/step-boundary event after claiming input, then agent/model, and publishes the chosen model selection as the optional agent.step until the step ends or its proposal is rejected, fails, or is cancelled. agent/pre-step listeners, tool conditions, prompt sections, and the provider and model variables read agent.step, so the pre-step payload, AssembleContext, and ToolActivationContext carry no model selection field. Plan mode commits pending selections at the step boundary, before model choice, and still narrates the switch in the first admitted step. The system prompt assembles once after step/start, including runtime context, and system-prompt/prepare is removed. The runtime-context snapshot is admitted after the step's accepted messages, so a changed runtime context alone no longer opens a step.
29 lines
1.1 KiB
JavaScript
29 lines
1.1 KiB
JavaScript
/** Activate a native tool after a file read and disable it after its first execution. */
|
|
export const name = 'python-sdk-dynamic-tools'
|
|
export const inject = ['tools']
|
|
|
|
/** @param {import('@deepseek-ai/cordis').Context} ctx - Scenario-owned tool registry. */
|
|
export function apply(ctx) {
|
|
let active = false
|
|
ctx.tools.register({
|
|
name: 'snapshot_ping',
|
|
description: 'Return pong once.',
|
|
parameters: { type: 'object', properties: {}, additionalProperties: false },
|
|
output: {
|
|
schema: { type: 'string' },
|
|
render(_args, value) { return [{ type: 'text', text: value }] },
|
|
},
|
|
async execute() { return 'pong' },
|
|
}, { when: async ({ agent }) => active && agent.step?.modelSelection.provider === 'deepseek-official' })
|
|
ctx.on('tools/post-execute', async (exec, result, next) => {
|
|
const downstream = await next()
|
|
if (result.isError) return downstream
|
|
if (exec.name === 'read' && exec.arguments.file_path === 'dynamic-tool-task.txt') {
|
|
active = true
|
|
} else if (exec.name === 'snapshot_ping') {
|
|
active = false
|
|
}
|
|
return downstream
|
|
})
|
|
}
|