@agentuity/opencode 1.0.16 → 1.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/architect.d.ts +1 -1
- package/dist/agents/architect.d.ts.map +1 -1
- package/dist/agents/architect.js +30 -33
- package/dist/agents/architect.js.map +1 -1
- package/dist/agents/builder.d.ts +1 -1
- package/dist/agents/builder.d.ts.map +1 -1
- package/dist/agents/builder.js +53 -60
- package/dist/agents/builder.js.map +1 -1
- package/dist/agents/expert-backend.d.ts +1 -1
- package/dist/agents/expert-backend.d.ts.map +1 -1
- package/dist/agents/expert-backend.js +31 -39
- package/dist/agents/expert-backend.js.map +1 -1
- package/dist/agents/expert-frontend.d.ts +1 -1
- package/dist/agents/expert-frontend.d.ts.map +1 -1
- package/dist/agents/expert-frontend.js +17 -23
- package/dist/agents/expert-frontend.js.map +1 -1
- package/dist/agents/expert-ops.d.ts +1 -1
- package/dist/agents/expert-ops.d.ts.map +1 -1
- package/dist/agents/expert-ops.js +36 -50
- package/dist/agents/expert-ops.js.map +1 -1
- package/dist/agents/expert.d.ts +1 -1
- package/dist/agents/expert.d.ts.map +1 -1
- package/dist/agents/expert.js +32 -42
- package/dist/agents/expert.js.map +1 -1
- package/dist/agents/lead.d.ts +1 -1
- package/dist/agents/lead.d.ts.map +1 -1
- package/dist/agents/lead.js +179 -222
- package/dist/agents/lead.js.map +1 -1
- package/dist/agents/memory.d.ts +1 -1
- package/dist/agents/memory.d.ts.map +1 -1
- package/dist/agents/memory.js +62 -90
- package/dist/agents/memory.js.map +1 -1
- package/dist/agents/monitor.d.ts +1 -1
- package/dist/agents/monitor.d.ts.map +1 -1
- package/dist/agents/monitor.js +93 -42
- package/dist/agents/monitor.js.map +1 -1
- package/dist/agents/product.d.ts +1 -1
- package/dist/agents/product.d.ts.map +1 -1
- package/dist/agents/product.js +16 -22
- package/dist/agents/product.js.map +1 -1
- package/dist/agents/reviewer.d.ts +1 -1
- package/dist/agents/reviewer.d.ts.map +1 -1
- package/dist/agents/reviewer.js +14 -26
- package/dist/agents/reviewer.js.map +1 -1
- package/dist/agents/runner.d.ts +1 -1
- package/dist/agents/runner.d.ts.map +1 -1
- package/dist/agents/runner.js +52 -76
- package/dist/agents/runner.js.map +1 -1
- package/dist/agents/scout.d.ts +1 -1
- package/dist/agents/scout.d.ts.map +1 -1
- package/dist/agents/scout.js +41 -42
- package/dist/agents/scout.js.map +1 -1
- package/dist/agents/types.d.ts +8 -0
- package/dist/agents/types.d.ts.map +1 -1
- package/dist/background/manager.d.ts +17 -0
- package/dist/background/manager.d.ts.map +1 -1
- package/dist/background/manager.js +144 -10
- package/dist/background/manager.js.map +1 -1
- package/dist/background/types.d.ts +3 -0
- package/dist/background/types.d.ts.map +1 -1
- package/dist/config/loader.js +2 -2
- package/dist/plugin/hooks/cadence.d.ts.map +1 -1
- package/dist/plugin/hooks/cadence.js +5 -9
- package/dist/plugin/hooks/cadence.js.map +1 -1
- package/dist/plugin/hooks/completion.d.ts +14 -0
- package/dist/plugin/hooks/completion.d.ts.map +1 -0
- package/dist/plugin/hooks/completion.js +45 -0
- package/dist/plugin/hooks/completion.js.map +1 -0
- package/dist/plugin/hooks/params.d.ts +46 -1
- package/dist/plugin/hooks/params.d.ts.map +1 -1
- package/dist/plugin/hooks/params.js +77 -0
- package/dist/plugin/hooks/params.js.map +1 -1
- package/dist/plugin/hooks/session-memory.d.ts.map +1 -1
- package/dist/plugin/hooks/session-memory.js +4 -0
- package/dist/plugin/hooks/session-memory.js.map +1 -1
- package/dist/plugin/hooks/tools.d.ts.map +1 -1
- package/dist/plugin/hooks/tools.js +26 -1
- package/dist/plugin/hooks/tools.js.map +1 -1
- package/dist/plugin/plugin.d.ts.map +1 -1
- package/dist/plugin/plugin.js +9 -2
- package/dist/plugin/plugin.js.map +1 -1
- package/dist/tools/background.d.ts.map +1 -1
- package/dist/tools/background.js +15 -0
- package/dist/tools/background.js.map +1 -1
- package/dist/types.d.ts +10 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +3 -3
- package/src/agents/architect.ts +30 -33
- package/src/agents/builder.ts +53 -60
- package/src/agents/expert-backend.ts +31 -39
- package/src/agents/expert-frontend.ts +17 -23
- package/src/agents/expert-ops.ts +36 -50
- package/src/agents/expert.ts +32 -42
- package/src/agents/lead.ts +179 -222
- package/src/agents/memory.ts +62 -90
- package/src/agents/monitor.ts +93 -42
- package/src/agents/product.ts +16 -22
- package/src/agents/reviewer.ts +14 -26
- package/src/agents/runner.ts +52 -76
- package/src/agents/scout.ts +41 -42
- package/src/agents/types.ts +8 -0
- package/src/background/manager.ts +163 -10
- package/src/background/types.ts +3 -0
- package/src/config/loader.ts +2 -2
- package/src/plugin/hooks/cadence.ts +5 -9
- package/src/plugin/hooks/completion.ts +61 -0
- package/src/plugin/hooks/params.ts +97 -1
- package/src/plugin/hooks/session-memory.ts +4 -0
- package/src/plugin/hooks/tools.ts +32 -1
- package/src/plugin/plugin.ts +9 -2
- package/src/tools/background.ts +28 -0
- package/src/types.ts +10 -0
package/src/config/loader.ts
CHANGED
|
@@ -146,7 +146,7 @@ const DEFAULT_BLOCKED_COMMANDS = [
|
|
|
146
146
|
|
|
147
147
|
const DEFAULT_BACKGROUND_CONFIG: BackgroundTaskConfig = {
|
|
148
148
|
enabled: true,
|
|
149
|
-
defaultConcurrency:
|
|
149
|
+
defaultConcurrency: 5,
|
|
150
150
|
staleTimeoutMs: 30 * 60 * 1000,
|
|
151
151
|
providerConcurrency: {},
|
|
152
152
|
modelConcurrency: {},
|
|
@@ -199,7 +199,7 @@ function mergeBackgroundConfig(
|
|
|
199
199
|
if (!base && !override) return undefined;
|
|
200
200
|
return {
|
|
201
201
|
enabled: override?.enabled ?? base?.enabled ?? true,
|
|
202
|
-
defaultConcurrency: override?.defaultConcurrency ?? base?.defaultConcurrency ??
|
|
202
|
+
defaultConcurrency: override?.defaultConcurrency ?? base?.defaultConcurrency ?? 5,
|
|
203
203
|
staleTimeoutMs: override?.staleTimeoutMs ?? base?.staleTimeoutMs ?? 30 * 60 * 1000,
|
|
204
204
|
providerConcurrency: {
|
|
205
205
|
...(base?.providerConcurrency ?? {}),
|
|
@@ -197,7 +197,10 @@ export function createCadenceHooks(
|
|
|
197
197
|
|
|
198
198
|
log(`Event received: ${event.type}`);
|
|
199
199
|
|
|
200
|
-
// Handle session.compacted - save compaction AND continue loop
|
|
200
|
+
// Handle session.compacted - save compaction AND continue loop.
|
|
201
|
+
// Note: Compaction continues in the SAME session (via session.prompt with
|
|
202
|
+
// the existing sessionId), so permissions configured in the config hook
|
|
203
|
+
// (plugin.ts) are automatically inherited — no re-application needed.
|
|
201
204
|
if (event.type === 'session.compacted') {
|
|
202
205
|
const sessionId = event.sessionId;
|
|
203
206
|
if (!sessionId) return;
|
|
@@ -379,14 +382,7 @@ ${taskList}
|
|
|
379
382
|
Use \`agentuity_background_output({ task_id: "..." })\` to check their status.
|
|
380
383
|
Use \`agentuity_session_dashboard({ session_id: "..." })\` to get a full session tree with status, costs, and health summary for Lead-of-Leads monitoring.
|
|
381
384
|
|
|
382
|
-
**Tip:**
|
|
383
|
-
\`\`\`typescript
|
|
384
|
-
agentuity_background_task({
|
|
385
|
-
agent: "monitor",
|
|
386
|
-
task: "Monitor these background tasks and report when all complete:\\n${tasks.map((t) => `- ${t.id}`).join('\\n')}",
|
|
387
|
-
description: "Monitor child tasks"
|
|
388
|
-
})
|
|
389
|
-
\`\`\``;
|
|
385
|
+
**Tip:** A Monitor agent is auto-launched to watch these tasks. You will receive \`[BACKGROUND TASK COMPLETED]\` notifications as each task finishes, and \`[ALL BACKGROUND TASKS COMPLETE]\` when all are done. Use \`agentuity_session_dashboard\` for a unified progress view.`;
|
|
390
386
|
}
|
|
391
387
|
|
|
392
388
|
// 5. Build SQLite dashboard section
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { PluginInput } from '@opencode-ai/plugin';
|
|
2
|
+
import type { CoderConfig } from '../../types';
|
|
3
|
+
|
|
4
|
+
export interface CompletionHooks {
|
|
5
|
+
onParams: (input: unknown) => void;
|
|
6
|
+
onMessage: (input: unknown) => void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Creates hooks for logging agent completion metrics.
|
|
11
|
+
*
|
|
12
|
+
* Tracks the start of each LLM call (via chat.params) and logs
|
|
13
|
+
* agent name, model, and duration when the response arrives (via chat.message).
|
|
14
|
+
*/
|
|
15
|
+
export function createCompletionHooks(ctx: PluginInput, _config: CoderConfig): CompletionHooks {
|
|
16
|
+
const startTimes = new Map<string, { startedAt: number; agent?: string; model?: string }>();
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
onParams(input: unknown): void {
|
|
20
|
+
const inp = input as {
|
|
21
|
+
sessionID?: string;
|
|
22
|
+
agent?: string;
|
|
23
|
+
model?: string;
|
|
24
|
+
};
|
|
25
|
+
if (!inp.sessionID) return;
|
|
26
|
+
startTimes.set(inp.sessionID, {
|
|
27
|
+
startedAt: Date.now(),
|
|
28
|
+
agent: inp.agent,
|
|
29
|
+
model: inp.model,
|
|
30
|
+
});
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
onMessage(input: unknown): void {
|
|
34
|
+
const inp = input as { sessionID?: string };
|
|
35
|
+
if (!inp.sessionID) return;
|
|
36
|
+
|
|
37
|
+
const start = startTimes.get(inp.sessionID);
|
|
38
|
+
if (!start) return;
|
|
39
|
+
|
|
40
|
+
const durationMs = Date.now() - start.startedAt;
|
|
41
|
+
const durationSec = (durationMs / 1000).toFixed(1);
|
|
42
|
+
|
|
43
|
+
const logLine = `Completion: agent=${start.agent ?? 'unknown'} model=${start.model ?? 'unknown'} duration=${durationSec}s`;
|
|
44
|
+
|
|
45
|
+
// Verbose local logging for immediate visibility
|
|
46
|
+
console.debug(`[agentuity-coder] ${logLine}`);
|
|
47
|
+
|
|
48
|
+
// Also send to the OpenCode log service
|
|
49
|
+
ctx.client.app.log({
|
|
50
|
+
body: {
|
|
51
|
+
service: 'agentuity-coder',
|
|
52
|
+
level: 'debug',
|
|
53
|
+
message: logLine,
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Clean up after logging
|
|
58
|
+
startTimes.delete(inp.sessionID);
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PluginInput } from '@opencode-ai/plugin';
|
|
2
|
-
import type { CoderConfig } from '../../types';
|
|
2
|
+
import type { AgentConfig, CoderConfig } from '../../types';
|
|
3
3
|
|
|
4
4
|
export interface ParamsHooks {
|
|
5
5
|
onParams: (input: unknown, output: unknown) => Promise<void>;
|
|
@@ -199,3 +199,99 @@ export function createParamsHooks(
|
|
|
199
199
|
*
|
|
200
200
|
* Note: Triggers use multi-word phrases to avoid false positives from common words.
|
|
201
201
|
*/
|
|
202
|
+
|
|
203
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
204
|
+
// Model Fallback Chain
|
|
205
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
206
|
+
|
|
207
|
+
/** Retryable HTTP status codes that should trigger model fallback */
|
|
208
|
+
export const RETRYABLE_STATUS_CODES = [429, 500, 502, 503] as const;
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Tracks API errors per agent to enable model fallback on subsequent calls.
|
|
212
|
+
*
|
|
213
|
+
* When an agent's primary model fails with a retryable error (429, 500, 502, 503),
|
|
214
|
+
* the next `chat.params` call can select a fallback model from the agent's
|
|
215
|
+
* `fallbackModels` list.
|
|
216
|
+
*
|
|
217
|
+
* Current limitation: The `chat.params` hook can modify temperature/topP/topK/options
|
|
218
|
+
* but CANNOT change the model itself (model is in the input, not output). Full model
|
|
219
|
+
* fallback requires one of:
|
|
220
|
+
* 1. A `chat.error` hook that allows retrying with a different model
|
|
221
|
+
* 2. A `chat.model` hook that allows overriding the model selection
|
|
222
|
+
* 3. Adding `model` to the `chat.params` output type
|
|
223
|
+
*
|
|
224
|
+
* TODO: When OpenCode adds a suitable hook, implement the retry logic here:
|
|
225
|
+
* - On API error (429/5xx), record the failure in `agentErrorState`
|
|
226
|
+
* - On next `chat.params` call for the same agent, select next fallback model
|
|
227
|
+
* - Log: `[ModelFallback] Switching from ${currentModel} to ${fallbackModel} due to ${error}`
|
|
228
|
+
* - Reset fallback state after successful completion or after TTL expires
|
|
229
|
+
*/
|
|
230
|
+
export class ModelFallbackTracker {
|
|
231
|
+
/**
|
|
232
|
+
* Map of agent name → { failedModel, failedAt, errorCode, fallbackIndex }
|
|
233
|
+
* Used to track which agents have experienced API errors.
|
|
234
|
+
*/
|
|
235
|
+
private agentErrorState = new Map<
|
|
236
|
+
string,
|
|
237
|
+
{
|
|
238
|
+
failedModel: string;
|
|
239
|
+
failedAt: number;
|
|
240
|
+
errorCode: number;
|
|
241
|
+
fallbackIndex: number;
|
|
242
|
+
}
|
|
243
|
+
>();
|
|
244
|
+
|
|
245
|
+
/** TTL for error state — reset after 5 minutes */
|
|
246
|
+
private readonly ERROR_STATE_TTL_MS = 5 * 60 * 1000;
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Record an API error for an agent. Call this from an event handler
|
|
250
|
+
* when a retryable API error is detected.
|
|
251
|
+
*/
|
|
252
|
+
recordError(agentName: string, model: string, errorCode: number): void {
|
|
253
|
+
const existing = this.agentErrorState.get(agentName);
|
|
254
|
+
const fallbackIndex = existing ? existing.fallbackIndex + 1 : 0;
|
|
255
|
+
this.agentErrorState.set(agentName, {
|
|
256
|
+
failedModel: model,
|
|
257
|
+
failedAt: Date.now(),
|
|
258
|
+
errorCode,
|
|
259
|
+
fallbackIndex,
|
|
260
|
+
});
|
|
261
|
+
console.debug(
|
|
262
|
+
`[ModelFallback] Recorded error for ${agentName}: model=${model} code=${errorCode} fallbackIndex=${fallbackIndex}`
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Get the next fallback model for an agent, if one is available.
|
|
268
|
+
* Returns undefined if no fallback is needed or available.
|
|
269
|
+
*/
|
|
270
|
+
getNextFallback(agentName: string, agentConfig: AgentConfig): string | undefined {
|
|
271
|
+
const state = this.agentErrorState.get(agentName);
|
|
272
|
+
if (!state) return undefined;
|
|
273
|
+
|
|
274
|
+
// Check TTL
|
|
275
|
+
if (Date.now() - state.failedAt > this.ERROR_STATE_TTL_MS) {
|
|
276
|
+
this.agentErrorState.delete(agentName);
|
|
277
|
+
return undefined;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const fallbacks = agentConfig.fallbackModels;
|
|
281
|
+
if (!fallbacks?.length) return undefined;
|
|
282
|
+
|
|
283
|
+
if (state.fallbackIndex >= fallbacks.length) {
|
|
284
|
+
// Exhausted all fallbacks
|
|
285
|
+
return undefined;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return fallbacks[state.fallbackIndex];
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Clear error state for an agent (e.g., after successful completion).
|
|
293
|
+
*/
|
|
294
|
+
clearError(agentName: string): void {
|
|
295
|
+
this.agentErrorState.delete(agentName);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
@@ -51,6 +51,10 @@ export function createSessionMemoryHooks(
|
|
|
51
51
|
/**
|
|
52
52
|
* Listen for session.compacted event.
|
|
53
53
|
* The compaction summary is already in context - just tell Lead to save it.
|
|
54
|
+
*
|
|
55
|
+
* Note: Compaction continues in the SAME session (via session.prompt with
|
|
56
|
+
* the existing sessionId), so permissions configured in the config hook
|
|
57
|
+
* (plugin.ts) are automatically inherited — no re-application needed.
|
|
54
58
|
*/
|
|
55
59
|
async onEvent(input: {
|
|
56
60
|
event: { type: string; properties?: Record<string, unknown> };
|
|
@@ -165,7 +165,38 @@ export function createToolHooks(ctx: PluginInput, config: CoderConfig): ToolHook
|
|
|
165
165
|
}
|
|
166
166
|
},
|
|
167
167
|
|
|
168
|
-
async after(
|
|
168
|
+
async after(input: unknown, output: unknown): Promise<void> {
|
|
169
|
+
// Graceful handling for unavailable tools: if a tool execution produced an
|
|
170
|
+
// error indicating the tool doesn't exist or is unavailable, normalize the
|
|
171
|
+
// output to a helpful message so the session continues instead of crashing.
|
|
172
|
+
const toolName = extractToolName(input);
|
|
173
|
+
if (!toolName) return;
|
|
174
|
+
|
|
175
|
+
const out = output as {
|
|
176
|
+
output?: string;
|
|
177
|
+
title?: string;
|
|
178
|
+
metadata?: Record<string, unknown>;
|
|
179
|
+
};
|
|
180
|
+
if (typeof out.output !== 'string') return;
|
|
181
|
+
|
|
182
|
+
const lower = out.output.toLowerCase();
|
|
183
|
+
const isToolMissing =
|
|
184
|
+
(lower.includes('not found') ||
|
|
185
|
+
lower.includes('not available') ||
|
|
186
|
+
lower.includes('does not exist') ||
|
|
187
|
+
lower.includes('unknown tool') ||
|
|
188
|
+
lower.includes('no such tool')) &&
|
|
189
|
+
(lower.includes('tool') || lower.includes(toolName.toLowerCase()));
|
|
190
|
+
|
|
191
|
+
if (isToolMissing) {
|
|
192
|
+
out.output = JSON.stringify({
|
|
193
|
+
error: `Tool '${toolName}' is not available in this session. It may have been removed or is not installed. Please use an alternative approach or ask the user for guidance.`,
|
|
194
|
+
tool: toolName,
|
|
195
|
+
recoverable: true,
|
|
196
|
+
});
|
|
197
|
+
out.title = `Tool unavailable: ${toolName}`;
|
|
198
|
+
}
|
|
199
|
+
},
|
|
169
200
|
};
|
|
170
201
|
}
|
|
171
202
|
|
package/src/plugin/plugin.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { createKeywordHooks } from './hooks/keyword';
|
|
|
15
15
|
import { createParamsHooks } from './hooks/params';
|
|
16
16
|
import { createCadenceHooks } from './hooks/cadence';
|
|
17
17
|
import { createSessionMemoryHooks } from './hooks/session-memory';
|
|
18
|
+
import { createCompletionHooks } from './hooks/completion';
|
|
18
19
|
import type { AgentRole } from '../types';
|
|
19
20
|
import { BackgroundManager } from '../background';
|
|
20
21
|
import type { SessionTreeNode } from '../sqlite';
|
|
@@ -99,7 +100,8 @@ export async function createCoderPlugin(ctx: PluginInput): Promise<Hooks> {
|
|
|
99
100
|
const sessionHooks = createSessionHooks(ctx, coderConfig);
|
|
100
101
|
const toolHooks = createToolHooks(ctx, coderConfig);
|
|
101
102
|
const keywordHooks = createKeywordHooks(ctx, coderConfig);
|
|
102
|
-
const paramsHooks = createParamsHooks(ctx, coderConfig
|
|
103
|
+
const paramsHooks = createParamsHooks(ctx, coderConfig);
|
|
104
|
+
const completionHooks = createCompletionHooks(ctx, coderConfig);
|
|
103
105
|
const tmuxManager = coderConfig.tmux?.enabled
|
|
104
106
|
? new TmuxSessionManager(ctx, coderConfig.tmux, {
|
|
105
107
|
onLog: (message) =>
|
|
@@ -208,11 +210,15 @@ export async function createCoderPlugin(ctx: PluginInput): Promise<Hooks> {
|
|
|
208
210
|
...(tools ? { tool: tools } : {}),
|
|
209
211
|
config: configHandler,
|
|
210
212
|
'chat.message': async (input: unknown, output: unknown) => {
|
|
213
|
+
completionHooks.onMessage(input);
|
|
211
214
|
await keywordHooks.onMessage(input, output);
|
|
212
215
|
await sessionHooks.onMessage(input, output);
|
|
213
216
|
await cadenceHooks.onMessage(input, output);
|
|
214
217
|
},
|
|
215
|
-
'chat.params':
|
|
218
|
+
'chat.params': async (input: unknown, output: unknown) => {
|
|
219
|
+
completionHooks.onParams(input);
|
|
220
|
+
await paramsHooks.onParams(input, output);
|
|
221
|
+
},
|
|
216
222
|
'tool.execute.before': toolHooks.before,
|
|
217
223
|
'tool.execute.after': toolHooks.after,
|
|
218
224
|
'shell.env': async (_input: unknown, output: unknown) => {
|
|
@@ -397,6 +403,7 @@ function createAgentConfigs(
|
|
|
397
403
|
...(agent.reasoningEffort ? { reasoningEffort: agent.reasoningEffort } : {}),
|
|
398
404
|
...(agent.thinking ? { thinking: agent.thinking } : {}),
|
|
399
405
|
...(agent.hidden ? { hidden: agent.hidden } : {}),
|
|
406
|
+
...(agent.fallbackModels?.length ? { fallbackModels: agent.fallbackModels } : {}),
|
|
400
407
|
};
|
|
401
408
|
}
|
|
402
409
|
|
package/src/tools/background.ts
CHANGED
|
@@ -105,6 +105,12 @@ export function createBackgroundTools(manager: BackgroundManager): {
|
|
|
105
105
|
status: string;
|
|
106
106
|
result?: string;
|
|
107
107
|
error?: string;
|
|
108
|
+
progress?: {
|
|
109
|
+
toolCalls: number;
|
|
110
|
+
lastTool?: string;
|
|
111
|
+
lastToolSec: number;
|
|
112
|
+
activeTools: number;
|
|
113
|
+
};
|
|
108
114
|
}> {
|
|
109
115
|
const task = manager.getTask(args.task_id);
|
|
110
116
|
if (!task) {
|
|
@@ -114,12 +120,34 @@ export function createBackgroundTools(manager: BackgroundManager): {
|
|
|
114
120
|
error: 'Task not found.',
|
|
115
121
|
};
|
|
116
122
|
}
|
|
123
|
+
|
|
124
|
+
// Include compact progress snapshot only for active tasks.
|
|
125
|
+
// Three numbers + optional tool name — minimal context cost.
|
|
126
|
+
// lastToolSec: seconds since the last tool call event was received.
|
|
127
|
+
// 0 = active right now; >300 with activeTools=0 = genuinely stuck.
|
|
128
|
+
let progress:
|
|
129
|
+
| { toolCalls: number; lastTool?: string; lastToolSec: number; activeTools: number }
|
|
130
|
+
| undefined;
|
|
131
|
+
|
|
132
|
+
if ((task.status === 'running' || task.status === 'pending') && task.progress) {
|
|
133
|
+
const lastToolSec = Math.floor(
|
|
134
|
+
(Date.now() - task.progress.lastUpdate.getTime()) / 1000
|
|
135
|
+
);
|
|
136
|
+
progress = {
|
|
137
|
+
toolCalls: task.progress.toolCalls,
|
|
138
|
+
lastTool: task.progress.lastTool,
|
|
139
|
+
lastToolSec,
|
|
140
|
+
activeTools: task.progress.activeToolCallsInFlight,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
117
144
|
return {
|
|
118
145
|
taskId: task.id,
|
|
119
146
|
sessionId: task.sessionId,
|
|
120
147
|
status: task.status,
|
|
121
148
|
result: task.result,
|
|
122
149
|
error: task.error,
|
|
150
|
+
progress,
|
|
123
151
|
};
|
|
124
152
|
},
|
|
125
153
|
};
|
package/src/types.ts
CHANGED
|
@@ -89,6 +89,16 @@ export interface AgentConfig {
|
|
|
89
89
|
reasoningEffort?: ReasoningEffort;
|
|
90
90
|
/** Extended thinking configuration for Anthropic models */
|
|
91
91
|
thinking?: ThinkingConfig;
|
|
92
|
+
/**
|
|
93
|
+
* Ordered list of fallback model IDs to try when the primary model fails
|
|
94
|
+
* with a retryable error (429 rate limit, 500/502/503 server error).
|
|
95
|
+
* Models are tried in order until one succeeds.
|
|
96
|
+
*
|
|
97
|
+
* Example: ['anthropic/claude-sonnet-4-20250514', 'openai/gpt-4.1']
|
|
98
|
+
*/
|
|
99
|
+
fallbackModels?: string[];
|
|
100
|
+
/** Hidden from @ autocomplete */
|
|
101
|
+
hidden?: boolean;
|
|
92
102
|
}
|
|
93
103
|
|
|
94
104
|
export interface AgentContext {
|