agent-accelerator 0.5.7 → 0.5.9
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 +27 -8
- package/package.json +1 -1
- package/src/agent/agent.ts +84 -45
- package/src/agent/architecture.md +1 -0
- package/src/agent/context.ts +3 -3
- package/src/agent/delegation.ts +12 -12
- package/src/agent/loop.ts +50 -53
- package/src/agent/subagent.ts +4 -4
- package/src/agent/worker.ts +2 -1
- package/src/architecture.md +1 -1
- package/src/index.ts +7 -7
- package/src/models/architecture.md +1 -1
- package/src/models/catalog-cache.ts +7 -7
- package/src/models/catalog.ts +22 -34
- package/src/providers/google.ts +7 -7
- package/src/providers/openai-compat.ts +10 -16
- package/src/providers/openai.ts +8 -7
- package/src/providers/openrouter.ts +4 -4
- package/src/providers/registry.ts +6 -5
- package/src/providers/shared.ts +6 -10
- package/src/scheduler/architecture.md +6 -3
- package/src/scheduler/scheduler.ts +111 -57
- package/src/scheduler/store.ts +273 -59
- package/src/session/architecture.md +1 -1
- package/src/session/store.ts +22 -22
- package/src/streaming/event-stream.ts +11 -11
- package/src/telemetry-file.ts +74 -24
- package/src/telemetry.ts +2 -2
- package/src/tools/executor.ts +1 -1
- package/src/tools/tool.ts +8 -8
- package/src/types/agent.ts +22 -20
- package/src/types/response.ts +8 -8
- package/src/types/scheduler.ts +2 -2
- package/src/types/tool.ts +5 -5
- package/src/update-models.ts +2 -2
- package/src/utils/architecture.md +3 -3
- package/src/utils/cache.ts +4 -4
- package/src/utils/durable.ts +78 -3
- package/src/utils/env.ts +1 -1
- package/src/utils/errors.ts +45 -31
- package/src/utils/headers.ts +4 -4
- package/src/utils/home.ts +1 -1
- package/src/utils/retry.ts +2 -28
- package/src/utils/session.ts +5 -5
|
@@ -4,7 +4,7 @@ import { telemetryBus } from "../telemetry.ts";
|
|
|
4
4
|
/** Listener invoked for a matching stream event type or `*`. */
|
|
5
5
|
export type StreamEventListener = (event: StreamEvent) => void;
|
|
6
6
|
|
|
7
|
-
/** Options for AssistantMessageEventStream
|
|
7
|
+
/** Options for AssistantMessageEventStream. */
|
|
8
8
|
export interface EventStreamOptions {
|
|
9
9
|
/**
|
|
10
10
|
* When false, `partialText`/`partialThinking` cumulative fields are stripped
|
|
@@ -25,9 +25,9 @@ type Resolver = {
|
|
|
25
25
|
reject: (err: Error) => void;
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
/** Default max buffered events
|
|
28
|
+
/** Default max buffered events. */
|
|
29
29
|
export const MAX_BUFFERED_EVENTS = 1000;
|
|
30
|
-
/** Default max approx bytes per delta event
|
|
30
|
+
/** Default max approx bytes per delta event. */
|
|
31
31
|
export const MAX_EVENT_BYTES = 1_048_576;
|
|
32
32
|
|
|
33
33
|
// Approximate size of an event's text fields; in: push's oversize guard, out: a character count.
|
|
@@ -43,7 +43,7 @@ function approxEventBytes(event: StreamEvent): number {
|
|
|
43
43
|
// Reports a dropped or overflowing event on the bus and the legacy hook, never throwing; in: push/enqueueBounded, out: telemetryBus.
|
|
44
44
|
function reportStreamAnomaly(detail: { type: string; [k: string]: unknown }): void {
|
|
45
45
|
// why: bus + hook only, never console — streams are hot paths and logging
|
|
46
|
-
// per-drop would spam and break no-console policy
|
|
46
|
+
// per-drop would spam and break no-console policy.
|
|
47
47
|
telemetryBus.emitWarning(detail.type, `[Agent Accelerator] stream anomaly: ${detail.type}`, detail);
|
|
48
48
|
try {
|
|
49
49
|
(globalThis as unknown as { __agentAccelAnomaly?: (d: unknown) => void }).__agentAccelAnomaly?.(detail);
|
|
@@ -68,7 +68,7 @@ export class AssistantMessageEventStream implements AsyncIterable<StreamEvent> {
|
|
|
68
68
|
private readonly buffered: boolean;
|
|
69
69
|
private readonly maxBufferedEvents: number;
|
|
70
70
|
private readonly maxEventBytes: number;
|
|
71
|
-
/** First listener exception captured for inspection
|
|
71
|
+
/** First listener exception captured for inspection. */
|
|
72
72
|
private listenerError: Error | null = null;
|
|
73
73
|
/** Count of events dropped by bounds (buffer cap / oversize / unbuffered). */
|
|
74
74
|
private droppedEvents = 0;
|
|
@@ -107,7 +107,7 @@ export class AssistantMessageEventStream implements AsyncIterable<StreamEvent> {
|
|
|
107
107
|
return this.listenerError;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
/** Number of events dropped by
|
|
110
|
+
/** Number of events dropped by bounds. */
|
|
111
111
|
getDroppedCount(): number {
|
|
112
112
|
return this.droppedEvents;
|
|
113
113
|
}
|
|
@@ -116,7 +116,7 @@ export class AssistantMessageEventStream implements AsyncIterable<StreamEvent> {
|
|
|
116
116
|
push(event: StreamEvent): void {
|
|
117
117
|
if (this.finished) return;
|
|
118
118
|
|
|
119
|
-
//
|
|
119
|
+
// 1MB oversize guard — drop oversized deltas (no console).
|
|
120
120
|
if (approxEventBytes(event) > this.maxEventBytes) {
|
|
121
121
|
this.droppedEvents++;
|
|
122
122
|
reportStreamAnomaly({ type: "stream_event_oversize", eventType: event.type });
|
|
@@ -132,7 +132,7 @@ export class AssistantMessageEventStream implements AsyncIterable<StreamEvent> {
|
|
|
132
132
|
|
|
133
133
|
if (out.type === "error") {
|
|
134
134
|
this.error = (out.error instanceof Error ? out.error : new Error(String(out.error))) ?? new Error("Unknown error in stream");
|
|
135
|
-
// Single error semantic
|
|
135
|
+
// Single error semantic: deliver the error event to listeners,
|
|
136
136
|
// reject result(), mark finished, reject pending iterators, and queue
|
|
137
137
|
// the error event so a late iterator observes it before failing.
|
|
138
138
|
this.deliverToListeners(out);
|
|
@@ -156,7 +156,7 @@ export class AssistantMessageEventStream implements AsyncIterable<StreamEvent> {
|
|
|
156
156
|
resolver.resolve({ value: out, done: false });
|
|
157
157
|
} else {
|
|
158
158
|
// No waiter right now (typical between `next()` polls of a burst):
|
|
159
|
-
// buffer for the iterator with a hard cap
|
|
159
|
+
// buffer for the iterator with a hard cap. Overflow drops the
|
|
160
160
|
// oldest with an anomaly report — see `enqueueBounded`. A stream built
|
|
161
161
|
// with `buffer: false` has no iterator to feed and keeps nothing.
|
|
162
162
|
if (this.buffered) this.enqueueBounded(out);
|
|
@@ -194,7 +194,7 @@ export class AssistantMessageEventStream implements AsyncIterable<StreamEvent> {
|
|
|
194
194
|
private enqueueBounded(event: StreamEvent): void {
|
|
195
195
|
this.queue.push(event);
|
|
196
196
|
while (this.queue.length > this.maxBufferedEvents) {
|
|
197
|
-
// Drop oldest buffered event to bound memory
|
|
197
|
+
// Drop oldest buffered event to bound memory. Error events are
|
|
198
198
|
// never dropped: if the oldest is an error, drop the next-oldest
|
|
199
199
|
// non-error instead; if the queue is all errors, keep them.
|
|
200
200
|
if (this.queue[0]?.type === "error") {
|
|
@@ -213,7 +213,7 @@ export class AssistantMessageEventStream implements AsyncIterable<StreamEvent> {
|
|
|
213
213
|
end(finalResponse?: AgentResponse): void {
|
|
214
214
|
if (this.finished) return;
|
|
215
215
|
if (!finalResponse) {
|
|
216
|
-
//
|
|
216
|
+
// Never hang result() — ending without a response is a
|
|
217
217
|
// programming error, so fail loudly instead of leaving consumers
|
|
218
218
|
// waiting forever.
|
|
219
219
|
this.fail(new Error("end() requires response"));
|
package/src/telemetry-file.ts
CHANGED
|
@@ -1,34 +1,84 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Opt-in disk sink for the telemetry bus (`AgentConfig.telemetry.persist`).
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
2
|
+
* Opt-in disk sink for the telemetry bus (`AgentConfig.telemetry.persist`). Appends one JSON line per event.
|
|
3
|
+
* An event that carries the id of a persisted session (`data.sessionId`) goes to that session's own file,
|
|
4
|
+
* `<session folder>/telemetry.ndjson`, so a session's trace sits next to its journal and tool logs; every other event
|
|
5
|
+
* goes to `<home>/telemetry/<YYYY-MM-DD>.ndjson`. Nothing is ever written outside a home folder: a session folder
|
|
6
|
+
* that is not inside a home that enabled telemetry (a `persist.dir` pointing elsewhere) falls back to the daily file.
|
|
7
|
+
* Each event is a single synchronous append, so a process crash keeps every event already emitted: a
|
|
8
|
+
* `tool.call_started` with no ending event was in flight, and the last `tool.progress` shows how far it got. Power loss
|
|
9
|
+
* is not covered (no fsync, by design: this is observability, not state). `turn.thinking` (full reasoning text) is never
|
|
10
|
+
* written. Several processes may enable the same home: each event is one append, so lines never mix.
|
|
9
11
|
*/
|
|
10
12
|
import * as fs from "node:fs";
|
|
11
13
|
import * as path from "node:path";
|
|
12
14
|
import { telemetryBus } from "./telemetry.ts";
|
|
15
|
+
import type { TelemetryEvent } from "./telemetry.ts";
|
|
13
16
|
import { safeStringify } from "./utils/serialization.ts";
|
|
14
|
-
import { lockFolder } from "./utils/durable.ts";
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
/** Homes (resolved paths) that asked for telemetry. */
|
|
19
|
+
const homes = new Set<string>();
|
|
20
|
+
/** Where each persisted session lives, by session id. */
|
|
21
|
+
const sessionFolders = new Map<string, string>();
|
|
22
|
+
let unsubscribe: (() => void) | undefined;
|
|
17
23
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
// True when `folder` is `home` itself or below it; in: the routing decision, out: a boolean.
|
|
25
|
+
function inside(home: string, folder: string): boolean {
|
|
26
|
+
const rel = path.relative(home, folder);
|
|
27
|
+
return rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Appends one line to a file, creating its folder; a full disk must never fail a run, and reporting it would re-enter this listener; in: the listener, out: the file.
|
|
31
|
+
function append(file: string, line: string): void {
|
|
32
|
+
try {
|
|
33
|
+
fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
|
|
34
|
+
fs.appendFileSync(file, line, { mode: 0o600 });
|
|
35
|
+
} catch {
|
|
36
|
+
// why: observability must never fail a run.
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// The bus listener: skips reasoning text, writes a session's event to its own folder when that folder is inside an enabled home, else to the daily file of every enabled home; in: each bus event, out: NDJSON files.
|
|
41
|
+
function onEvent(event: TelemetryEvent): void {
|
|
42
|
+
if (event.code === "turn.thinking") return;
|
|
43
|
+
const line = safeStringify(event) + "\n";
|
|
44
|
+
const id = (event.data as { sessionId?: unknown } | undefined)?.sessionId;
|
|
45
|
+
const folder = typeof id === "string" ? sessionFolders.get(id) : undefined;
|
|
46
|
+
if (folder && [...homes].some((h) => inside(h, folder))) {
|
|
47
|
+
append(path.join(folder, "telemetry.ndjson"), line);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const day = new Date(event.timestamp).toISOString().slice(0, 10);
|
|
51
|
+
for (const home of homes) {
|
|
52
|
+
if (!fs.existsSync(home)) {
|
|
53
|
+
homes.delete(home); // a deleted home is not recreated by a stray event
|
|
54
|
+
continue;
|
|
32
55
|
}
|
|
33
|
-
|
|
56
|
+
append(path.join(home, "telemetry", `${day}.ndjson`), line);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Starts appending bus events for `home` (idempotent per folder); one listener serves every enabled home. */
|
|
61
|
+
export function persistTelemetry(home: string): void {
|
|
62
|
+
const resolved = path.resolve(home);
|
|
63
|
+
unsubscribe = telemetryBus.onEvent(onEvent); // listeners are a Set, so this is idempotent, and it restores the sink after `telemetryBus.clear()`
|
|
64
|
+
if (homes.has(resolved)) return;
|
|
65
|
+
homes.add(resolved);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Remembers where a persisted session lives, so its events are written next to it; in: the Agent constructor and `importSession`, out: the routing map. */
|
|
69
|
+
export function registerSessionFolder(sessionId: string, folder: string): void {
|
|
70
|
+
sessionFolders.set(sessionId, path.resolve(folder));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Forgets a session's folder (its events fall back to the daily file); in: `disposeSession` and `importSession`, out: the routing map. */
|
|
74
|
+
export function unregisterSessionFolder(sessionId: string): void {
|
|
75
|
+
sessionFolders.delete(sessionId);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Forgets every enabled home and session and removes the listener. Test hook (not part of the public entry). */
|
|
79
|
+
export function resetTelemetryFile(): void {
|
|
80
|
+
homes.clear();
|
|
81
|
+
sessionFolders.clear();
|
|
82
|
+
unsubscribe?.();
|
|
83
|
+
unsubscribe = undefined;
|
|
34
84
|
}
|
package/src/telemetry.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* In-process telemetry bus
|
|
2
|
+
* In-process telemetry bus. Library code routes warnings, anomalies and
|
|
3
3
|
* per-turn traces here instead of `console.*`. The default has zero listeners,
|
|
4
4
|
* so emission is a no-op; CLIs, tests and observability layers attach with
|
|
5
5
|
* `telemetryBus.onEvent`. Intentionally dependency-free: every module in the
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* it without creating an import cycle.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
/** Telemetry event emitted via the in-process bus
|
|
10
|
+
/** Telemetry event emitted via the in-process bus. */
|
|
11
11
|
export interface TelemetryEvent {
|
|
12
12
|
code: string;
|
|
13
13
|
message: string;
|
package/src/tools/executor.ts
CHANGED
|
@@ -539,7 +539,7 @@ export async function executeToolCalls(
|
|
|
539
539
|
let attempts = 0;
|
|
540
540
|
let timedOut = false;
|
|
541
541
|
|
|
542
|
-
// Truncated streamed arguments
|
|
542
|
+
// Truncated streamed arguments: the `__truncated_raw` marker means the
|
|
543
543
|
// provider's partial JSON never parsed. Never execute or overwrite wire
|
|
544
544
|
// finishReason here — return a synthetic error so the model retries with
|
|
545
545
|
// complete JSON.
|
package/src/tools/tool.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { zodToJsonSchema } from "./schema.ts";
|
|
|
10
10
|
import { ConfigError } from "../types/errors.ts";
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* Valid tool-name pattern
|
|
13
|
+
* Valid tool-name pattern: 1–64 chars of letters, digits, `_`, `-`.
|
|
14
14
|
* Names are validated at registration in {@link tool} (record-key fallback
|
|
15
15
|
* included); invalid names throw `ConfigError` with a fix.
|
|
16
16
|
*/
|
|
@@ -31,7 +31,7 @@ export function assertValidToolName(name: string): void {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
|
-
* Normalizes the
|
|
34
|
+
* Normalizes the canonical `thinking` option to a bare level.
|
|
35
35
|
* Accepts a level string or `{ level, budgetTokens }`; `budgetTokens` is
|
|
36
36
|
* carried separately by providers, so only the level is returned here.
|
|
37
37
|
* Resolution honors `thinking ?? thinkingLevel`.
|
|
@@ -50,7 +50,7 @@ export function normalizeThinkingV2(
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
|
-
* Resolves the
|
|
53
|
+
* Resolves the canonical busy policy. `whenBusy` wins over `mode`.
|
|
54
54
|
*
|
|
55
55
|
* @example `resolveWhenBusy({ whenBusy: "queue", mode: "steer" }); // "queue"`
|
|
56
56
|
*/
|
|
@@ -62,7 +62,7 @@ export function resolveWhenBusy(
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
|
-
* Normalizes the
|
|
65
|
+
* Normalizes the `maxAttempts` alias to a `maxTries` value.
|
|
66
66
|
* `maxTries` wins when both are set.
|
|
67
67
|
*
|
|
68
68
|
* @example `normalizeMaxAttempts({ maxAttempts: 3 }); // 3`
|
|
@@ -90,7 +90,7 @@ export interface CreateToolOptions<TInput = any, TOutput = any> {
|
|
|
90
90
|
/** Maximum total attempts for transient failures. `0`/omitted means no configured limit. */
|
|
91
91
|
maxTries?: number | string;
|
|
92
92
|
/**
|
|
93
|
-
* Canonical alias for `maxTries
|
|
93
|
+
* Canonical alias for `maxTries`. When both are set, `maxTries` wins.
|
|
94
94
|
* Normalized by `normalizeMaxAttempts`.
|
|
95
95
|
*/
|
|
96
96
|
maxAttempts?: number | string;
|
|
@@ -116,12 +116,12 @@ export interface CreateToolOptions<TInput = any, TOutput = any> {
|
|
|
116
116
|
/** Optional hook to redact/replace the error message sent back to the model. */
|
|
117
117
|
redactError?: (err: unknown) => string;
|
|
118
118
|
/**
|
|
119
|
-
* Canonical alias for `redactError
|
|
119
|
+
* Canonical alias for `redactError`. When both are set,
|
|
120
120
|
* `redactError` wins.
|
|
121
121
|
*/
|
|
122
122
|
redact?: (err: unknown) => string;
|
|
123
123
|
/**
|
|
124
|
-
* Explicit retry policy
|
|
124
|
+
* Explicit retry policy. Preferred over bare `maxTries` for new
|
|
125
125
|
* code; the executor reads via `(toolDef as any).retry`.
|
|
126
126
|
*/
|
|
127
127
|
retry?: { maxRetries?: number; baseDelayMs?: number; maxDelayMs?: number };
|
|
@@ -165,7 +165,7 @@ export interface CreateToolOptions<TInput = any, TOutput = any> {
|
|
|
165
165
|
export function tool<TInput = any, TOutput = any>(
|
|
166
166
|
options: CreateToolOptions<TInput, TOutput>
|
|
167
167
|
): ToolDefinition<TInput, TOutput> {
|
|
168
|
-
//
|
|
168
|
+
// Names are validated at registration (record-key fallback included).
|
|
169
169
|
if (options.name !== undefined) assertValidToolName(options.name);
|
|
170
170
|
// ToolDefinition (src/types/tool.ts) carries the v2 policies as typed
|
|
171
171
|
// optionals; the executor additionally reads them via `(toolDef as any).*`.
|
package/src/types/agent.ts
CHANGED
|
@@ -10,7 +10,7 @@ import type { Agent } from "../agent/agent.ts";
|
|
|
10
10
|
import type { z } from "zod";
|
|
11
11
|
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
13
|
-
//
|
|
13
|
+
// Canonical option types (all additive; nothing renamed).
|
|
14
14
|
//
|
|
15
15
|
// Canonical homes (one place per setting):
|
|
16
16
|
// - Worker model: `dynamicSubagents.model` only. Top-level `subagentModel`
|
|
@@ -27,10 +27,10 @@ import type { z } from "zod";
|
|
|
27
27
|
/** Canonical model reference: `provider/model` string, catalog spec, or provider helper result. */
|
|
28
28
|
export type ModelRef = string | ModelSpec | ModelProviderInstance;
|
|
29
29
|
|
|
30
|
-
/** Canonical reasoning option
|
|
30
|
+
/** Canonical reasoning option: bare level, or level + explicit token budget. */
|
|
31
31
|
export type ThinkingOption = ThinkingLevel | { level?: ThinkingLevel; budgetTokens?: number };
|
|
32
32
|
|
|
33
|
-
/** Canonical retry policy
|
|
33
|
+
/** Canonical retry policy. Read by the loop via `(config as any).retry`. */
|
|
34
34
|
export interface RetryPolicyConfig {
|
|
35
35
|
maxRetries?: number;
|
|
36
36
|
baseDelayMs?: number;
|
|
@@ -38,7 +38,7 @@ export interface RetryPolicyConfig {
|
|
|
38
38
|
budgetMs?: number;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
/** Minimal logger surface for Agent/loop telemetry
|
|
41
|
+
/** Minimal logger surface for Agent/loop telemetry. */
|
|
42
42
|
export interface AgentLogger {
|
|
43
43
|
debug?: (...args: unknown[]) => void;
|
|
44
44
|
info?: (...args: unknown[]) => void;
|
|
@@ -46,17 +46,17 @@ export interface AgentLogger {
|
|
|
46
46
|
error?: (...args: unknown[]) => void;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
/** Canonical tool-selection control
|
|
49
|
+
/** Canonical tool-selection control. String form is the portable subset. */
|
|
50
50
|
export type ToolChoiceOption =
|
|
51
51
|
| "auto"
|
|
52
52
|
| "none"
|
|
53
53
|
| "required"
|
|
54
54
|
| { mode?: "auto" | "none" | "required"; tool?: string };
|
|
55
55
|
|
|
56
|
-
/** Canonical stop control
|
|
56
|
+
/** Canonical stop control: sequence(s) halting generation. */
|
|
57
57
|
export type StopOption = string | string[];
|
|
58
58
|
|
|
59
|
-
/** Canonical structured-output input
|
|
59
|
+
/** Canonical structured-output input. Zod, JSON Schema, or explicit form. */
|
|
60
60
|
export type StructuredOutputOption =
|
|
61
61
|
| z.ZodType
|
|
62
62
|
| Record<string, unknown>
|
|
@@ -90,7 +90,7 @@ export interface AgentConfig {
|
|
|
90
90
|
/** Requested reasoning level, validated against the model catalog. */
|
|
91
91
|
thinkingLevel?: ThinkingLevel;
|
|
92
92
|
/**
|
|
93
|
-
* Canonical reasoning option (
|
|
93
|
+
* Canonical reasoning option (preferred over `thinkingLevel`).
|
|
94
94
|
* Accepts a bare level or `{ level, budgetTokens }`. When both are set,
|
|
95
95
|
* `thinking` wins; resolution honors `thinking ?? thinkingLevel`.
|
|
96
96
|
* See `normalizeThinkingV2` (re-exported from the root entry).
|
|
@@ -151,11 +151,11 @@ export interface AgentConfig {
|
|
|
151
151
|
resume?: "automatic" | "explicit";
|
|
152
152
|
/**
|
|
153
153
|
* Folder for everything Agent Accelerator writes to disk (`sessions/`,
|
|
154
|
-
* `
|
|
154
|
+
* `scheduled/`, `telemetry/`). Defaults to `setHome()`, then the `AGENT_ACCEL_HOME` env var, then `.agent-accel/` in the working directory.
|
|
155
155
|
* An explicit `persist.dir` / `persist.file` still wins for sessions.
|
|
156
156
|
*/
|
|
157
157
|
home?: string;
|
|
158
|
-
//
|
|
158
|
+
// Additional options (all optional, additive; loop reads via `(config as any).*`).
|
|
159
159
|
/**
|
|
160
160
|
* Canonical tool-selection control (`"auto"` default). `"none"` applies to
|
|
161
161
|
* every turn of a run; `"required"` and a pinned tool (`{ tool: "name" }`)
|
|
@@ -193,8 +193,10 @@ export interface AgentConfig {
|
|
|
193
193
|
/** @deprecated Not implemented yet (accepted for forward compatibility; passing it emits a `config.unsupported_option` warning). */
|
|
194
194
|
contextManagement?: unknown;
|
|
195
195
|
/**
|
|
196
|
-
* Telemetry options. `persist: true` appends every `telemetryBus` event (except full reasoning
|
|
197
|
-
*
|
|
196
|
+
* Telemetry options. `persist: true` appends every `telemetryBus` event (except full reasoning text). An event
|
|
197
|
+
* that belongs to a persisted session (`data.sessionId`: tool events, resume and retry events) goes to
|
|
198
|
+
* `<session folder>/telemetry.ndjson`, next to the session's journal; every other event goes to
|
|
199
|
+
* `<home>/telemetry/<date>.ndjson`. Nothing is written outside the home. Off by default: the SDK writes nothing unless asked.
|
|
198
200
|
*/
|
|
199
201
|
telemetry?: { persist?: boolean };
|
|
200
202
|
/**
|
|
@@ -226,7 +228,7 @@ export interface AgentConfig {
|
|
|
226
228
|
* models with unknown pricing contribute $0, never a guess.
|
|
227
229
|
*/
|
|
228
230
|
budget?: Budget;
|
|
229
|
-
/** Run + network limits
|
|
231
|
+
/** Run + network limits. Turn/budget caps unlimited by default; network timeouts finite. */
|
|
230
232
|
limits?: AgentRunLimits;
|
|
231
233
|
/**
|
|
232
234
|
* The only models this agent may use, as `provider/model` strings compared as written. Unset (default) = any model.
|
|
@@ -260,7 +262,7 @@ export interface InterruptedRun {
|
|
|
260
262
|
pendingToolCalls: string[];
|
|
261
263
|
}
|
|
262
264
|
|
|
263
|
-
/** Per-request + run limits
|
|
265
|
+
/** Per-request + run limits. */
|
|
264
266
|
export interface AgentRunLimits {
|
|
265
267
|
maxTurns?: number;
|
|
266
268
|
deadlineMs?: number;
|
|
@@ -275,7 +277,7 @@ export interface AgentRunLimits {
|
|
|
275
277
|
/** Developer policy for mid-session new-query insertion while a run is active. */
|
|
276
278
|
export type MidSessionMode = "steer" | "queue" | "auto";
|
|
277
279
|
|
|
278
|
-
/**
|
|
280
|
+
/** Canonical busy-policy alias: prefer `whenBusy`, `mode` kept for compat. */
|
|
279
281
|
export type WhenBusyMode = MidSessionMode;
|
|
280
282
|
|
|
281
283
|
/** Developer-configured policy for LLM-spawned dynamic sub-agents. */
|
|
@@ -288,7 +290,7 @@ export interface MidSessionConfig {
|
|
|
288
290
|
*/
|
|
289
291
|
mode?: MidSessionMode;
|
|
290
292
|
/**
|
|
291
|
-
* Canonical alias for `mode` (
|
|
293
|
+
* Canonical alias for `mode` (preferred). When both are set,
|
|
292
294
|
* `whenBusy` wins. Accepted anywhere `mode` is read; resolution honors
|
|
293
295
|
* `whenBusy ?? mode ?? "auto"`.
|
|
294
296
|
*/
|
|
@@ -341,7 +343,7 @@ export interface AgentRunOptions {
|
|
|
341
343
|
/** Per-run reasoning-level override, validated against the selected model. */
|
|
342
344
|
thinkingLevel?: ThinkingLevel;
|
|
343
345
|
/**
|
|
344
|
-
* Canonical per-run reasoning option (
|
|
346
|
+
* Canonical per-run reasoning option (preferred over `thinkingLevel`).
|
|
345
347
|
* Resolution honors `thinking ?? thinkingLevel`.
|
|
346
348
|
*/
|
|
347
349
|
thinking?: ThinkingOption;
|
|
@@ -375,7 +377,7 @@ export interface AgentRunOptions {
|
|
|
375
377
|
wrapThinking?: boolean;
|
|
376
378
|
/** Called after every model/tool turn with a turn summary (also drives sub-agent step logs + durable persistence). */
|
|
377
379
|
onTurn?: (turn: AgentTurnEvent) => void;
|
|
378
|
-
//
|
|
380
|
+
// Per-run knobs (all optional, additive; `output` intentionally
|
|
379
381
|
// omitted here — it is agent-level only, see AgentConfig.output).
|
|
380
382
|
/** Per-run tool-selection override. */
|
|
381
383
|
toolChoice?: ToolChoiceOption;
|
|
@@ -409,7 +411,7 @@ export interface AgentTurnEvent {
|
|
|
409
411
|
toolResults?: Array<{ id: string; name: string; isError?: boolean }>;
|
|
410
412
|
}
|
|
411
413
|
|
|
412
|
-
/** Optional run budgets enforced by delegation helpers
|
|
414
|
+
/** Optional run budgets enforced by delegation helpers. All fields default to unlimited. */
|
|
413
415
|
export interface Budget {
|
|
414
416
|
/** Maximum total cost in USD across this agent + spawned workers. */
|
|
415
417
|
maxCostUsd?: number;
|
|
@@ -433,7 +435,7 @@ export interface BudgetState {
|
|
|
433
435
|
startedAtMs: number;
|
|
434
436
|
}
|
|
435
437
|
|
|
436
|
-
/** Run/turn lineage attached to sub-agent metadata via `(metadata as any)
|
|
438
|
+
/** Run/turn lineage attached to sub-agent metadata via `(metadata as any)`. */
|
|
437
439
|
export interface SubAgentRunIds {
|
|
438
440
|
/** Stable id for this worker batch/run (`newRunId`). */
|
|
439
441
|
runId?: string;
|
package/src/types/response.ts
CHANGED
|
@@ -67,7 +67,7 @@ export type FinishReason =
|
|
|
67
67
|
/** Maps a vendor finish reason to canonical FinishReason + raw passthrough.
|
|
68
68
|
* Known aliases collapse to the canonical set; empty/undefined stays
|
|
69
69
|
* undefined; any other non-empty string maps to `"error"` with the original
|
|
70
|
-
* preserved in `rawFinishReason
|
|
70
|
+
* preserved in `rawFinishReason`. */
|
|
71
71
|
export function normalizeFinishReason(raw?: string): {
|
|
72
72
|
finishReason?: FinishReason;
|
|
73
73
|
rawFinishReason?: string;
|
|
@@ -118,7 +118,7 @@ export interface AgentResponseJSON {
|
|
|
118
118
|
model: string;
|
|
119
119
|
provider: ProviderId | string;
|
|
120
120
|
finishReason?: FinishReason;
|
|
121
|
-
/** Original vendor finish string when it differs from canonical `finishReason
|
|
121
|
+
/** Original vendor finish string when it differs from canonical `finishReason`. */
|
|
122
122
|
rawFinishReason?: string;
|
|
123
123
|
durationMs: number;
|
|
124
124
|
raw: ProviderRawData;
|
|
@@ -140,7 +140,7 @@ export class AgentResponse {
|
|
|
140
140
|
readonly model: string;
|
|
141
141
|
readonly provider: ProviderId | string;
|
|
142
142
|
readonly finishReason?: FinishReason;
|
|
143
|
-
/** Original vendor finish string when it differs from canonical `finishReason
|
|
143
|
+
/** Original vendor finish string when it differs from canonical `finishReason`. */
|
|
144
144
|
readonly rawFinishReason?: string;
|
|
145
145
|
readonly durationMs: number;
|
|
146
146
|
readonly raw: ProviderRawData;
|
|
@@ -247,15 +247,15 @@ export type StreamEventType =
|
|
|
247
247
|
/** Payload for one streaming text, thinking, tool, usage, or lifecycle event. */
|
|
248
248
|
export interface StreamEvent {
|
|
249
249
|
type: StreamEventType;
|
|
250
|
-
/** Schema version for typed consumers
|
|
250
|
+
/** Schema version for typed consumers. Currently always 1 when present. */
|
|
251
251
|
schemaVersion?: 1;
|
|
252
252
|
delta?: string;
|
|
253
253
|
thinkingDelta?: string;
|
|
254
254
|
toolCall?: ToolCallRecord;
|
|
255
255
|
toolResult?: ToolResultRecord;
|
|
256
|
-
/** Batch tool calls for `tool_start` events
|
|
256
|
+
/** Batch tool calls for `tool_start` events. */
|
|
257
257
|
toolCalls?: ToolCallRecord[];
|
|
258
|
-
/** Batch tool results for `tool_end` events
|
|
258
|
+
/** Batch tool results for `tool_end` events. */
|
|
259
259
|
toolResults?: ToolResultRecord[];
|
|
260
260
|
subagent?: SubAgentExecutionMetadata;
|
|
261
261
|
/** Tracking id of the worker emitting a `subagent_delta` event. */
|
|
@@ -271,7 +271,7 @@ export interface StreamEvent {
|
|
|
271
271
|
/** Canonical finish reason when known; vendor strings pass through as-is
|
|
272
272
|
* for provider compat (normalize with `normalizeFinishReason`). */
|
|
273
273
|
finishReason?: string;
|
|
274
|
-
/** Original vendor finish string when it differs from canonical
|
|
274
|
+
/** Original vendor finish string when it differs from canonical. */
|
|
275
275
|
rawFinishReason?: string;
|
|
276
276
|
error?: Error | unknown;
|
|
277
277
|
partialText?: string;
|
|
@@ -279,7 +279,7 @@ export interface StreamEvent {
|
|
|
279
279
|
raw?: ProviderRawData;
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
-
/** Typed (discriminated) stream event schema, version 1
|
|
282
|
+
/** Typed (discriminated) stream event schema, version 1.
|
|
283
283
|
* `StreamEvent` stays the permissive compat shape; use this union when you
|
|
284
284
|
* want exhaustive switching (e.g. `tool_start`/`tool_end` lifecycle). */
|
|
285
285
|
export type StreamEventV2 =
|
package/src/types/scheduler.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Lifecycle of a scheduled action as stored in `
|
|
1
|
+
/** Lifecycle of a scheduled action as stored in `task.json`. */
|
|
2
2
|
export type ScheduledState = "waiting" | "cooking" | "missed" | "done";
|
|
3
3
|
|
|
4
4
|
/** Outcome of one run. */
|
|
@@ -45,7 +45,7 @@ export type ScheduledActionPatch = Partial<Omit<ScheduledActionInput, "scheduled
|
|
|
45
45
|
scheduled_action?: Partial<Omit<ScheduledActionInput["scheduled_action"], "id">>;
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
-
/**
|
|
48
|
+
/** The record inside an action's `task.json`. All times are local clock strings `YYYY-MM-DDTHH:mm:ss` (no offset). */
|
|
49
49
|
export interface ScheduledActionRecord {
|
|
50
50
|
id: string;
|
|
51
51
|
name: string;
|
package/src/types/tool.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { z } from "zod";
|
|
2
2
|
|
|
3
|
-
/** Minimal logger surface accepted by tool contexts (
|
|
3
|
+
/** Minimal logger surface accepted by tool contexts (additive). */
|
|
4
4
|
export interface ToolLogger {
|
|
5
5
|
debug?: (...args: unknown[]) => void;
|
|
6
6
|
info?: (...args: unknown[]) => void;
|
|
@@ -8,7 +8,7 @@ export interface ToolLogger {
|
|
|
8
8
|
error?: (...args: unknown[]) => void;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
/** Live-event emitter handed to tools that stream progress (
|
|
11
|
+
/** Live-event emitter handed to tools that stream progress (additive). */
|
|
12
12
|
export type ToolEmitFn = (event: { type: string; [k: string]: unknown }) => void;
|
|
13
13
|
|
|
14
14
|
export interface ToolExecutionContext {
|
|
@@ -22,7 +22,7 @@ export interface ToolExecutionContext {
|
|
|
22
22
|
sessionId?: string;
|
|
23
23
|
/** Forwards live sub-agent deltas (used by the `subagents` tool for realtime tracking). */
|
|
24
24
|
onSubagentEvent?: (event: { trackingId: string; delta?: string; thinkingDelta?: string; partialText?: string; partialThinking?: string }) => void;
|
|
25
|
-
//
|
|
25
|
+
// Tool API v2 context additions (all optional, additive).
|
|
26
26
|
/** Stable id for this run (`newRunId`). Mirrors SubAgentRunIds.runId. */
|
|
27
27
|
runId?: string;
|
|
28
28
|
/** Live-event emitter for tools that stream progress. */
|
|
@@ -69,7 +69,7 @@ export interface ToolDefinition<TInput = any, TOutput = any> {
|
|
|
69
69
|
maxConcurrency?: number | string;
|
|
70
70
|
/** Function executed after validation; its result is made JSON-safe for model context. */
|
|
71
71
|
execute: ToolExecuteFn<TInput, TOutput>;
|
|
72
|
-
//
|
|
72
|
+
// Tool API v2 additions (all optional, additive; loop reads via `(toolDef as any).*`).
|
|
73
73
|
/**
|
|
74
74
|
* Canonical alias for `maxTries`. When both are set, `maxTries` wins.
|
|
75
75
|
* Normalized by `normalizeMaxAttempts` (see tools/tool.ts).
|
|
@@ -101,7 +101,7 @@ export interface ToolDefinition<TInput = any, TOutput = any> {
|
|
|
101
101
|
redactError?: (err: unknown) => string;
|
|
102
102
|
/**
|
|
103
103
|
* Canonical alias for `redactError`. When both are set, `redactError` wins.
|
|
104
|
-
* Kept short for
|
|
104
|
+
* Kept short for Tool API v2 parity.
|
|
105
105
|
*/
|
|
106
106
|
redact?: (err: unknown) => string;
|
|
107
107
|
/** Free-form tags for grouping/filtering tools (e.g. `["web", "readonly"]`). */
|
package/src/update-models.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { refreshModelCatalog } from "./index.ts";
|
|
|
12
12
|
import { ConfigError } from "./types/errors.ts";
|
|
13
13
|
|
|
14
14
|
const args = process.argv.slice(2);
|
|
15
|
-
//
|
|
15
|
+
// Force is true only with explicit --force (previously also true when no --ttl).
|
|
16
16
|
const force = args.includes("--force");
|
|
17
17
|
|
|
18
18
|
let customTtlMs: number | undefined;
|
|
@@ -26,7 +26,7 @@ for (const arg of args) {
|
|
|
26
26
|
} else {
|
|
27
27
|
customTtlMs = parseFloat(val);
|
|
28
28
|
}
|
|
29
|
-
//
|
|
29
|
+
// Reject non-numeric TTLs (e.g. --ttl=abc) instead of silently caching NaN.
|
|
30
30
|
if (!Number.isFinite(customTtlMs)) {
|
|
31
31
|
throw new ConfigError(`Invalid --ttl value "${val}": expected a number with optional h/m suffix (e.g. --ttl=24h).`);
|
|
32
32
|
}
|
|
@@ -4,7 +4,7 @@ Small shared helpers. Each file has one job.
|
|
|
4
4
|
|
|
5
5
|
| File | What it does |
|
|
6
6
|
| :-- | :-- |
|
|
7
|
-
| `durable.ts` | The ONE disk writer (`writeFileDurable`: temp, fsync, `.bak`, rename, folder fsync), `readWithBackup`,
|
|
7
|
+
| `durable.ts` | The ONE disk writer (`writeFileDurable`: temp, fsync, `.bak`, rename, folder fsync), `readWithBackup`, `lockFolder` (one process per folder, used for session folders; stale-lock takeover, temp sweep) and `withFileMutex` (short per-file lock for state several processes change, e.g. one scheduled action). |
|
|
8
8
|
| `home.ts` | `resolveHome` / `setHome`: the single folder everything is stored in. |
|
|
9
9
|
| `env.ts` | Process-env lookups and API key resolution. No `globalThis` fallback. |
|
|
10
10
|
| `headers.ts` | Session-affinity headers, opt-in attribution, browser stripping, package version fallback. |
|
|
@@ -12,8 +12,8 @@ Small shared helpers. Each file has one job.
|
|
|
12
12
|
| `safe-io.ts` | `fileAccess.roots` containment and the guarded remote fetch (private hosts refused, redirects re-checked, size cap). |
|
|
13
13
|
| `raw-capture.ts` | The `captureRaw` policy for `AgentResponse.raw`. |
|
|
14
14
|
| `cache.ts` | Cache-key clamp (64 chars) and the central secret redaction. |
|
|
15
|
-
| `errors.ts` | `toConciseProviderError` and pre-network modality guards. |
|
|
16
|
-
| `retry.ts` | `withRetries`, `isTransientError
|
|
15
|
+
| `errors.ts` | `toConciseProviderError` (any raw provider failure becomes one-line `ProviderError`: `code` `"provider"`, `retryable` from status/code, the provider's code as `providerCode`; SDK errors pass through), `isTransientError`, and the pre-network modality guards (`ValidationError`). |
|
|
16
|
+
| `retry.ts` | `withRetries`, `isTransientError` (re-exported from `errors.ts`), `isRetryableRun`, `sleep`. Structured data only (status, code, flags), never message text. |
|
|
17
17
|
| `session.ts` | Id helpers (`createSessionId`, `hashSessionPart`, `createTrackingId`, run/turn ids), `parseModelRef`, `previewPrompt`. |
|
|
18
18
|
| `serialization.ts` | `toJsonSafe`, `safeStringify`, `escapeXml`. |
|
|
19
19
|
| `base64.ts`, `thought-signature.ts` | Runtime-agnostic base64; Gemini thought-signature helpers. |
|