agent-accelerator 0.5.5 → 0.5.7

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.
Files changed (47) hide show
  1. package/README.md +16 -17
  2. package/package.json +1 -1
  3. package/src/agent/agent.ts +16 -18
  4. package/src/agent/architecture.md +25 -0
  5. package/src/agent/context.ts +4 -0
  6. package/src/agent/delegation.ts +18 -84
  7. package/src/agent/loop.ts +14 -16
  8. package/src/agent/worker.ts +1 -3
  9. package/src/architecture.md +28 -0
  10. package/src/index.ts +6 -73
  11. package/src/models/architecture.md +14 -0
  12. package/src/models/catalog-cache.ts +3 -0
  13. package/src/models/catalog.ts +7 -0
  14. package/src/providers/architecture.md +24 -0
  15. package/src/providers/google.ts +26 -39
  16. package/src/providers/openai-compat.ts +53 -104
  17. package/src/providers/openai.ts +47 -104
  18. package/src/providers/openrouter.ts +114 -175
  19. package/src/providers/registry.ts +1 -0
  20. package/src/providers/shared.ts +134 -5
  21. package/src/providers.ts +30 -59
  22. package/src/scheduler/architecture.md +19 -0
  23. package/src/scheduler/scheduler.ts +21 -0
  24. package/src/scheduler/store.ts +6 -0
  25. package/src/scheduler/time.ts +2 -0
  26. package/src/session/architecture.md +19 -0
  27. package/src/session/store.ts +18 -3
  28. package/src/session/usage.ts +1 -0
  29. package/src/streaming/architecture.md +13 -0
  30. package/src/streaming/event-stream.ts +5 -0
  31. package/src/telemetry.ts +1 -0
  32. package/src/tools/architecture.md +19 -0
  33. package/src/tools/executor.ts +13 -0
  34. package/src/tools/schema.ts +1 -0
  35. package/src/tools/subagent-result.ts +1 -0
  36. package/src/types/architecture.md +20 -0
  37. package/src/types/message.ts +1 -1
  38. package/src/utils/architecture.md +25 -0
  39. package/src/utils/base64.ts +2 -0
  40. package/src/utils/cache.ts +2 -0
  41. package/src/utils/errors.ts +8 -1
  42. package/src/utils/headers.ts +4 -1
  43. package/src/utils/media.ts +11 -1
  44. package/src/utils/raw-capture.ts +3 -0
  45. package/src/utils/retry.ts +1 -0
  46. package/src/utils/safe-io.ts +4 -0
  47. package/src/utils/session.ts +5 -161
@@ -1,7 +1,5 @@
1
1
  import { clampCacheKey } from "./cache.ts";
2
2
  import type { ThinkingLevel } from "../types/core.ts";
3
- import type { MidSessionMode } from "../types/agent.ts";
4
- import type { AgentConfig } from "../types/agent.ts";
5
3
  import type { ModelSpec } from "../types/model.ts";
6
4
  import type { ModelProviderInstance } from "../providers/registry.ts";
7
5
  import type { ContentPart } from "../types/message.ts";
@@ -83,6 +81,7 @@ export function nowMs(): number {
83
81
  return Date.now();
84
82
  }
85
83
 
