mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-08-29 04:26:38 +00:00
fix: align model selection with current settings remotes
This commit is contained in:
@@ -32,6 +32,7 @@
|
||||
"dsh": {
|
||||
"client": {
|
||||
"inject": [
|
||||
"@deepseek-ai/dsh-client-connection",
|
||||
"@deepseek-ai/dsh-client-locale",
|
||||
"@deepseek-ai/dsh-client-ui-settings",
|
||||
"@deepseek-ai/dsh-api-remotes"
|
||||
@@ -47,6 +48,7 @@
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-connection": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-settings": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
@@ -55,6 +57,7 @@
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-api-remotes": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-connection": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-locale": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-store": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-test-runtime": "workspace:^",
|
||||
|
||||
+5
-1
@@ -280,7 +280,11 @@ export class SubagentModelSelectionCardController {
|
||||
this.publish()
|
||||
await this.scope.mutate([
|
||||
{ op: 'set', path: ['enabled'], value: desiredEnabled },
|
||||
{ op: 'set', path: ['allowedModels'], value: desired },
|
||||
{
|
||||
op: 'set',
|
||||
path: ['allowedModels'],
|
||||
value: desired.map(route => ({ provider: route.provider, model: route.model })),
|
||||
},
|
||||
], this.draftRevision)
|
||||
if (generation !== this.saveGeneration) return
|
||||
const landed = this.currentEnabled() === desiredEnabled && sameRoutes(this.currentRoutes(), desired)
|
||||
|
||||
@@ -188,7 +188,7 @@ describe('SettingsScopeController', () => {
|
||||
|
||||
const write = scope.mutate(ops)
|
||||
ops[0] = { op: 'unset', path: ['enabled'] }
|
||||
;(ops[1] as { value: Array<{ model: string }> }).value[0]!.model = 'changed'
|
||||
;(ops[1] as unknown as { value: Array<{ model: string }> }).value[0]!.model = 'changed'
|
||||
await write
|
||||
|
||||
expect(mutate).toHaveBeenCalledWith(
|
||||
@@ -202,7 +202,7 @@ describe('SettingsScopeController', () => {
|
||||
})
|
||||
|
||||
it('preserves an editor-owned revision fence behind earlier queued writes', async () => {
|
||||
const first = deferred<RpcResponse<SettingsNamespaceView>>()
|
||||
const first = deferred<Answer<SettingsNamespaceView>>()
|
||||
const describeCall = vi.fn()
|
||||
.mockResolvedValueOnce(described({ preference: 'system' }, 7))
|
||||
.mockResolvedValueOnce(described({ preference: 'dark' }, 8))
|
||||
@@ -217,11 +217,12 @@ describe('SettingsScopeController', () => {
|
||||
first.resolve(ok(view({ preference: 'dark' }, 8)))
|
||||
await Promise.all([earlier, fenced])
|
||||
|
||||
expect(mutate).toHaveBeenNthCalledWith(2, {
|
||||
ns: 'ui-test',
|
||||
ops: [{ op: 'set', path: ['preference'], value: 'light' }],
|
||||
expectedRevision: 7,
|
||||
})
|
||||
expect(mutate).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
'ui-test',
|
||||
[{ op: 'set', path: ['preference'], value: 'light' }],
|
||||
7,
|
||||
)
|
||||
expect(scope.getSnapshot()).toMatchObject({ value: { preference: 'dark' }, revision: 8 })
|
||||
})
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Context } from '@deepseek-ai/cordis'
|
||||
import LlmRuntime, { ToolCallId } from '@deepseek-ai/dsh-llm'
|
||||
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
|
||||
import ToolRuntime from '@deepseek-ai/dsh-tools'
|
||||
import type { Agent } from '@deepseek-ai/dsh-agent'
|
||||
import type { Agent, AgentOptions } from '@deepseek-ai/dsh-agent'
|
||||
import AgentLoop from '@deepseek-ai/dsh-agent-loop'
|
||||
import { mountAgentLoopTestDependencies } from '@deepseek-ai/dsh-agent-loop-testkit'
|
||||
import SubagentRuntime from '@deepseek-ai/dsh-subagent'
|
||||
@@ -22,14 +22,18 @@ export function fakeAgent(id = 'parent-1'): Agent {
|
||||
|
||||
/** Mount the real tool and service stack around one scripted subagent provider. */
|
||||
const setupAgents = new WeakMap<Context, Agent>()
|
||||
const setupProviders = new WeakMap<Context, Awaited<ReturnType<typeof mock.mountScriptedProvider>>>()
|
||||
let setupAgentCounter = 0
|
||||
|
||||
/** Test-only opt-in translated to the real Host setting and Session path. */
|
||||
type SetupConfig = tool.Config & { withModelSelection?: boolean }
|
||||
type SetupConfig = tool.Config & {
|
||||
withModelSelection?: boolean
|
||||
parentAgentOptions?: AgentOptions
|
||||
}
|
||||
|
||||
const TEST_ALLOWED_MODELS = [
|
||||
'allowed-model', 'configured-model', 'current-model', 'fast-model', 'other-model',
|
||||
'parent-model', 'unlisted-model',
|
||||
'allowed-model', 'child-model', 'configured-model', 'current-model', 'fast-model',
|
||||
'other-model', 'parent-model', 'selected-model', 'unlisted-model',
|
||||
].flatMap(model => [
|
||||
{ provider: 'alpha', model },
|
||||
{ provider: 'current-provider', model },
|
||||
@@ -38,7 +42,7 @@ const TEST_ALLOWED_MODELS = [
|
||||
|
||||
export async function setup(toolConfig: SetupConfig, mockConfig: Partial<mock.Config> = {}): Promise<Context> {
|
||||
const ctx = new Context()
|
||||
const { withModelSelection, ...config } = toolConfig
|
||||
const { withModelSelection, parentAgentOptions, ...config } = toolConfig
|
||||
if (withModelSelection === true) {
|
||||
await ctx.plugin(SubagentModelSelectionConfig, {
|
||||
enabled: true,
|
||||
@@ -47,9 +51,11 @@ export async function setup(toolConfig: SetupConfig, mockConfig: Partial<mock.Co
|
||||
await mountAgentLoopTestDependencies(ctx)
|
||||
await ctx.plugin(AgentLoop, { agents: [] })
|
||||
await ctx.plugin(SubagentRuntime)
|
||||
await mock.mountScriptedProvider(ctx, { name: 'mock', ...mockConfig })
|
||||
const provider = await mock.mountScriptedProvider(ctx, { name: 'mock', ...mockConfig })
|
||||
setupProviders.set(ctx, provider)
|
||||
const handle = await ctx.agents.create({
|
||||
sessionId: SessionId(`model-selection-setup-${++setupAgentCounter}`),
|
||||
...parentAgentOptions !== undefined ? { agentOptions: parentAgentOptions } : {},
|
||||
setup: async (agentCtx) => {
|
||||
await agentCtx.plugin(tool, { ...config, modelSelectionSettings: true })
|
||||
},
|
||||
@@ -61,11 +67,20 @@ export async function setup(toolConfig: SetupConfig, mockConfig: Partial<mock.Co
|
||||
await ctx.plugin(SystemPrompt)
|
||||
await ctx.plugin(ToolRuntime)
|
||||
await ctx.plugin(SubagentRuntime)
|
||||
await mock.mountScriptedProvider(ctx, { name: 'mock', ...mockConfig })
|
||||
const provider = await mock.mountScriptedProvider(ctx, { name: 'mock', ...mockConfig })
|
||||
setupProviders.set(ctx, provider)
|
||||
await ctx.plugin(tool, config)
|
||||
return ctx
|
||||
}
|
||||
|
||||
/** Dispose the scripted provider mounted by {@link setup}. */
|
||||
export async function disposeSetupProvider(ctx: Context): Promise<void> {
|
||||
const provider = setupProviders.get(ctx)
|
||||
if (provider === undefined) throw new Error('context has no setup provider')
|
||||
setupProviders.delete(ctx)
|
||||
await provider.dispose()
|
||||
}
|
||||
|
||||
/** Return the real Agent created for a settings-controlled setup. */
|
||||
export function modelSelectionSetupAgent(ctx: Context): Agent {
|
||||
const agent = setupAgents.get(ctx)
|
||||
|
||||
@@ -238,4 +238,11 @@ describe('list_subagent_models', () => {
|
||||
expect(text(result)).toContain('available providers: alpha')
|
||||
expect(text(result)).not.toContain('secret')
|
||||
})
|
||||
|
||||
it('reports no available provider when the authorized registry intersection is empty', async () => {
|
||||
const ctx = await setupListTool([{ provider: 'missing', model: 'fast' }])
|
||||
const result = await call(ctx, { provider: 'missing' })
|
||||
expect(result.isError).toBe(true)
|
||||
expect(text(result)).toContain('available providers: (none)')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { Context } from '@deepseek-ai/cordis'
|
||||
import { CallId } from '@deepseek-ai/dsh-llm'
|
||||
import { ToolCallId } from '@deepseek-ai/dsh-llm'
|
||||
import { Session, SessionId } from '@deepseek-ai/dsh-session'
|
||||
import type { SessionEvent } from '@deepseek-ai/dsh-session'
|
||||
import { bindScopeParent, createScope, scopeOf, scopeTarget } from '@deepseek-ai/dsh-scope'
|
||||
@@ -171,7 +171,7 @@ describe('SubagentModelSelectionConfig', () => {
|
||||
|
||||
const result = await ctx.tools.execute({
|
||||
signal: new AbortController().signal,
|
||||
callId: CallId('disallowed-session-route'),
|
||||
callId: ToolCallId('disallowed-session-route'),
|
||||
name: 'subagent',
|
||||
arguments: {
|
||||
description: 'forced route',
|
||||
|
||||
@@ -10,7 +10,11 @@ import { Session, SessionId } from '@deepseek-ai/dsh-session'
|
||||
import { MockAdapter } from '../../../core/agent-loop/tests/mock-adapter.ts'
|
||||
import * as mock from './scripted-provider.ts'
|
||||
import * as tool from '../src/index.ts'
|
||||
import { assertAllowedModelRoutes, assertAllowedModelSelection } from '../src/model-selection.ts'
|
||||
import {
|
||||
assertAllowedModelRoutes,
|
||||
assertAllowedModelSelection,
|
||||
preflightChildLlmRoute,
|
||||
} from '../src/model-selection.ts'
|
||||
import { callSubagent, modelSelectionSetupAgent, setup, text } from './harness.ts'
|
||||
|
||||
const REASONING = {
|
||||
@@ -284,6 +288,12 @@ describe('dsh-tool-subagent model selection', () => {
|
||||
expect(text(result)).toContain('without an effective provider and model')
|
||||
})
|
||||
|
||||
it('rejects preflight without an effective provider and model', async () => {
|
||||
const ctx = await setup({ provider: 'mock' })
|
||||
await expect(preflightChildLlmRoute(ctx.llm, {}, undefined, AbortSignal.abort()))
|
||||
.rejects.toThrow('without an effective provider and model')
|
||||
})
|
||||
|
||||
it.each([
|
||||
{ provider: 'alpha' },
|
||||
{ model: 'fast-model' },
|
||||
|
||||
@@ -4,7 +4,7 @@ import { tmpdir } from 'node:os'
|
||||
import path from 'node:path'
|
||||
import { Context } from '@deepseek-ai/cordis'
|
||||
import Loader from '@deepseek-ai/cordis-plugin-loader'
|
||||
import LlmRuntime, { ToolCallId, ReasoningEffortId } from '@deepseek-ai/dsh-llm'
|
||||
import { ToolCallId, ReasoningEffortId } from '@deepseek-ai/dsh-llm'
|
||||
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
|
||||
import ToolRuntime, { TOOL_ABORTED_BEFORE_DISPATCH } from '@deepseek-ai/dsh-tools'
|
||||
import { assembleContextFor, type Agent } from '@deepseek-ai/dsh-agent'
|
||||
@@ -21,7 +21,15 @@ import { MockAdapter, textResponse } from '../../../core/agent-loop/tests/mock-a
|
||||
import * as mock from './scripted-provider.ts'
|
||||
import * as tool from '../src/index.ts'
|
||||
import { Session, SessionId } from '@deepseek-ai/dsh-session'
|
||||
import { callSubagent, fakeAgent, setup, testToolSignal, text } from './harness.ts'
|
||||
import {
|
||||
callSubagent,
|
||||
disposeSetupProvider,
|
||||
fakeAgent,
|
||||
modelSelectionSetupAgent,
|
||||
setup,
|
||||
testToolSignal,
|
||||
text,
|
||||
} from './harness.ts'
|
||||
|
||||
/**
|
||||
* Drives the REAL plugin body: mounts `dsh-tool-subagent` on a real
|
||||
@@ -221,36 +229,19 @@ describe('dsh-tool-subagent', () => {
|
||||
})
|
||||
|
||||
it('merges model overrides over provider-owned route defaults before preflight', async () => {
|
||||
let seen: { agentOptions?: { provider?: string; model?: string; reasoningEffort?: string; maxTokens?: number } } | undefined
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(LlmRuntime)
|
||||
await ctx.plugin(SystemPrompt)
|
||||
await ctx.plugin(ToolRuntime)
|
||||
await ctx.plugin(SubagentRuntime)
|
||||
ctx.subagents.registerProvider({
|
||||
name: 'capture',
|
||||
capabilities: { agentOptions: true, outputSchema: false, depthLimit: false, toolFilter: false, persona: false },
|
||||
inheritsParentContext: false,
|
||||
let seen: SubagentStartRequest | undefined
|
||||
const ctx = await setup({
|
||||
provider: 'mock',
|
||||
withModelSelection: true,
|
||||
agentOptions: { reasoningEffort: ReasoningEffortId('high'), maxTokens: 321 },
|
||||
maxDepth: 'provider-managed',
|
||||
}, {
|
||||
agentRouteDefaults: { provider: 'alpha', model: 'child-model' },
|
||||
start: async (request) => {
|
||||
seen = request
|
||||
return {
|
||||
id: SessionId('capture-child'),
|
||||
localAgent: undefined,
|
||||
result: Promise.resolve({ output: [{ type: 'text', text: 'ok' }], stopReason: 'completed' as const }),
|
||||
dispose: async () => {},
|
||||
}
|
||||
},
|
||||
onStart: (request) => { seen = request },
|
||||
})
|
||||
ctx.llm.registerAdapter(['alpha'], new MockAdapter([], {
|
||||
efforts: [{ id: ReasoningEffortId('high'), name: 'High' }],
|
||||
}))
|
||||
await ctx.plugin(tool, {
|
||||
provider: 'capture',
|
||||
enableModelSelection: true,
|
||||
agentOptions: { reasoningEffort: ReasoningEffortId('high'), maxTokens: 321 },
|
||||
maxDepth: 'provider-managed',
|
||||
})
|
||||
|
||||
await callSubagent(ctx, {
|
||||
description: 'd',
|
||||
@@ -258,7 +249,7 @@ describe('dsh-tool-subagent', () => {
|
||||
provider: 'alpha',
|
||||
model: 'child-model',
|
||||
})
|
||||
expect(ctx.tools.schemas().find(schema => schema.name === 'subagent')?.description)
|
||||
expect(ctx.tools.schemas(modelSelectionSetupAgent(ctx)).find(schema => schema.name === 'subagent')?.description)
|
||||
.toContain('this provider\'s route defaults')
|
||||
expect(seen?.agentOptions).toEqual({
|
||||
provider: 'alpha',
|
||||
@@ -270,40 +261,21 @@ describe('dsh-tool-subagent', () => {
|
||||
|
||||
it('does not inherit parent effort for a provider-owned route default', async () => {
|
||||
let seen: SubagentStartRequest | undefined
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(LlmRuntime)
|
||||
await ctx.plugin(SystemPrompt)
|
||||
await ctx.plugin(ToolRuntime)
|
||||
await ctx.plugin(SubagentRuntime)
|
||||
ctx.subagents.registerProvider({
|
||||
name: 'provider-defaults',
|
||||
capabilities: { agentOptions: true, outputSchema: false, depthLimit: false, toolFilter: false, persona: false },
|
||||
inheritsParentContext: false,
|
||||
agentRouteDefaults: { provider: 'alpha', model: 'child-model' },
|
||||
start: async (request) => {
|
||||
seen = request
|
||||
return {
|
||||
id: SessionId('provider-default-child'),
|
||||
localAgent: undefined,
|
||||
result: Promise.resolve({ output: [{ type: 'text', text: 'ok' }], stopReason: 'completed' as const }),
|
||||
dispose: async () => {},
|
||||
}
|
||||
},
|
||||
})
|
||||
ctx.llm.registerAdapter(['alpha'], new MockAdapter([]))
|
||||
await ctx.plugin(tool, {
|
||||
provider: 'provider-defaults',
|
||||
enableModelSelection: true,
|
||||
maxDepth: 'provider-managed',
|
||||
})
|
||||
const parent = {
|
||||
...fakeAgent('same-route-parent'),
|
||||
options: {
|
||||
const ctx = await setup({
|
||||
provider: 'mock',
|
||||
withModelSelection: true,
|
||||
parentAgentOptions: {
|
||||
provider: 'alpha',
|
||||
model: 'child-model',
|
||||
reasoningEffort: ReasoningEffortId('high'),
|
||||
},
|
||||
} as Agent
|
||||
maxDepth: 'provider-managed',
|
||||
}, {
|
||||
agentRouteDefaults: { provider: 'alpha', model: 'child-model' },
|
||||
onStart: (request) => { seen = request },
|
||||
})
|
||||
ctx.llm.registerAdapter(['alpha'], new MockAdapter([]))
|
||||
const parent = modelSelectionSetupAgent(ctx)
|
||||
|
||||
const result = await callSubagent(ctx, {
|
||||
description: 'd',
|
||||
@@ -312,6 +284,7 @@ describe('dsh-tool-subagent', () => {
|
||||
model: 'child-model',
|
||||
}, { agent: parent })
|
||||
|
||||
if (result.isError) throw new Error(text(result))
|
||||
expect(result.isError).toBe(false)
|
||||
expect(seen?.agentOptions).toEqual({ provider: 'alpha', model: 'child-model' })
|
||||
})
|
||||
@@ -994,24 +967,15 @@ describe('dsh-tool-subagent background mode', () => {
|
||||
})
|
||||
|
||||
it('rejects startup when the provider changes during asynchronous route preflight', async () => {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(LlmRuntime)
|
||||
await ctx.plugin(SystemPrompt)
|
||||
await ctx.plugin(ToolRuntime)
|
||||
await ctx.plugin(SubagentRuntime)
|
||||
const oldStart = vi.fn(async (): Promise<never> => { throw new Error('old provider must not start') })
|
||||
const oldStart = vi.fn()
|
||||
const replacementStart = vi.fn(async (): Promise<never> => { throw new Error('replacement provider must not start') })
|
||||
const disposeOld = ctx.subagents.registerProvider({
|
||||
name: 'swapped',
|
||||
capabilities: { agentOptions: true, outputSchema: false, depthLimit: false, toolFilter: false, persona: false },
|
||||
inheritsParentContext: false,
|
||||
agentRouteDefaults: { provider: 'alpha', model: 'selected-model' },
|
||||
start: oldStart,
|
||||
})
|
||||
await ctx.plugin(tool, {
|
||||
provider: 'swapped',
|
||||
enableModelSelection: true,
|
||||
const ctx = await setup({
|
||||
provider: 'mock',
|
||||
withModelSelection: true,
|
||||
maxDepth: 'provider-managed',
|
||||
}, {
|
||||
agentRouteDefaults: { provider: 'alpha', model: 'selected-model' },
|
||||
onStart: oldStart,
|
||||
})
|
||||
const adapter = new MockAdapter([])
|
||||
let releasePreflight!: () => void
|
||||
@@ -1029,9 +993,9 @@ describe('dsh-tool-subagent background mode', () => {
|
||||
model: 'selected-model',
|
||||
})
|
||||
await vi.waitFor(() => { expect(resolveModel).toHaveBeenCalledOnce() })
|
||||
disposeOld()
|
||||
await disposeSetupProvider(ctx)
|
||||
ctx.subagents.registerProvider({
|
||||
name: 'swapped',
|
||||
name: 'mock',
|
||||
capabilities: { agentOptions: true, outputSchema: false, depthLimit: false, toolFilter: false, persona: false },
|
||||
inheritsParentContext: false,
|
||||
agentRouteDefaults: { provider: 'beta', model: 'replacement-model' },
|
||||
|
||||
Generated
+3
@@ -3127,6 +3127,9 @@ importers:
|
||||
'@deepseek-ai/dsh-api-remotes':
|
||||
specifier: workspace:^
|
||||
version: link:../../api/remotes
|
||||
'@deepseek-ai/dsh-client-connection':
|
||||
specifier: workspace:^
|
||||
version: link:../connection
|
||||
'@deepseek-ai/dsh-client-locale':
|
||||
specifier: workspace:^
|
||||
version: link:../locale
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":1,"agentInfo":{"name":"deepseek-harness-acp","version":"0.0.1"},"agentCapabilities":{"mcpCapabilities":{"http":true},"promptCapabilities":{"image":false,"audio":false,"embeddedContext":false},"sessionCapabilities":{"close":{},"list":{},"resume":{}}},"authMethods":[]}}
|
||||
{"jsonrpc":"2.0","id":2,"result":{"sessionId":"{{sessionId}}","configOptions":[{"id":"model","name":"Model","category":"model","type":"select","currentValue":"[\"deepseek-official\",\"deepseek-v4-flash\"]","options":[{"group":"deepseek-official","name":"DeepSeek","options":[{"value":"[\"deepseek-official\",\"deepseek-v4-flash\"]","name":"deepseek-v4-flash"},{"value":"[\"deepseek-official\",\"deepseek-v4-pro\"]","name":"deepseek-v4-pro"}]}]}]}}
|
||||
{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call","toolCallId":"call_wait","title":"bash","kind":"other","status":"in_progress","rawInput":{"command":"node -e \"const fs=require('node:fs'); fs.writeFileSync('started.tmp', 'started'); fs.renameSync('started.tmp', 'started.txt'); setInterval(() => {}, 1000)\"","description":"Wait until cancellation"}}}}
|
||||
{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call_update","toolCallId":"call_wait","status":"failed","content":[{"type":"content","content":{"type":"text","text":"Error: tool call aborted"}}]}}}
|
||||
{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call","toolCallId":"call_skipped","title":"bash","kind":"other","status":"in_progress","rawInput":{"command":"printf skipped > skipped.txt","description":"Write skipped marker"}}}}
|
||||
{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"{{sessionId}}","update":{"sessionUpdate":"tool_call_update","toolCallId":"call_skipped","status":"failed","content":[{"type":"content","content":{"type":"text","text":"Error: tool call aborted before dispatch"}}]}}}
|
||||
{"jsonrpc":"2.0","id":3,"result":{"stopReason":"cancelled"}}
|
||||
@@ -260,23 +260,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "list_subagent_models",
|
||||
"description": "Discover LLM routes for subagents without changing the current Agent. Call with no arguments to list registered providers, with `provider` to list its advertised models, or with `provider` and `model` to inspect that exact model and its reasoning efforts. Catalog membership is advisory: an adapter may accept an unlisted model id. Use the returned ids with a delegation tool's `provider`, `model`, and `reasoning_effort` fields.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"provider": {
|
||||
"type": "string",
|
||||
"description": "Registered LLM provider id. Omit to list providers."
|
||||
},
|
||||
"model": {
|
||||
"type": "string",
|
||||
"description": "Exact model id to inspect. Requires provider; omit to list that provider's advertised models."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ralph",
|
||||
"description": "Run a foreground fresh-agent Ralph loop toward one immutable objective. Use only when the direct human explicitly asks for Ralph or fresh-agent iteration. Each round opens a new child with no parent conversation or prior child session; the shared workspace is long-term memory, and only a bounded structured report crosses rounds. The call returns when a worker reports completion or a concrete blocker, or at the round limit. Ordinary long-running same-session work belongs to goal tools.",
|
||||
@@ -504,7 +487,7 @@
|
||||
},
|
||||
{
|
||||
"name": "subagent",
|
||||
"description": "Delegate a self-contained task to a subagent (a separate agent that works in its own context) to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent returns its result, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. This tool runs in the background by default, immediately returns a durable subagent id, and keeps the child conversation available for later turns. When that run settles, the runtime sends the parent a notice containing its outcome and any final assistant message; `send_message` starts a later turn in the same child conversation. Set `run_in_background: false` only when your next action depends on receiving the result. Child LLM selection is optional. Omit `provider`, `model`, and `reasoning_effort` to use configured child defaults and inherit compatible missing values from the parent Agent. Supply `provider` and `model` together after using `list_subagent_models` to inspect advertised routes and efforts. Changing the effective route without naming an effort uses the selected model's default effort.",
|
||||
"description": "Delegate a self-contained task to a subagent (a separate agent that works in its own context) to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent returns its result, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. This tool runs in the background by default, immediately returns a durable subagent id, and keeps the child conversation available for later turns. When that run settles, the runtime sends the parent a notice containing its outcome and any final assistant message; `send_message` starts a later turn in the same child conversation. Set `run_in_background: false` only when your next action depends on receiving the result.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -516,18 +499,6 @@
|
||||
"type": "string",
|
||||
"description": "The complete, self-contained task for the subagent. It does not share this conversation's context, so include everything it needs."
|
||||
},
|
||||
"provider": {
|
||||
"type": "string",
|
||||
"description": "LLM provider route for the child. Supply together with model; omit both to use configured child defaults or inherit the parent route."
|
||||
},
|
||||
"model": {
|
||||
"type": "string",
|
||||
"description": "Model id interpreted by provider. Supply together with provider; omit both to use configured child defaults or inherit the parent route."
|
||||
},
|
||||
"reasoning_effort": {
|
||||
"type": "string",
|
||||
"description": "Adapter-owned reasoning effort for the effective child route. Omit to inherit a compatible configured/parent effort or use a newly selected model's default."
|
||||
},
|
||||
"run_in_background": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to run in the background and return a durable subagent id immediately. Defaults to true. Set false to wait for the result when your next action depends on it."
|
||||
|
||||
@@ -260,23 +260,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "list_subagent_models",
|
||||
"description": "Discover LLM routes for subagents without changing the current Agent. Call with no arguments to list registered providers, with `provider` to list its advertised models, or with `provider` and `model` to inspect that exact model and its reasoning efforts. Catalog membership is advisory: an adapter may accept an unlisted model id. Use the returned ids with a delegation tool's `provider`, `model`, and `reasoning_effort` fields.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"provider": {
|
||||
"type": "string",
|
||||
"description": "Registered LLM provider id. Omit to list providers."
|
||||
},
|
||||
"model": {
|
||||
"type": "string",
|
||||
"description": "Exact model id to inspect. Requires provider; omit to list that provider's advertised models."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ralph",
|
||||
"description": "Run a foreground fresh-agent Ralph loop toward one immutable objective. Use only when the direct human explicitly asks for Ralph or fresh-agent iteration. Each round opens a new child with no parent conversation or prior child session; the shared workspace is long-term memory, and only a bounded structured report crosses rounds. The call returns when a worker reports completion or a concrete blocker, or at the round limit. Ordinary long-running same-session work belongs to goal tools.",
|
||||
@@ -504,7 +487,7 @@
|
||||
},
|
||||
{
|
||||
"name": "subagent",
|
||||
"description": "Delegate a self-contained task to a subagent (a separate agent that works in its own context) to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent returns its result, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. This tool runs in the background by default, immediately returns a durable subagent id, and keeps the child conversation available for later turns. When that run settles, the runtime sends the parent a notice containing its outcome and any final assistant message; `send_message` starts a later turn in the same child conversation. Set `run_in_background: false` only when your next action depends on receiving the result. Child LLM selection is optional. Omit `provider`, `model`, and `reasoning_effort` to use configured child defaults and inherit compatible missing values from the parent Agent. Supply `provider` and `model` together after using `list_subagent_models` to inspect advertised routes and efforts. Changing the effective route without naming an effort uses the selected model's default effort.",
|
||||
"description": "Delegate a self-contained task to a subagent (a separate agent that works in its own context) to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent returns its result, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. This tool runs in the background by default, immediately returns a durable subagent id, and keeps the child conversation available for later turns. When that run settles, the runtime sends the parent a notice containing its outcome and any final assistant message; `send_message` starts a later turn in the same child conversation. Set `run_in_background: false` only when your next action depends on receiving the result.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -516,18 +499,6 @@
|
||||
"type": "string",
|
||||
"description": "The complete, self-contained task for the subagent. It does not share this conversation's context, so include everything it needs."
|
||||
},
|
||||
"provider": {
|
||||
"type": "string",
|
||||
"description": "LLM provider route for the child. Supply together with model; omit both to use configured child defaults or inherit the parent route."
|
||||
},
|
||||
"model": {
|
||||
"type": "string",
|
||||
"description": "Model id interpreted by provider. Supply together with provider; omit both to use configured child defaults or inherit the parent route."
|
||||
},
|
||||
"reasoning_effort": {
|
||||
"type": "string",
|
||||
"description": "Adapter-owned reasoning effort for the effective child route. Omit to inherit a compatible configured/parent effort or use a newly selected model's default."
|
||||
},
|
||||
"run_in_background": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to run in the background and return a durable subagent id immediately. Defaults to true. Set false to wait for the result when your next action depends on it."
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
version: 1
|
||||
scenario: subagent-configured-effort-rejection
|
||||
profile: headless
|
||||
composition: subagent-configured-effort
|
||||
recording: authored
|
||||
header:
|
||||
class: subagent-configured-effort
|
||||
pin: true
|
||||
systemPromptSource: text-turn
|
||||
toolSchemasSource: text-turn
|
||||
replay:
|
||||
override: true
|
||||
Reference in New Issue
Block a user