agent-accelerator 0.5.4 → 0.5.6
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/README.md +34 -17
- package/package.json +1 -1
- package/src/agent/agent.ts +111 -35
- package/src/agent/config-blocks.ts +80 -0
- package/src/agent/loop.ts +6 -4
- package/src/agent/subagents-tool.ts +2 -2
- package/src/agent/subagents.md +2 -2
- package/src/agent/worker.ts +7 -5
- package/src/agent/workers.ts +2 -2
- package/src/index.ts +3 -3
- package/src/providers/google.ts +6 -39
- package/src/providers/openai-compat.ts +31 -104
- package/src/providers/openai.ts +30 -103
- package/src/providers/openrouter.ts +151 -400
- package/src/providers/shared.ts +136 -7
- package/src/providers.ts +21 -6
- package/src/scheduler/scheduled-actions.md +4 -2
- package/src/scheduler/scheduler.ts +87 -50
- package/src/scheduler/store.ts +23 -1
- package/src/scheduler/tool.ts +9 -8
- package/src/session/store.ts +3 -3
- package/src/streaming/event-stream.ts +7 -2
- package/src/tools/executor.ts +17 -2
- package/src/tools/tool.ts +0 -16
- package/src/types/agent.ts +32 -17
- package/src/types/message.ts +1 -1
- package/src/types/scheduler.ts +9 -2
- package/src/utils/errors.ts +4 -1
- package/src/utils/headers.ts +1 -1
- package/src/utils/media.ts +10 -1
package/src/scheduler/store.ts
CHANGED
|
@@ -17,6 +17,7 @@ import { telemetryBus } from "../telemetry.ts";
|
|
|
17
17
|
import { resolveHome } from "../utils/home.ts";
|
|
18
18
|
export { resolveHome };
|
|
19
19
|
import { ValidationError } from "../types/errors.ts";
|
|
20
|
+
import type { CostSource } from "../session/usage.ts";
|
|
20
21
|
import type { ScheduledActionRecord, ScheduledRunStatus } from "../types/scheduler.ts";
|
|
21
22
|
import { durationMs, runFileName } from "./time.ts";
|
|
22
23
|
|
|
@@ -33,6 +34,8 @@ export interface PendingDelivery {
|
|
|
33
34
|
status: ScheduledRunStatus;
|
|
34
35
|
readyAt: string;
|
|
35
36
|
deliverAt: string;
|
|
37
|
+
/** Set when the run replaced a missed occurrence: it is late whatever the clock says (a `run_now` on a `missed` action, or `onMissed: "run"`). */
|
|
38
|
+
late?: boolean;
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
/** Header written at the top of every run file. */
|
|
@@ -46,9 +49,26 @@ export interface RunHeader {
|
|
|
46
49
|
/** The run finished after its delivery time. */
|
|
47
50
|
late: boolean;
|
|
48
51
|
model?: string;
|
|
52
|
+
/** Model calls the run made (all attempts), and what they spent: the same numbers `usageReport()` keeps for workers. */
|
|
53
|
+
turns?: number;
|
|
54
|
+
/** Input + output tokens. */
|
|
49
55
|
tokens?: number;
|
|
50
|
-
/**
|
|
56
|
+
/** Everything sent; `freshInputTokens + cacheReadTokens + cacheWriteTokens`. */
|
|
57
|
+
inputTokens?: number;
|
|
58
|
+
freshInputTokens?: number;
|
|
59
|
+
cacheReadTokens?: number;
|
|
60
|
+
cacheWriteTokens?: number;
|
|
61
|
+
/** Everything generated, thinking included. */
|
|
62
|
+
outputTokens?: number;
|
|
63
|
+
thinkingTokens?: number;
|
|
64
|
+
/** `cacheReadTokens / inputTokens`, 0 to 1; absent when nothing was sent. */
|
|
65
|
+
cacheHitRate?: number;
|
|
66
|
+
/** `unknown` when no turn had a known price (never a made-up 0). */
|
|
51
67
|
costUsd?: number | "unknown";
|
|
68
|
+
/** Where the price came from: the `provider`'s reported cost, the `catalog`, `mixed`, or `unknown`. */
|
|
69
|
+
costSource?: CostSource;
|
|
70
|
+
/** Turns with no known price; when present, `costUsd` is a lower bound. */
|
|
71
|
+
unpricedTurns?: number;
|
|
52
72
|
error?: string;
|
|
53
73
|
}
|
|
54
74
|
|
|
@@ -163,6 +183,7 @@ const recordSchema = z
|
|
|
163
183
|
startCookingInAdvance: z.string(),
|
|
164
184
|
repeatEvery: z.string().optional(),
|
|
165
185
|
retries: z.number().int().min(0).optional(),
|
|
186
|
+
onMissed: z.enum(["skip", "run"]).optional(),
|
|
166
187
|
}),
|
|
167
188
|
state: z.enum(["waiting", "cooking", "missed", "done"]),
|
|
168
189
|
nextCookAt: iso.nullable(),
|
|
@@ -195,6 +216,7 @@ const deliverySchema = z.object({
|
|
|
195
216
|
status: z.enum(["ok", "failed"]),
|
|
196
217
|
readyAt: iso,
|
|
197
218
|
deliverAt: iso,
|
|
219
|
+
late: z.boolean().optional(),
|
|
198
220
|
});
|
|
199
221
|
|
|
200
222
|
/** `undefined` when a `deliveries.json` entry is usable, else a one-line reason. Never throws. */
|
package/src/scheduler/tool.ts
CHANGED
|
@@ -14,7 +14,7 @@ import type { ScheduledActionInput, ScheduledActionPatch } from "../types/schedu
|
|
|
14
14
|
import {
|
|
15
15
|
createScheduledAction,
|
|
16
16
|
getScheduler,
|
|
17
|
-
|
|
17
|
+
deleteScheduledAction,
|
|
18
18
|
listScheduledActions,
|
|
19
19
|
runScheduledAction,
|
|
20
20
|
skipScheduledAction,
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
import { readRun } from "./store.ts";
|
|
25
25
|
import { formatDatetime } from "./time.ts";
|
|
26
26
|
|
|
27
|
-
const COMMANDS = ["create", "list", "get", "update", "
|
|
27
|
+
const COMMANDS = ["create", "list", "get", "update", "delete", "run_now", "skip"] as const;
|
|
28
28
|
|
|
29
29
|
let manual: string | undefined;
|
|
30
30
|
/** Read on first use (not at import), so a program that never enables scheduling never touches the file. */
|
|
@@ -50,9 +50,10 @@ const scheduledActionSchema = z.object({
|
|
|
50
50
|
startCookingInAdvance: z.string().optional().describe('Duration "DD:HH:MM" before delivery when the run starts.'),
|
|
51
51
|
repeatEvery: z.string().optional().describe('Duration "DD:HH:MM" between deliveries. Omit to run once.'),
|
|
52
52
|
retries: z.number().optional().describe("Extra attempts if a run fails."),
|
|
53
|
+
onMissed: z.enum(["skip", "run"]).optional().describe('If the host program was not running at delivery time: "skip" = move on to the next time, "run" = run when it is back. Omit to decide later.'),
|
|
53
54
|
});
|
|
54
55
|
|
|
55
|
-
const describedId = "Full action id including its 6-character suffix (get, update,
|
|
56
|
+
const describedId = "Full action id including its 6-character suffix (get, update, delete, run_now, skip).";
|
|
56
57
|
|
|
57
58
|
/** Builds the `scheduled_actions` tool for `agent`; its description is the manual with the worker pool filled in. */
|
|
58
59
|
export function createScheduledActionsTool(agent: Agent): ToolDefinition {
|
|
@@ -85,10 +86,10 @@ export function createScheduledActionsTool(agent: Agent): ToolDefinition {
|
|
|
85
86
|
instructions: z.string().optional().describe("The worker's system prompt (create, update)."),
|
|
86
87
|
task: z.string().optional().describe("The concrete assignment for every run (create, update)."),
|
|
87
88
|
tools: z.array(z.string()).optional().describe(`Worker tools to grant, from: ${poolNames.join(", ") || "none"}.`),
|
|
88
|
-
timeoutMs: z.number().optional().describe("
|
|
89
|
+
timeoutMs: z.number().optional().describe("Stop a run that takes longer than this many ms (> 0). Omit it for no limit of your own; the host program may cap it."),
|
|
89
90
|
scheduled_action: scheduledActionSchema.optional(),
|
|
90
|
-
force: z.boolean().optional().describe("
|
|
91
|
-
purge: z.boolean().optional().describe("
|
|
91
|
+
force: z.boolean().optional().describe("delete: abort a run that is cooking. Ask the user first."),
|
|
92
|
+
purge: z.boolean().optional().describe("delete: also delete past run files."),
|
|
92
93
|
}),
|
|
93
94
|
execute: async (a) => {
|
|
94
95
|
const sa = a.scheduled_action ?? {};
|
|
@@ -137,8 +138,8 @@ export function createScheduledActionsTool(agent: Agent): ToolDefinition {
|
|
|
137
138
|
}
|
|
138
139
|
return updateScheduledAction(id, patch, { home });
|
|
139
140
|
}
|
|
140
|
-
case "
|
|
141
|
-
return
|
|
141
|
+
case "delete":
|
|
142
|
+
return deleteScheduledAction(needId(), { home, force: a.force, purge: a.purge });
|
|
142
143
|
case "run_now":
|
|
143
144
|
return runScheduledAction(needId(), { home });
|
|
144
145
|
case "skip":
|
package/src/session/store.ts
CHANGED
|
@@ -1391,7 +1391,7 @@ function resolveEffectivePricing(
|
|
|
1391
1391
|
/**
|
|
1392
1392
|
* Prices one usage snapshot with integer micro-USD accumulation (Q-36).
|
|
1393
1393
|
*
|
|
1394
|
-
* -
|
|
1394
|
+
* - A provider-reported `usage.cost.totalCost` (a number, 0 included: free or cached) wins (source `provider`).
|
|
1395
1395
|
* - Else catalog pricing via `resolveEffectivePricing` (source `catalog`).
|
|
1396
1396
|
* - Else returns `undefined` (source `unknown` is implicit) — unknown stays
|
|
1397
1397
|
* unknown, never a fabricated 0 object.
|
|
@@ -1408,7 +1408,7 @@ export function priceUsage(
|
|
|
1408
1408
|
opts?: { serviceTier?: ServiceTier | string; modelId?: string }
|
|
1409
1409
|
): PricedCost | undefined {
|
|
1410
1410
|
const reported = usage?.cost;
|
|
1411
|
-
if (reported && typeof reported.totalCost === "number" && reported.totalCost
|
|
1411
|
+
if (reported && typeof reported.totalCost === "number" && reported.totalCost >= 0) {
|
|
1412
1412
|
const micro = (d?: number): number => (typeof d === "number" && d > 0 ? Math.round(d * 1_000_000) : 0);
|
|
1413
1413
|
const inputMicroUSD = micro(reported.inputCost);
|
|
1414
1414
|
const outputMicroUSD = micro(reported.outputCost);
|
|
@@ -1492,7 +1492,7 @@ export function addCostToUsage(
|
|
|
1492
1492
|
spec?: ModelSpec,
|
|
1493
1493
|
opts?: { serviceTier?: ServiceTier | string }
|
|
1494
1494
|
): TokenUsage["cost"] | undefined {
|
|
1495
|
-
if (usage?.cost && typeof usage.cost.totalCost === "number" && usage.cost.totalCost
|
|
1495
|
+
if (usage?.cost && typeof usage.cost.totalCost === "number" && usage.cost.totalCost >= 0) {
|
|
1496
1496
|
return usage.cost;
|
|
1497
1497
|
}
|
|
1498
1498
|
const priced = priceUsage(usage, spec, opts);
|
|
@@ -14,6 +14,8 @@ export interface EventStreamOptions {
|
|
|
14
14
|
includePartial?: boolean;
|
|
15
15
|
/** Max buffered events when no iterator is attached. Default 1000. Oldest dropped. */
|
|
16
16
|
maxBufferedEvents?: number;
|
|
17
|
+
/** `false`: events go to listeners and waiting iterators only, never into the buffer (for a caller that only wants `result()`). Default true. */
|
|
18
|
+
buffer?: boolean;
|
|
17
19
|
/** Max approx bytes for a single delta event. Default 1MB. Oversized dropped. */
|
|
18
20
|
maxEventBytes?: number;
|
|
19
21
|
}
|
|
@@ -61,6 +63,7 @@ export class AssistantMessageEventStream implements AsyncIterable<StreamEvent> {
|
|
|
61
63
|
private resolveFinalResult!: (result: AgentResponse) => void;
|
|
62
64
|
private rejectFinalResult!: (err: Error) => void;
|
|
63
65
|
private readonly includePartial: boolean;
|
|
66
|
+
private readonly buffered: boolean;
|
|
64
67
|
private readonly maxBufferedEvents: number;
|
|
65
68
|
private readonly maxEventBytes: number;
|
|
66
69
|
/** First listener exception captured for inspection (Q-29/Q-41). */
|
|
@@ -80,6 +83,7 @@ export class AssistantMessageEventStream implements AsyncIterable<StreamEvent> {
|
|
|
80
83
|
*/
|
|
81
84
|
constructor(opts?: EventStreamOptions) {
|
|
82
85
|
this.includePartial = opts?.includePartial !== false;
|
|
86
|
+
this.buffered = opts?.buffer !== false;
|
|
83
87
|
this.maxBufferedEvents =
|
|
84
88
|
typeof opts?.maxBufferedEvents === "number" && Number.isFinite(opts.maxBufferedEvents) && opts.maxBufferedEvents > 0
|
|
85
89
|
? Math.floor(opts.maxBufferedEvents)
|
|
@@ -151,8 +155,9 @@ export class AssistantMessageEventStream implements AsyncIterable<StreamEvent> {
|
|
|
151
155
|
} else {
|
|
152
156
|
// No waiter right now (typical between `next()` polls of a burst):
|
|
153
157
|
// buffer for the iterator with a hard cap (Q-29). Overflow drops the
|
|
154
|
-
// oldest with an anomaly report — see `enqueueBounded`.
|
|
155
|
-
|
|
158
|
+
// oldest with an anomaly report — see `enqueueBounded`. A stream built
|
|
159
|
+
// with `buffer: false` has no iterator to feed and keeps nothing.
|
|
160
|
+
if (this.buffered) this.enqueueBounded(out);
|
|
156
161
|
}
|
|
157
162
|
}
|
|
158
163
|
|
package/src/tools/executor.ts
CHANGED
|
@@ -422,6 +422,21 @@ function waitForRetry(ms: number, signal?: AbortSignal): Promise<void> {
|
|
|
422
422
|
});
|
|
423
423
|
}
|
|
424
424
|
|
|
425
|
+
// Settles with `work`, or rejects "Tool execution aborted" the moment `signal` aborts, without waiting for a tool that never looks at its signal (it finishes in the background, its result is dropped); in: executeAttempt, out: the attempt's result or error.
|
|
426
|
+
function raceAbort<T>(work: Promise<T>, signal: AbortSignal | undefined): Promise<T> {
|
|
427
|
+
if (!signal) return work;
|
|
428
|
+
return new Promise<T>((resolve, reject) => {
|
|
429
|
+
const onAbort = () => reject(new Error("Tool execution aborted"));
|
|
430
|
+
if (signal.aborted) {
|
|
431
|
+
work.catch(() => {}); // the abandoned tool may still fail later: nobody listens
|
|
432
|
+
onAbort();
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
436
|
+
work.then(resolve, reject).finally(() => signal.removeEventListener("abort", onAbort));
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
|
|
425
440
|
async function executeAttempt(
|
|
426
441
|
toolDef: ToolDefinition,
|
|
427
442
|
parsedInput: unknown,
|
|
@@ -429,7 +444,7 @@ async function executeAttempt(
|
|
|
429
444
|
timeoutMs: number | undefined
|
|
430
445
|
): Promise<unknown> {
|
|
431
446
|
if (!timeoutMs || timeoutMs <= 0) {
|
|
432
|
-
return toolDef.execute(parsedInput as any, context);
|
|
447
|
+
return raceAbort(Promise.resolve(toolDef.execute(parsedInput as any, context)), context.signal);
|
|
433
448
|
}
|
|
434
449
|
|
|
435
450
|
const controller = new AbortController();
|
|
@@ -453,7 +468,7 @@ async function executeAttempt(
|
|
|
453
468
|
}, timeoutMs);
|
|
454
469
|
});
|
|
455
470
|
const result = await Promise.race([
|
|
456
|
-
Promise.resolve(toolDef.execute(parsedInput as any, executionContext)),
|
|
471
|
+
raceAbort(Promise.resolve(toolDef.execute(parsedInput as any, executionContext)), context.signal),
|
|
457
472
|
timeout,
|
|
458
473
|
]);
|
|
459
474
|
// A resolved promise can beat a timer callback even when the event loop
|
package/src/tools/tool.ts
CHANGED
|
@@ -61,22 +61,6 @@ export function resolveWhenBusy(
|
|
|
61
61
|
return v === "steer" || v === "queue" ? v : "auto";
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
/**
|
|
65
|
-
* Maps the Q-52 canonical worker-timeout knobs to the legacy `timeout` value
|
|
66
|
-
* (`0` = no limit, `-1` = model sets per-task `timeoutMs`, `>0` = fixed ms).
|
|
67
|
-
* An explicit `timeout`/`workerTimeoutMs` wins over `modelMaySetTimeout`.
|
|
68
|
-
*
|
|
69
|
-
* @example `normalizeWorkerTimeout({ modelMaySetTimeout: true }); // -1`
|
|
70
|
-
*/
|
|
71
|
-
export function normalizeWorkerTimeout(
|
|
72
|
-
config?: { timeout?: number; workerTimeoutMs?: number; modelMaySetTimeout?: boolean }
|
|
73
|
-
): number {
|
|
74
|
-
const explicit = config?.workerTimeoutMs ?? config?.timeout;
|
|
75
|
-
if (Number.isFinite(explicit as number)) return Math.floor(explicit as number);
|
|
76
|
-
if (config?.modelMaySetTimeout === true) return -1;
|
|
77
|
-
return 0;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
64
|
/**
|
|
81
65
|
* Normalizes the Q-52 `maxAttempts` alias to a `maxTries` value.
|
|
82
66
|
* `maxTries` wins when both are set.
|
package/src/types/agent.ts
CHANGED
|
@@ -121,7 +121,8 @@ export interface AgentConfig {
|
|
|
121
121
|
* - `{ mode: "steer" }`: only steer (inject into current turn) is allowed.
|
|
122
122
|
* - `{ mode: "queue" }`: only queue (next-turn follow-up) is allowed.
|
|
123
123
|
* - `{ mode: "auto" }` (default): caller picks per message via `enqueue` or `steer()`/`queue()`.
|
|
124
|
-
* `interrupt` (
|
|
124
|
+
* `interrupt` (stop the active run now, optionally start a new message) is always available, whatever the mode:
|
|
125
|
+
* `interrupt()`, `interrupt(message)`, `enqueue: "interrupt"`, `cancel()` and `AbortSignal`.
|
|
125
126
|
*/
|
|
126
127
|
midSession?: MidSessionConfig;
|
|
127
128
|
/**
|
|
@@ -227,6 +228,25 @@ export interface AgentConfig {
|
|
|
227
228
|
budget?: Budget;
|
|
228
229
|
/** Run + network limits (Q-22). Turn/budget caps unlimited by default; network timeouts finite. */
|
|
229
230
|
limits?: AgentRunLimits;
|
|
231
|
+
/**
|
|
232
|
+
* The only models this agent may use, as `provider/model` strings compared as written. Unset (default) = any model.
|
|
233
|
+
* Checked when the Agent is built (also for a config an agent edited through {@link Agent.fromConfig}); a model
|
|
234
|
+
* outside the list throws a `ConfigError`. Workers and `subagentModel` are not affected.
|
|
235
|
+
*/
|
|
236
|
+
allowedModels?: string[];
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* The part of an agent that an agent may edit (self-improvement): see {@link Agent.toConfig} and {@link Agent.fromConfig}.
|
|
241
|
+
* Plain JSON. Every other setting (limits, budget, cache, thinking, keys, ...) stays with the developer.
|
|
242
|
+
*/
|
|
243
|
+
export interface EditableAgentConfig {
|
|
244
|
+
/** `provider/model`; must be in `allowedModels` when the developer set it. */
|
|
245
|
+
model?: string;
|
|
246
|
+
/** System instructions. */
|
|
247
|
+
instructions?: string;
|
|
248
|
+
/** Names of tools, picked from the developer's tool pool (`base.tools` of `fromConfig`). */
|
|
249
|
+
tools?: string[];
|
|
230
250
|
}
|
|
231
251
|
|
|
232
252
|
/** A run that a crash cut off (see {@link Agent.interrupted}). */
|
|
@@ -246,6 +266,7 @@ export interface AgentRunLimits {
|
|
|
246
266
|
deadlineMs?: number;
|
|
247
267
|
maxTotalTokens?: number;
|
|
248
268
|
maxToolCallsPerRun?: number;
|
|
269
|
+
/** Network timeouts in ms. Defaults 300 000 / 120 000 / 300 000. `0` or `Infinity` turns one off. */
|
|
249
270
|
requestTimeoutMs?: number;
|
|
250
271
|
firstByteTimeoutMs?: number;
|
|
251
272
|
streamIdleTimeoutMs?: number;
|
|
@@ -288,7 +309,7 @@ export interface DynamicSubagentsConfig {
|
|
|
288
309
|
allowScheduledActions?: boolean;
|
|
289
310
|
/** Developer-only worker model override. Never choosable by the Main Agent LLM. Falls back to top-level `subagentModel`, then `SUB_AGENT_MODEL` env, then the parent model. */
|
|
290
311
|
model?: string | ModelSpec | ModelProviderInstance;
|
|
291
|
-
/** Max workers that may be open at once on this agent (the model must close one before spawning another).
|
|
312
|
+
/** Max workers that may be open at once on this agent (the model must close one before spawning another). Default: no limit; set a whole number >= 1 to cap it. */
|
|
292
313
|
maxSpawn?: number;
|
|
293
314
|
/** Fixed reasoning level for all dynamic workers. The Main Agent cannot override it. Falls back to the parent level when omitted. */
|
|
294
315
|
thinkingLevel?: ThinkingLevel;
|
|
@@ -300,27 +321,19 @@ export interface DynamicSubagentsConfig {
|
|
|
300
321
|
*/
|
|
301
322
|
workerBudget?: Pick<Budget, "maxCostUsd" | "maxTotalTokens">;
|
|
302
323
|
/**
|
|
303
|
-
* How many levels of workers may exist below this agent
|
|
304
|
-
* `3` = a worker may start workers that start workers. A worker with levels left gets its own `subagents` tool, and
|
|
305
|
-
* its children can only be granted the tools the worker itself was granted.
|
|
324
|
+
* How many levels of workers may exist below this agent. Default: no limit. `1` = workers cannot start workers of their
|
|
325
|
+
* own; `3` = a worker may start workers that start workers. A worker with levels left gets its own `subagents` tool, and
|
|
326
|
+
* its children can only be granted the tools the worker itself was granted. A whole number >= 1, or omit it for no limit.
|
|
306
327
|
*/
|
|
307
328
|
maxDepth?: number;
|
|
308
329
|
/** Tool pool available to dynamic workers. Workers receive zero tools unless the Main Agent grants a per-task `tools` subset by name. */
|
|
309
330
|
tools?: Record<string, ToolDefinition> | ToolDefinition[];
|
|
310
|
-
/** Per-run timeout in ms of a SCHEDULED ACTION's worker (the `subagents` tool and `agent.workers` have no timeouts). `0` (default) = no limit. `-1` = the action sets its own `timeoutMs`. `>0` = fixed. */
|
|
311
|
-
timeout?: number;
|
|
312
331
|
/**
|
|
313
|
-
*
|
|
314
|
-
*
|
|
315
|
-
* `
|
|
332
|
+
* Longest a SCHEDULED ACTION's run may take, in ms (the `subagents` tool and `agent.workers` have no timeouts). An
|
|
333
|
+
* action can set its own shorter `timeoutMs`; this is the ceiling for it, and the limit for actions that set none.
|
|
334
|
+
* Default: no limit (`0` and `Infinity` mean the same).
|
|
316
335
|
*/
|
|
317
336
|
workerTimeoutMs?: number;
|
|
318
|
-
/**
|
|
319
|
-
* Scheduled actions only: when true, each action sets its own `timeoutMs` (maps to
|
|
320
|
-
* `timeout: -1`). When both are set, an explicit `timeout`/`workerTimeoutMs`
|
|
321
|
-
* wins over `modelMaySetTimeout`.
|
|
322
|
-
*/
|
|
323
|
-
modelMaySetTimeout?: boolean;
|
|
324
337
|
}
|
|
325
338
|
|
|
326
339
|
/** Per-run overrides for {@link Agent.run}, {@link Agent.ask}, and {@link Agent.stream}. */
|
|
@@ -346,8 +359,10 @@ export interface AgentRunOptions {
|
|
|
346
359
|
* enforces `"steer"` or `"queue"`, that policy wins and this field is ignored.
|
|
347
360
|
* When idle, this field is ignored and the call runs immediately.
|
|
348
361
|
* Defaults to `"queue"` (finish current turn, run as next turn).
|
|
362
|
+
* `"interrupt"` is honored in every mode: it stops the active run (provider request, tools, workers) and starts this
|
|
363
|
+
* prompt as the next run, ahead of queued follow-ups.
|
|
349
364
|
*/
|
|
350
|
-
enqueue?: "steer" | "queue";
|
|
365
|
+
enqueue?: "steer" | "queue" | "interrupt";
|
|
351
366
|
/** Headers merged for this run only. */
|
|
352
367
|
headers?: Record<string, string>;
|
|
353
368
|
/** Called for each text delta as it streams (only when stream:true). */
|
package/src/types/message.ts
CHANGED
|
@@ -9,7 +9,7 @@ export interface TextPart {
|
|
|
9
9
|
thoughtSignature?: string;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
/** Detail level a provider spends on one image or video (more detail = more input tokens). Google
|
|
12
|
+
/** Detail level a provider spends on one image or video (more detail = more input tokens). Google (images and videos) and OpenRouter (images, as `image_url.detail`) honour it; other providers ignore it with a warning. */
|
|
13
13
|
export type MediaResolution = "low" | "medium" | "high" | "ultra_high";
|
|
14
14
|
|
|
15
15
|
/** Image content accepted as a URL, data, path, or binary value. */
|
package/src/types/scheduler.ts
CHANGED
|
@@ -15,6 +15,12 @@ export interface ScheduleSpec {
|
|
|
15
15
|
repeatEvery?: string;
|
|
16
16
|
/** Extra attempts if a run fails, only while time remains before delivery. Default 0. */
|
|
17
17
|
retries?: number;
|
|
18
|
+
/**
|
|
19
|
+
* What happens when the host program was not running at a delivery time. `"skip"`: move on to the next time (a one-shot
|
|
20
|
+
* is done). `"run"`: run it as soon as the program is back. Omitted: the action is marked `missed` and waits for
|
|
21
|
+
* `runScheduledAction` or `skipScheduledAction`.
|
|
22
|
+
*/
|
|
23
|
+
onMissed?: "skip" | "run";
|
|
18
24
|
}
|
|
19
25
|
|
|
20
26
|
/** What `createScheduledAction` receives: dynamic sub-agent fields plus the schedule. */
|
|
@@ -24,6 +30,7 @@ export interface ScheduledActionInput {
|
|
|
24
30
|
task: string;
|
|
25
31
|
/** Names from the developer's `dynamicSubagents.tools` pool. */
|
|
26
32
|
tools?: string[];
|
|
33
|
+
/** Longest one run may take, in ms. Never above `dynamicSubagents.workerTimeoutMs` when the developer set one. */
|
|
27
34
|
timeoutMs?: number;
|
|
28
35
|
scheduled_action: ScheduleSpec & {
|
|
29
36
|
/** Human label. */
|
|
@@ -74,8 +81,8 @@ export interface ScheduledDelivery {
|
|
|
74
81
|
late: boolean;
|
|
75
82
|
}
|
|
76
83
|
|
|
77
|
-
/** Result of `
|
|
78
|
-
export type
|
|
84
|
+
/** Result of `deleteScheduledAction`. */
|
|
85
|
+
export type DeleteResult =
|
|
79
86
|
| { ok: true }
|
|
80
87
|
| { ok: false; reason: "not_found" }
|
|
81
88
|
| { ok: false; reason: "running"; message: string };
|
package/src/utils/errors.ts
CHANGED
|
@@ -113,7 +113,8 @@ const PART_TO_MODALITY: Record<string, "image" | "audio" | "video" | "pdf"> = {
|
|
|
113
113
|
|
|
114
114
|
/**
|
|
115
115
|
* Fails fast — before any network call — when the catalog knows the model
|
|
116
|
-
* lacks a requested input modality (image/audio/video/document
|
|
116
|
+
* lacks a requested input modality (image/audio/video/document; files are
|
|
117
|
+
* not checked on OpenRouter, which parses them for any model). Unknown
|
|
117
118
|
* models (custom providers, dynamic routers) are skipped: the provider
|
|
118
119
|
* verdict stands and surfaces via toConciseProviderError instead.
|
|
119
120
|
*/
|
|
@@ -130,6 +131,8 @@ export function assertModalitiesSupported(
|
|
|
130
131
|
if (mapped) needed.add(mapped);
|
|
131
132
|
}
|
|
132
133
|
}
|
|
134
|
+
// OpenRouter reads a file with the model's native support or its own parser, so the catalog's "pdf" flag never gates a file there.
|
|
135
|
+
if (providerId === "openrouter") needed.delete("pdf");
|
|
133
136
|
if (needed.size === 0) return;
|
|
134
137
|
let supported: readonly string[] | undefined;
|
|
135
138
|
try {
|
package/src/utils/headers.ts
CHANGED
|
@@ -23,7 +23,7 @@ export function getPackageVersion(): string {
|
|
|
23
23
|
const v = (globalThis as any).process?.env?.npm_package_version;
|
|
24
24
|
if (typeof v === "string" && v) return v;
|
|
25
25
|
} catch {}
|
|
26
|
-
return "0.5.
|
|
26
|
+
return "0.5.6";
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
function getAgentAccelUserAgent(): string {
|
package/src/utils/media.ts
CHANGED
|
@@ -26,6 +26,11 @@ export function inferMimeType(input: string, fallback = "application/octet-strea
|
|
|
26
26
|
if (clean.endsWith(".mp3")) return "audio/mp3";
|
|
27
27
|
if (clean.endsWith(".wav")) return "audio/wav";
|
|
28
28
|
if (clean.endsWith(".ogg")) return "audio/ogg";
|
|
29
|
+
if (clean.endsWith(".flac")) return "audio/flac";
|
|
30
|
+
if (clean.endsWith(".m4a")) return "audio/m4a";
|
|
31
|
+
if (clean.endsWith(".aac")) return "audio/aac";
|
|
32
|
+
if (clean.endsWith(".aiff") || clean.endsWith(".aif")) return "audio/aiff";
|
|
33
|
+
if (clean.endsWith(".mpeg") || clean.endsWith(".mpg")) return "video/mpeg";
|
|
29
34
|
if (clean.endsWith(".mp4")) return "video/mp4";
|
|
30
35
|
if (clean.endsWith(".webm")) return "video/webm";
|
|
31
36
|
if (clean.endsWith(".mov")) return "video/quicktime";
|
|
@@ -53,8 +58,12 @@ export function sniffMimeType(bytes: Uint8Array): string | undefined {
|
|
|
53
58
|
if (ascii(bytes, 0, "RIFF") && ascii(bytes, 8, "WAVE")) return "audio/wav";
|
|
54
59
|
if (ascii(bytes, 0, "%PDF")) return "application/pdf";
|
|
55
60
|
if (ascii(bytes, 0, "OggS")) return "audio/ogg";
|
|
61
|
+
if (ascii(bytes, 0, "fLaC")) return "audio/flac";
|
|
62
|
+
if (ascii(bytes, 0, "FORM") && ascii(bytes, 8, "AIF")) return "audio/aiff";
|
|
63
|
+
if (bytes[0] === 0xff && ((bytes[1] ?? 0) & 0xf6) === 0xf0) return "audio/aac"; // ADTS: sync bits plus layer 00 (MP3 frames have a non-zero layer)
|
|
56
64
|
if (ascii(bytes, 0, "ID3") || (bytes[0] === 0xff && ((bytes[1] ?? 0) & 0xe0) === 0xe0)) return "audio/mp3";
|
|
57
|
-
if (ascii(bytes, 4, "ftyp")) return ascii(bytes, 8, "qt") ? "video/quicktime" : "video/mp4";
|
|
65
|
+
if (ascii(bytes, 4, "ftyp")) return ascii(bytes, 8, "M4A") || ascii(bytes, 8, "M4B") ? "audio/m4a" : ascii(bytes, 8, "qt") ? "video/quicktime" : "video/mp4";
|
|
66
|
+
if (bytes[0] === 0 && bytes[1] === 0 && bytes[2] === 1 && bytes[3] === 0xba) return "video/mpeg"; // MPEG program stream
|
|
58
67
|
if (bytes[0] === 0x1a && bytes[1] === 0x45 && bytes[2] === 0xdf && bytes[3] === 0xa3) return "video/webm";
|
|
59
68
|
return undefined;
|
|
60
69
|
}
|