84
+ // 32 random lowercase hex characters; in: newRunId/newTurnId, out: a string.
86
85
  function random32Hex(): string {
87
86
  try {
88
87
  const c = (globalThis as any)?.crypto;
@@ -111,14 +110,7 @@ export function newTurnId(): string {
111
110
  return random32Hex();
112
111
  }
113
112
 
114
- /**
115
- * Single canonical prompt preview (Q-49): merges the former
116
- * `previewPrompt` (agent.ts) / `steerPreview` (loop.ts) duplicates.
117
- * Bounded to 500 chars, display-only. Other modules own their copies;
118
- * new code should import this one.
119
- *
120
- * @example `previewPrompt("hello")`
121
- */
113
+ /** Bounded (500 chars), display-only preview of a prompt, used in `queued`/`steer_injected` events, turn lists and `interrupted()`. */
122
114
  export function previewPrompt(prompt: string | ContentPart[]): string {
123
115
  if (typeof prompt === "string") return prompt.slice(0, 500);
124
116
  try {
@@ -141,6 +133,7 @@ export interface ParsedModelRef {
141
133
  thinking?: ThinkingLevel;
142
134
  }
143
135
 
136
+ // Splits `provider/model` on the first slash (bare ids default to openrouter); in: parseModelRef, out: provider and model id.
144
137
  function splitModelString(raw: string): { provider: string; modelId: string } {
145
138
  const trimmed = raw.trim();
146
139
  const slash = trimmed.indexOf("/");
@@ -153,12 +146,14 @@ function splitModelString(raw: string): { provider: string; modelId: string } {
153
146
  };
154
147
  }
155
148
 
149
+ // Type guard for a `{ model: string }` helper result; in: parseModelRef, out: a boolean.
156
150
  function isModelProviderInstance(v: unknown): v is ModelProviderInstance {
157
151
  if (!v || typeof v !== "object" || Array.isArray(v)) return false;
158
152
  const r = v as Record<string, unknown>;
159
153
  return typeof r["model"] === "string" && (r["model"] as string).length > 0;
160
154
  }
161
155
 
156
+ // Type guard for a catalog spec (`provider` and `id` strings); in: parseModelRef, out: a boolean.
162
157
  function isModelSpec(v: unknown): v is ModelSpec {
163
158
  if (!v || typeof v !== "object" || Array.isArray(v)) return false;
164
159
  const r = v as Record<string, unknown>;
@@ -192,154 +187,3 @@ export function parseModelRef(input: string | ModelSpec | ModelProviderInstance)
192
187
  }
193
188
  throw new ConfigError("parseModelRef: expected string | ModelSpec | ModelProviderInstance.");
194
189
  }
195
-
196
- /** Validated, readonly agent configuration returned by {@link resolveAgentConfig} (Q-32). */
197
- export interface ResolvedAgentConfig {
198
- readonly model: NonNullable<AgentConfig["model"]>;
199
- readonly thinkingLevel?: ThinkingLevel;
200
- readonly maxTurns: number;
201
- readonly midSession: { readonly mode: MidSessionMode; readonly maxQueued: number };
202
- readonly toolNames: readonly string[];
203
- }
204
-
205
- const VALID_THINKING_LEVELS: readonly ThinkingLevel[] = [
206
- "none",
207
- "dynamic",
208
- "minimal",
209
- "low",
210
- "medium",
211
- "high",
212
- "xhigh",
213
- "max",
214
- ];
215
-
216
- const VALID_MIDSESSION_MODES: readonly MidSessionMode[] = ["steer", "queue", "auto"];
217
-
218
- /** Local name normalization mirroring `normalizeToolName` (no import cycle, Q-32). */
219
- function normalizeConfigToolName(name: string): string {
220
- return name
221
- .trim()
222
- .replace(/^(?:functions?|tools?)\./i, "")
223
- .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
224
- .replace(/[\s-]+/g, "_")
225
- .toLowerCase();
226
- }
227
-
228
- /**
229
- * Single config resolution (Q-32). Validates `model`, `thinkingLevel`,
230
- * `maxTurns`, `midSession`, and tool-name collisions, collecting EVERY issue
231
- * and throwing one `ConfigError` listing all of them. Not wired into `Agent`
232
- * (other owner) — call it from setup paths that want fail-fast validation.
233
- *
234
- * @example `const cfg = resolveAgentConfig({ model, maxTurns: 10 });`
235
- */
236
- export function resolveAgentConfig(config: AgentConfig): Readonly<ResolvedAgentConfig> {
237
- const issues: string[] = [];
238
- const cfg = (config ?? {}) as AgentConfig;
239
-
240
- let model: NonNullable<AgentConfig["model"]> | undefined;
241
- const rawModel = cfg.model;
242
- if (typeof rawModel === "string") {
243
- if (rawModel.trim()) model = rawModel;
244
- else issues.push("model: must be a non-empty string | ModelSpec | ModelProviderInstance.");
245
- } else if (rawModel && typeof rawModel === "object") {
246
- model = rawModel as NonNullable<AgentConfig["model"]>;
247
- } else {
248
- issues.push("model: is required (string | ModelSpec | ModelProviderInstance).");
249
- }
250
-
251
- let thinkingLevel: ThinkingLevel | undefined;
252
- if (cfg.thinkingLevel !== undefined) {
253
- if ((VALID_THINKING_LEVELS as readonly string[]).includes(cfg.thinkingLevel)) {
254
- thinkingLevel = cfg.thinkingLevel;
255
- } else {
256
- issues.push(
257
- `thinkingLevel: invalid '${cfg.thinkingLevel}'. Expected one of: ${VALID_THINKING_LEVELS.join(", ")}.`
258
- );
259
- }
260
- }
261
-
262
- let maxTurns = Infinity;
263
- if (cfg.maxTurns !== undefined) {
264
- const m = cfg.maxTurns;
265
- if (m === 0) {
266
- maxTurns = Infinity;
267
- } else if (m === Infinity) {
268
- maxTurns = Infinity;
269
- } else if (typeof m === "number" && Number.isFinite(m) && m >= 1) {
270
- maxTurns = Math.floor(m);
271
- } else {
272
- issues.push(`maxTurns: must be finite >= 1 or Infinity (0/omitted means unlimited). Received: ${String(m)}.`);
273
- }
274
- }
275
-
276
- let mode: MidSessionMode = "auto";
277
- if (cfg.midSession?.mode !== undefined) {
278
- if ((VALID_MIDSESSION_MODES as readonly string[]).includes(cfg.midSession.mode as string)) {
279
- mode = cfg.midSession.mode as MidSessionMode;
280
- } else {
281
- issues.push(
282
- `midSession.mode: invalid '${String(cfg.midSession.mode)}'. Expected one of: ${VALID_MIDSESSION_MODES.join(", ")}.`
283
- );
284
- }
285
- }
286
- let maxQueued = 20;
287
- if (cfg.midSession?.maxQueued !== undefined) {
288
- const q = cfg.midSession.maxQueued;
289
- if (typeof q === "number" && Number.isFinite(q) && Math.floor(q) === q && q >= 0) {
290
- maxQueued = q;
291
- } else {
292
- issues.push(`midSession.maxQueued: must be an integer >= 0. Received: ${String(q)}.`);
293
- }
294
- }
295
-
296
- const toolNames: string[] = [];
297
- const tools = cfg.tools;
298
- if (tools !== undefined) {
299
- const entries: Array<[string, string]> = [];
300
- if (Array.isArray(tools)) {
301
- for (const def of tools) {
302
- const declared = (def as { name?: unknown })?.name;
303
- if (typeof declared === "string" && declared.trim()) {
304
- toolNames.push(declared);
305
- entries.push([declared, declared]);
306
- } else {
307
- issues.push("tools: array entries must declare a non-empty `name`.");
308
- }
309
- }
310
- } else if (tools && typeof tools === "object") {
311
- for (const [key, def] of Object.entries(tools)) {
312
- toolNames.push(key);
313
- const declared = (def as { name?: unknown })?.name;
314
- entries.push([key, typeof declared === "string" && declared ? declared : key]);
315
- }
316
- } else {
317
- issues.push("tools: must be a record or array of ToolDefinitions.");
318
- }
319
- const seen = new Map<string, string>();
320
- for (const [key, declared] of entries) {
321
- for (const candidate of new Set([key, declared])) {
322
- const normalized = normalizeConfigToolName(String(candidate));
323
- const prev = seen.get(normalized);
324
- if (prev !== undefined && prev !== key) {
325
- issues.push(
326
- `tools: name collision: '${prev}' and '${key}' both normalize to '${normalized}'. Rename one tool.`
327
- );
328
- } else if (prev === undefined) {
329
- seen.set(normalized, key);
330
- }
331
- }
332
- }
333
- }
334
-
335
- if (issues.length > 0) {
336
- throw new ConfigError(`Invalid Agent config (${issues.length} issue${issues.length === 1 ? "" : "s"}): ${issues.join(" ")}`);
337
- }
338
- return {
339
- model: model as NonNullable<AgentConfig["model"]>,
340
- ...(thinkingLevel !== undefined ? { thinkingLevel } : {}),
341
- maxTurns,
342
- midSession: { mode, maxQueued },
343
- toolNames,
344
- };
345
- }