agent-accelerator 0.1.0 → 0.3.0

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 (48) hide show
  1. package/README.md +174 -123
  2. package/{SYSTEM_PROMPT_AGENT.md → examples/prompts/SYSTEM_PROMPT_AGENT.md} +1 -1
  3. package/package.json +14 -9
  4. package/src/agent/agent.ts +385 -73
  5. package/src/agent/context.ts +1 -0
  6. package/src/agent/delegation.ts +443 -30
  7. package/src/agent/loop.ts +183 -53
  8. package/src/data/README.md +6 -6
  9. package/src/index.ts +163 -46
  10. package/src/models/catalog-cache.ts +60 -9
  11. package/src/models/catalog.ts +55 -8
  12. package/src/providers/google.ts +926 -0
  13. package/src/providers/openai-compat.ts +1147 -0
  14. package/src/providers/openai.ts +959 -0
  15. package/src/providers/openrouter-responses.ts +949 -0
  16. package/src/providers/openrouter.ts +1037 -0
  17. package/src/{ai-sdk → providers}/registry.ts +43 -55
  18. package/src/providers.ts +492 -0
  19. package/src/session/store.ts +806 -0
  20. package/src/streaming/sse-parser.ts +6 -4
  21. package/src/tools/executor.ts +23 -7
  22. package/src/tools/schema.ts +21 -11
  23. package/src/types/agent.ts +33 -2
  24. package/src/types/core.ts +3 -2
  25. package/src/types/message.ts +5 -0
  26. package/src/types/model.ts +3 -7
  27. package/src/types/provider-payloads.ts +2 -84
  28. package/src/types/response.ts +24 -0
  29. package/src/types/tool.ts +8 -0
  30. package/src/update-models.ts +56 -0
  31. package/src/utils/cache.ts +1 -1
  32. package/src/utils/documents.ts +517 -0
  33. package/src/utils/env.ts +0 -7
  34. package/src/{ai-sdk → utils}/errors.ts +61 -2
  35. package/src/utils/headers.ts +10 -20
  36. package/src/utils/media.ts +5 -2
  37. package/src/utils/retry.ts +89 -0
  38. package/src/utils/serialization.ts +15 -0
  39. package/src/utils/session.ts +36 -0
  40. package/src/ai-sdk/converters.ts +0 -342
  41. package/src/ai-sdk/executor.ts +0 -454
  42. package/src/ai-sdk/index.ts +0 -55
  43. package/src/ai-sdk/model-provider.ts +0 -303
  44. package/src/ai-sdk/options.ts +0 -306
  45. package/src/ai-sdk/provider.ts +0 -415
  46. package/src/tokens/counter.ts +0 -136
  47. /package/{SYSTEM_PROMPT.md → examples/prompts/SYSTEM_PROMPT.md} +0 -0
  48. /package/{SYSTEM_PROMPT_TOOLS.md → examples/prompts/SYSTEM_PROMPT_TOOLS.md} +0 -0
package/README.md CHANGED
@@ -1,13 +1,14 @@
1
1
  # Agent Accelerator
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/agent-accelerator.svg?color=cb3837&logo=npm)](https://www.npmjs.com/package/agent-accelerator)
3
4
  [![GitHub](https://img.shields.io/badge/GitHub-sashvat--bharat%2Fagent--accelerator-blue?logo=github)](https://github.com/sashvat-bharat/agent-accelerator)
4
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
6
 
6
- A thin, typed transport SDK for calling LLMs through a single `Agent` interface.
7
+ > **Stability notice:** Agent Accelerator is pre-1.0 and under active development. Public APIs, provider transports, and configuration options may still change in breaking ways between releases. For production use, please pin your dependency to an exact version.
7
8
 
8
- GitHub: [https://github.com/sashvat-bharat/agent-accelerator](https://github.com/sashvat-bharat/agent-accelerator)
9
+ A thin, typed transport SDK for calling LLMs through a single `Agent` interface.
9
10
 
10
- Agent Accelerator supports `google`, `opencode`, `openrouter`, `openai`, and any OpenAI-compatible endpoint using `{PREFIX}_API_KEY` and `{PREFIX}_BASE_URL`.
11
+ Agent Accelerator supports `google`, `openrouter`, `openai`, and any OpenAI-compatible endpoint using `{PREFIX}_API_KEY` and `{PREFIX}_BASE_URL`.
11
12
 
12
13
 
13
14
  ```ts
@@ -45,7 +46,7 @@ yarn add agent-accelerator
45
46
 
46
47
  Requires `bun` or `node 22+`.
47
48
 
48
- Core dependencies are `zod`, `ai`, and selected `@ai-sdk/*` provider packages used as the backend transport.
49
+ Core dependencies are `zod` only. Document conversion additionally uses the optional `@firecrawl/anydoc` peer. All provider transports are native REST (`fetch`, no SDK).
49
50
 
50
51
  ---
51
52
 
@@ -53,7 +54,6 @@ Core dependencies are `zod`, `ai`, and selected `@ai-sdk/*` provider packages us
53
54
 
54
55
  ```bash
55
56
  GEMINI_API_KEY=...
56
- OPENCODE_API_KEY=...
57
57
  OPENROUTER_API_KEY=...
58
58
  OPENAI_API_KEY=...
59
59
  # or OPENAI_BASE_API_KEY=...
@@ -126,15 +126,17 @@ An `Agent` holds :
126
126
  | `subagents` | `SubAgent[] \| Agent[]` | Pre-defined workers. Each worker becomes a callable tool. Useful for fixed roles such as researcher or critic. |
127
127
  | `subagentModel` | `string \| ModelSpec \| ModelProviderInstance` | Developer-only model for dynamically spawned workers. Never choosable by the Main Agent. Overridden by `dynamicSubagents.model`. Falls back to `SUB_AGENT_MODEL`. |
128
128
  | `dynamicSubagents` | `DynamicSubagentsConfig` | Enables and constrains LLM-spawned stateless workers: `{ enabled, model?, maxSpawn?, thinkingLevel?, tools?, timeout? }`. See [Dynamic delegation](#dynamic-delegation). |
129
- | `thinkingLevel` | `ThinkingLevel` | `none \| dynamic \| minimal \| low \| medium \| high \| xhigh`. Validated against the model catalog before a request. |
129
+ | `thinkingLevel` | `ThinkingLevel` | `none \| dynamic \| minimal \| low \| medium \| high \| xhigh \| max`. Validated against the model catalog before a request. |
130
130
  | `cache` | `CacheConfig` | `{ retention, sessionId, cachedContentId, ttlSeconds }`. Controls cache reuse. |
131
131
  | `serviceTier` | `"flex" \| "priority"` | Cost / priority routing where supported. Omit for standard routing. |
132
- | `maxTurns` | `number` | Maximum model → tool → model loops per `run`. Defaults to `10`. |
132
+ | `bypassInputFileModality` | `boolean` | When `true`, `file` parts are converted client-side to Markdown for models lacking native support. Capable models still receive files natively. Defaults to `false`. |
133
+ | `maxTurns` | `number` | Maximum model → tool → model loops per `run`. Infinite by default (`0` or omitted = no limit). Hitting a finite limit with pending tool calls warns and sets `finishReason: "max_turns"`. |
133
134
  | `sessionId` | `string` | Stable identifier used for cache affinity. Auto-generated when omitted. |
134
135
  | `headers` | `Record<string,string>` | Additional headers merged into every request. |
135
136
  | `apiKey` | `string` | Overrides environment-based API-key lookup for this agent. |
136
137
  | `baseUrl` | `string` | Overrides the default endpoint for this agent. |
137
138
  | `stateless` | `boolean` | When `true`, history is cleared before and after each `run`. Useful for one-shot evaluators. Defaults to `false`. |
139
+ | `persist` | `{ dir?: string; file?: string }` | Durable sessions: rewrites the session file after every step (user/assistant/tool/sub-agent). `{ dir }` uses `sessions/<sessionId>/session.json`, `{ file }` a single `.session.json`. Writes are atomic and never fail a turn. |
138
140
 
139
141
  When `dynamicSubagents.enabled` is set without a resolvable worker model, construction throws `SubAgentModelError`.
140
142
 
@@ -145,6 +147,12 @@ await agent.run(prompt, opts?) // non-streaming, or streaming when opts.stream i
145
147
  agent.ask(prompt, optsOrBool?) // string deltas when streaming, otherwise same as run
146
148
  agent.stream(prompt, opts?) // AssistantMessageEventStream
147
149
  agent.reset() // clears messages + signatures, keeps config
150
+ agent.exportSession(telemetry?) // storable snapshot for saveSessionFile
151
+ agent.importSession(saved) // restores messages + config from loadSessionFile
152
+ agent.track(trackingId) // live snapshot of one sub-agent worker (`NAME-{TrackingID}`)
153
+ agent.listTrackedSubAgents() // TrackingIDs of known workers
154
+ agent.subscribeToSubAgent(id, fn) // live worker updates, returns unsubscribe fn
155
+ agent.persistNow() // rewrites the persist target now (no-op unless persist is set)
148
156
  ```
149
157
 
150
158
  `prompt` accepts `string | ContentPart[]`.
@@ -158,8 +166,9 @@ Use `ContentPart[]` when sending images, audio, or video alongside text.
158
166
  | `stream` | When `true`, returns a stream instead of a regular response promise. |
159
167
  | `onDelta(delta, event)` | Called for each text chunk. Use to render answers live. |
160
168
  | `onThinkingDelta(delta, event)` | Called for each reasoning chunk. Use to render reasoning separately. |
161
- | `onEvent(event)` | Called for every event: `text_delta`, `thinking_delta`, `tool_call_complete`, `tool_result`, `subagent_complete`, `usage`, `done`, and `error`. |
169
+ | `onEvent(event)` | Called for every event: `text_delta`, `thinking_delta`, `tool_call_complete`, `tool_result`, `subagent_complete`, `subagent_delta`, `usage`, `done`, and `error`. |
162
170
  | `wrapThinking` | Wraps reasoning as `<think>\n...\n</think>\n\n`, allowing UIs to render it without maintaining separate state. |
171
+ | `onTurn(turn)` | Called after every model/tool turn with `{ turns, text?, thinking?, toolCalls?, toolResults? }`. Drives sub-agent step logs and persistence. |
163
172
  | `additionalContext` | Added only to the current user turn. Keeps the system prompt stable for better caching. |
164
173
  | `sessionId` | Per-run session override. |
165
174
  | `headers` | Per-run header merge. |
@@ -289,6 +298,8 @@ A `spawn_subagents` tool is injected with the following task shape:
289
298
  - `tools` — developer-owned pool. Workers get zero tools unless the Main Agent grants a per-task `tools` subset by name (unknown names are ignored), keeping worker context small.
290
299
  - `timeout` (ms) — `0` = no limit, `-1` = the Main Agent sets a per-task `timeoutMs`, `>0` = fixed limit for every worker. Timed-out workers report an error entry; the rest of the batch still completes.
291
300
  - Workers are stateless: one task in, one result out, then shut down. No history, no recursion. The Main Agent cannot choose worker models or reasoning levels.
301
+ - Worker names use UPPER-KEBAB (`HBM-PRICING-ANALYST`). Each worker gets a system-generated 32-char TrackingID, displayed as `NAME-{TrackingID}` (e.g. `HBM-PRICING-ANALYST-9f2c…`).
302
+ - Workers stream internally: thinking/text deltas update the worker trace live (`agent.track(id)`, `subscribeToSubAgent`) and surface on the parent stream as `subagent_delta` events.
292
303
 
293
304
  ```ts
294
305
  const res = await agent.run("Audit auth pipeline and write a threat model");
@@ -327,11 +338,12 @@ const agent = new Agent({
327
338
 
328
339
  ### Tool Helpers
329
340
 
330
- * `tool({ name?, description, input?, parameters?, strict?, timeoutMs?, maxTries?, maxConcurrency?, execute })` — creates a `ToolDefinition`. Provide either a Zod `input` schema or raw JSON `parameters`. `execute(input, ctx)` may return arbitrary values; results are converted safely for model context. `timeoutMs` defaults to `0` (no time limit) and is a best-effort event-loop deadline; `ctx.signal` enables cooperative cancellation. `maxTries` accepts a number or numeric string; a positive value is the total attempt limit, while `0`/omitted means no configured limit for transient retries. `maxConcurrency` limits simultaneous calls for that tool (default pool: 8).
341
+ * `tool({ name?, description, input?, parameters?, strict?, timeoutMs?, maxTries?, maxConcurrency?, execute })` — creates a `ToolDefinition`. Provide either a Zod `input` schema or raw JSON `parameters`. `execute(input, ctx)` may return arbitrary values; results are converted safely for model context. `timeoutMs` defaults to `0` (no time limit) and is a best-effort event-loop deadline; `ctx.signal` enables cooperative cancellation. `maxTries` accepts a number or numeric string; a positive value is the total attempt limit, while `0`/omitted falls back to 3 attempts. `maxConcurrency` limits simultaneous calls for that tool (default pool: 8).
331
342
  * `toStandardToolDeclarations(record | array)` — converts tools to `{ name, description, parameters }` for providers.
332
343
  * `zodToJsonSchema(schema)` — converts Zod schemas using native conversion with a fallback extractor.
333
344
  * `cleanJsonSchema(schema)` — removes `$schema`, `$defs`, and `definitions`, resolves `$ref`, and preserves explicit `additionalProperties`.
334
345
  * `executeToolCalls({ tools, toolCalls, agentName?, parallel?, signal?, sessionId? })` — executes tool calls. Calls validate Zod input, use bounded parallelism, enforce per-tool timeouts, retry transient failures, recover namespace/camel-case tool-name aliases, and return `ToolResultRecord[]`. Missing tools and aborts are represented as error results rather than thrown.
346
+ * `convert_document_to_markdown` — built-in tool that converts document files (PDF/Word/PowerPoint/Excel/OpenDocument/RTF/EPUB/CSV, local path or URL) to Markdown for models without native document parsing. Requires the optional `@firecrawl/anydoc` peer.
335
347
 
336
348
  The agent loop also blocks an identical tool name and argument set when the model requests it in the immediately following turn. The synthetic error is returned to the model so it can reuse the prior result or change its arguments.
337
349
 
@@ -386,7 +398,8 @@ for (const result of response.toolResults) {
386
398
  name,
387
399
  arguments,
388
400
  rawArguments?,
389
- thoughtSignature?
401
+ thoughtSignature?,
402
+ callId?,
390
403
  }
391
404
  ```
392
405
 
@@ -408,7 +421,6 @@ for (const result of response.toolResults) {
408
421
  First-class provider IDs are:
409
422
 
410
423
  * `google`
411
- * `opencode`
412
424
  * `openrouter`
413
425
  * `openai`
414
426
 
@@ -417,9 +429,6 @@ Any other provider prefix is treated as an OpenAI-compatible custom provider.
417
429
  ### Model Strings
418
430
 
419
431
  * `"google/<id>"` → Google AI Studio at `generativelanguage.googleapis.com`.
420
- * `"opencode/<id>"` → OpenCode Zen at `opencode.ai/zen/v1`.
421
- * `"opencode-go/<id>"` → OpenCode Go endpoint.
422
- * OpenCode automatically selects Chat vs Responses API. Claude models and models using `api=openai-responses` use Responses.
423
432
  * `"openrouter/<scope>/<model>"` or `"scope/model:variant"` → OpenRouter.
424
433
  * `"openai/<id>"` → OpenAI.
425
434
  * `"groq/<id>"`, `"ollama/<id>"`, etc. → custom providers using `{PREFIX}_API_KEY` and `{PREFIX}_BASE_URL`. The API key is optional for local endpoints.
@@ -437,7 +446,7 @@ An unknown prefix with no catalog match still routes to a custom provider, allow
437
446
  * `getProvider("groq")` → returns a cached provider and automatically creates a custom provider for unknown prefixes.
438
447
  * `ensureCustomProvider(prefix, { baseUrl?, apiKey?, name? })` → gets or creates a custom provider. Useful for multiple endpoints in one process.
439
448
  * `normalizeProviderPrefix(s)` → lowercases and trims a provider prefix.
440
- * `ModelProvider.GoogleGenAI(model, apiKey?, { thinkingLevel?, baseUrl? })` — same shape is available for `.OpenCode`, `.OpenRouter`, `.OpenAI`, `.Custom`, `.OpenAICompatible`, and `.Generic`.
449
+ * `ModelProvider.GoogleGenAI(model, apiKey?, { thinkingLevel?, baseUrl? })` — same shape is available for `.OpenRouter`, `.OpenAI`, `.Custom`, `.OpenAICompatible`, and `.Generic`.
441
450
 
442
451
  Each returns a `ModelProviderInstance`:
443
452
 
@@ -472,93 +481,82 @@ new Agent({
472
481
  });
473
482
  ```
474
483
 
475
- `BaseProvider` is the abstract provider base containing `id`, `name`, `models`, `getModel`, `generate`, `stream`, and `countTokens`.
484
+ `Provider` is the provider contract containing `id`, `name`, `models`, `getModel`, `generate`, and `stream`.
476
485
 
477
- Its catalog-first `getModel` behavior includes a hardcoded fallback.
486
+ Its catalog-first `getModel` behavior includes a permissive fallback (`createGenericModelSpec`) so private model IDs never fail preflight.
478
487
 
479
- Extend `BaseProvider` when implementing a fully custom transport.
488
+ Implement the `Provider` interface when adding a fully custom transport.
480
489
 
481
490
  `ProviderRequestOptions { apiKey?, baseUrl?, headers?, thinking?, cache?, serviceTier?, tools?, toolChoice?, signal?, sessionId?, env? }` is the per-call options object passed to `generate`/`stream`. Agent builds it automatically.
482
491
 
483
492
  ### Google
484
493
 
485
- `GoogleAIStudioProvider` and `GOOGLE_MODELS` provide Google AI Studio support.
494
+ `GoogleInteractionsProvider` (aliased as `GoogleAIStudioProvider`) and `GOOGLE_MODELS` provide Google support over the Interactions API (`POST {baseUrl}/interactions`, streaming via `?alt=sse`).
486
495
 
487
- The catalog is filtered with fallback support for lite and flash models.
496
+ Turns chain statefully through `previous_interaction_id` per session, falling back to stateless full-history sends when the session switches providers or models.
488
497
 
489
- Google models matching `gemini-1.x` or `gemini-2.x` are rejected.
490
-
491
- Thinking levels map to:
498
+ Thinking levels map to `thinking_level`, with `thinking_summaries` enabled whenever thinking is active:
492
499
 
493
500
  ```text
494
- OFF | MINIMAL | LOW | MEDIUM | HIGH
501
+ minimal | low | medium | high (xhigh/max clamp to high; none is unsupported and omitted; dynamic omits)
495
502
  ```
496
503
 
497
504
  Google-specific handling includes:
498
505
 
499
506
  * Isolating `thoughtSignature` per part for prefix stability.
500
507
  * Converting JSON Schema to OpenAPI 3.0 through `stripSchemaForGoogle`.
501
- * Supporting explicit `cachedContents` when `retention != implicit` and the prompt is large.
508
+ * Implicit/automatic caching only — explicit retention and `cachedContentId` are warned about and dropped (the Interactions API defines no explicit cache primitives).
502
509
 
503
510
  Helpers:
504
511
 
505
512
  * `createExplicitCache({ model, systemInstruction?, contents?, tools?, displayName?, ttlSeconds?, expireTime?, apiKey?, baseUrl? })`
506
513
  * `isValidThoughtSignature(sig)`
507
514
  * `retainThoughtSignature(existing, incoming)`
515
+ * `extractGoogleThoughtSignature(obj)`
508
516
  * `stripSchemaForGoogle(schema)`
517
+ * `clearInteractionChains(sessionId?)`
509
518
 
510
519
  ### OpenAI
511
520
 
512
- `OpenAIProvider` and `OPENAI_MODELS` provide OpenAI support.
521
+ `OpenAIResponsesProvider` (aliased as `OpenAIProvider`) and `OPENAI_MODELS` provide OpenAI support over the Responses API (`POST {baseUrl}/responses`).
513
522
 
514
- `OpenAIProvider` is also the base class for OpenAI-wire transports.
523
+ Every turn is stateless: the full history is sent explicitly with `store: false`, so no `previous_response_id`, `background`, or conversation chaining is ever used.
515
524
 
516
- Thinking levels map to:
525
+ Thinking levels map to `reasoning.effort` verbatim:
517
526
 
518
527
  ```text
519
- reasoning_effort: low | medium | high
528
+ none | minimal | low | medium | high | xhigh | max (dynamic omits — server default)
520
529
  ```
521
530
 
522
531
  It also:
523
532
 
524
- * passes `service_tier`;
525
- * derives `max_completion_tokens` from the configured budget;
526
- * preserves Google thought signatures through `extra_content.google.thought_signature`;
527
- * exposes `extractGoogleThoughtSignature(obj)`.
528
-
529
- ### OpenCode
530
-
531
- `OpenCodeProvider` and `OPENCODE_MODELS` provide OpenCode support.
532
-
533
- Requests include:
534
-
535
- * `session_id`
536
- * `prompt_cache_key`
537
- * headers used for sticky routing
538
-
539
- The provider handles both Chat and Responses payloads.
540
-
541
- Transient `500`, `502`, `503`, and `529` errors are retried with thinking disabled, followed by an attempt using the alternate endpoint.
533
+ * passes `service_tier` (`flex` | `priority`);
534
+ * pins cache affinity with `prompt_cache_key` (clamped to 64 chars);
535
+ * rejects `video` parts up front with a one-line error (the Responses wire carries text/image/file only);
536
+ * never sends `temperature`, token caps, or background/conversation fields.
542
537
 
543
538
  ### OpenRouter
544
539
 
545
- `OpenRouterProvider` and `OPENROUTER_MODELS` provide OpenRouter support.
540
+ `OpenRouterChatCompletionsProvider` (aliased as `OpenRouterProvider` / `OpenRouter`) and `OPENROUTER_MODELS` provide OpenRouter support over Chat Completions (`POST {baseUrl}/chat/completions`).
546
541
 
547
- Requests include:
542
+ Every turn is stateless: the full `messages[]` array is sent explicitly — no chaining primitives exist on this endpoint.
548
543
 
549
- * `session_id`
550
- * `prompt_cache_key`
544
+ Session affinity is a top-level body `session_id` plus the `x-session-id` header fallback (body takes precedence per OpenRouter docs).
551
545
 
552
- Thinking is mapped to:
546
+ Thinking levels map to `reasoning.effort` verbatim:
553
547
 
554
548
  ```text
555
- reasoning { effort | enabled }
556
- include_reasoning
549
+ none | minimal | low | medium | high | xhigh | max (dynamic omits — server default)
557
550
  ```
558
551
 
559
- based on catalog capabilities.
552
+ It also:
553
+
554
+ * passes `service_tier` (`flex` | `priority`);
555
+ * enables the `file-parser` plugin when file parts are present (remote file URLs are additionally surfaced in text);
556
+ * maps `tool_choice` (`auto` omitted; `none`, `required`, and function pins supported);
557
+ * reports `cached_tokens` / `cache_write_tokens` / reasoning tokens, preferring provider-reported `cost` when present.
560
558
 
561
- `serviceTier` is mapped to provider routing.
559
+ `serviceTier` values other than `flex` / `priority` are omitted (standard routing).
562
560
 
563
561
  ### Custom
564
562
 
@@ -588,7 +586,6 @@ Examples include:
588
586
 
589
587
  * `OpenAIChatCompletionRequest`
590
588
  * `GoogleGenerateContentRequest`
591
- * `OpenCodeChatRequest`
592
589
  * `OpenRouterChatRequest`
593
590
 
594
591
  ---
@@ -604,14 +601,15 @@ ThinkingLevel =
604
601
  | "low"
605
602
  | "medium"
606
603
  | "high"
607
- | "xhigh";
604
+ | "xhigh"
605
+ | "max";
608
606
  ```
609
607
 
610
608
  ### Thinking Levels
611
609
 
612
610
  * `none` — disables thinking where supported.
613
611
  * `dynamic` — allows the model to decide.
614
- * `minimal`, `low`, `medium`, `high`, `xhigh` — request increasing levels of reasoning where supported.
612
+ * `minimal`, `low`, `medium`, `high`, `xhigh`, `max` — request increasing levels of reasoning where supported.
615
613
 
616
614
  Thinking can be configured on the `Agent` or through `ModelProvider.*(..., { thinkingLevel })`.
617
615
 
@@ -632,6 +630,7 @@ ThinkingConfig {
632
630
 
633
631
  * `getModelThinkingInfo(provider, modelId)` → `{ supportsThinking, reasoningOptions?, allowedLevels, supportsDisable, description }`. Useful for building UI selectors.
634
632
  * `validateModelThinking(provider, modelId, level)` → throws `ThinkingLevelError { provider, modelId, requestedLevel, allowedLevels, supportsThinking }` with a fix hint. Automatically called by `run` and `stream`. Catch it and use `err.allowedLevels` to offer valid options.
633
+ * `resolveEffectiveThinking(base, override?)` → resolves a per-run `thinkingLevel` override into a `ThinkingConfig` without mutating agent config.
635
634
  * `getModelsForProvider("google")` → returns known model specifications.
636
635
 
637
636
  Unknown models allow all thinking levels.
@@ -660,40 +659,40 @@ CacheRetention =
660
659
 
661
660
  ### Retention
662
661
 
663
- * `implicit` — automatic prefix reuse without an explicit cache object or storage fee.
664
- * `short` — approximately 5 minutes.
665
- * `medium` — approximately 1 hour.
666
- * `long` — approximately 12 hours for Google explicit caches and approximately 24 hours for prompt caching where supported.
662
+ * `implicit` — automatic prefix reuse without an explicit cache object or storage fee. This is the only retention the native adapters act on (by doing nothing special — stable prompts plus session affinity do the work).
663
+ * `short` / `medium` / `long` — TTL hints (`5m` / `1h` / `12h`) consumed only by the opt-in `createExplicitCache` helper. Provider adapters warn about and drop any non-`implicit` retention: none of the native transports expose retention control.
667
664
 
668
665
  ### Session Affinity
669
666
 
670
667
  `sessionId` pins provider affinity using mechanisms such as:
671
668
 
672
- * `x-session-id`
673
- * `x-opencode-session`
674
- * `prompt_cache_key` (openai/openrouter/opencode only — strict endpoints such as groq reject it, so custom providers get headers only)
669
+ * `x-session-id` (+ `x-client-request-id`) headers — all providers, best effort
670
+ * top-level body `session_id` — OpenRouter (takes precedence over the header)
671
+ * `prompt_cache_key` — OpenAI only (custom endpoints get headers only; strict ones reject unknown body fields)
675
672
 
676
673
  Reuse the same session ID across turns when cache affinity is desired.
677
674
 
678
- In browser runtimes only CORS-safe attribution headers are sent; affinity
679
- still flows via `promptCacheKey` provider options, never via headers.
675
+ In browser runtimes custom `x-*` headers are stripped to avoid CORS preflights: OpenAI keeps affinity through its body key, while custom endpoints lose affinity entirely on browsers.
680
676
 
681
677
  ### Explicit Caches
682
678
 
683
- `cachedContentId` reuses a previously created Google `cachedContents/...` resource.
679
+ `createExplicitCache` mints a Google `cachedContents/...` resource directly (TTL via `retention`/`ttlSeconds`).
680
+
681
+ `cachedContentId` is accepted and carried in context, but no native adapter currently sends it — explicit references are warned about and dropped, so stable prompts plus session affinity remain the cache-reuse path.
684
682
 
685
683
  `ttlSeconds` overrides the retention mapping.
686
684
 
687
685
  ### Provider Cache Mechanisms
688
686
 
689
- * **Google** keeps system prompts and tools stable and isolates signatures.
690
- * **OpenCode / OpenRouter** use sticky session keys.
687
+ * **Google** keeps system prompts and tools stable and isolates signatures (implicit caching only).
688
+ * **OpenAI** pins affinity with `prompt_cache_key`.
689
+ * **OpenRouter** pins affinity with body `session_id` plus headers (sticky routing from the first request).
690
+ * **Custom endpoints** get headers-only affinity; anything else cache-related is warned about and dropped.
691
691
 
692
692
  The following cache helpers are exported:
693
693
 
694
- * `applyAnthropicCacheControl`
695
- * `getCacheControlForRetention`
696
694
  * `getPromptCacheRetention`
695
+ * `retentionToTtlSeconds`
697
696
  * `clampCacheKey`
698
697
 
699
698
  For the best cache reuse, keep `instructions` and the tool set stable. Put changing data in user messages or `additionalContext`.
@@ -741,6 +740,7 @@ StreamEvent {
741
740
  toolCall?,
742
741
  toolResult?,
743
742
  subagent?,
743
+ subagentTrackingId?,
744
744
  usage?,
745
745
  responseId?,
746
746
  finishReason?,
@@ -766,12 +766,13 @@ tool_call_delta
766
766
  tool_call_complete
767
767
  tool_result
768
768
  subagent_complete
769
+ subagent_delta
769
770
  usage
770
771
  done
771
772
  error
772
773
  ```
773
774
 
774
- Emitted in practice: `start`, `text_delta`, `thinking_delta`, `tool_call_complete`, `tool_result`, `subagent_complete`, `usage`, `done`, `error`. The rest exist in the type for forward compatibility.
775
+ Emitted in practice: `start`, `text_delta`, `thinking_delta`, `tool_call_complete`, `tool_result`, `subagent_complete`, `subagent_delta`, `usage`, `done`, `error`. The rest exist in the type for forward compatibility.
775
776
 
776
777
  Use:
777
778
 
@@ -779,6 +780,7 @@ Use:
779
780
  * `thinking_delta` for reasoning output.
780
781
  * `tool_call_complete` / `tool_result` for tool progress.
781
782
  * `subagent_complete` for each completed worker during streaming multi-agent runs.
783
+ * `subagent_delta` for live worker thinking/text (`subagentTrackingId` + `delta`/`thinkingDelta` + partials). Render per-worker; never merge into the parent answer.
782
784
  * `usage` for interim usage counts.
783
785
  * `done` for final usage and completion information.
784
786
 
@@ -808,8 +810,6 @@ AgentResponse {
808
810
  text,
809
811
  thinking?,
810
812
  thoughtSignature?,
811
- thinkingSignature?,
812
- textSignature?,
813
813
  toolCalls,
814
814
  toolResults,
815
815
  subagents,
@@ -850,10 +850,33 @@ SubAgentExecutionMetadata {
850
850
  toolCalls?,
851
851
  raw?,
852
852
  isError?,
853
- error?
853
+ error?,
854
+ trackingId?,
855
+ sessionId?,
856
+ parentSessionId?,
857
+ steps?
858
+ }
859
+ ```
860
+
861
+ `finishReason` is `"max_turns"` when a finite `maxTurns` limit stopped the run with tool calls still pending (plus a console warning naming the dropped tools).
862
+
863
+ ### SubAgentStep
864
+
865
+ ```ts
866
+ SubAgentStep {
867
+ turn,
868
+ type, // "assistant" | "tool_call" | "tool_result"
869
+ name?,
870
+ text?,
871
+ thinking?,
872
+ isError?,
873
+ timestamp,
874
+ partial? // true while the worker is still streaming this step
854
875
  }
855
876
  ```
856
877
 
878
+ `agent.track(id)` returns these live; `partial` entries finalize when the worker's turn completes.
879
+
857
880
  ### TokenUsage
858
881
 
859
882
  ```ts
@@ -930,8 +953,8 @@ const res = await agent.run([...]).catch(fail);
930
953
 
931
954
  Agent Accelerator features an adaptive, dynamically synchronized model catalog powered by [models.dev](https://models.dev). To avoid shipping a bloated 4.4 MB static JSON file with production builds, the SDK employs a high-performance **12-hour TTL local caching architecture**:
932
955
 
933
- - **Automated 12-Hour Cache Validation**: When `.run()`, `.ask()`, or `.stream()` executes, the runtime checks `src/data/models-cache.json`. If the cache timestamp is within 12 hours, it reads from disk with zero network delay. When the TTL expires, it transparently synchronizes with `https://models.dev/api.json`.
934
- - **Git & Package Safety**: The dynamic cache file (`src/data/models-cache.json`) is gitignored and excluded from production packages.
956
+ - **Automated 12-Hour Cache Validation**: When `.run()`, `.ask()`, or `.stream()` executes, the runtime checks `src/data/models.dev.json`. If the cache timestamp is within 12 hours, it reads from disk with zero network delay. When the TTL expires, it transparently synchronizes with `https://models.dev/api.json`.
957
+ - **Git & Package Safety**: The dynamic cache file (`src/data/models.dev.json`) is gitignored and excluded from production packages.
935
958
 
936
959
  ### Developer Catalog Controls
937
960
 
@@ -958,9 +981,9 @@ console.log(status.modelCount, status.providerCount, status.isExpired);
958
981
  ### CLI Refresh
959
982
 
960
983
  ```bash
961
- bun run update-models # Refresh model catalog (force or expired)
962
- bun scripts/update-models.ts --force # Force re-download
963
- bun scripts/update-models.ts --ttl=24h # Refresh with custom TTL
984
+ bun run update-models # Refresh model catalog (force or expired)
985
+ bun src/update-models.ts --force # Force re-download
986
+ bun src/update-models.ts --ttl=24h # Refresh with custom TTL
964
987
  ```
965
988
 
966
989
  Upstream data lags on some inputs (e.g. `gpt-4o` accepts audio). Record
@@ -1025,15 +1048,8 @@ ModelCapabilities {
1025
1048
  }
1026
1049
  ```
1027
1050
 
1028
- When estimated input exceeds the available context budget, `Agent` trims the oldest middle history using:
1029
-
1030
- ```text
1031
- context * 0.9 - maxOutput
1032
- ```
1033
-
1034
- The beginning of the conversation and the most recent tail are preserved.
1035
-
1036
1051
  ---
1052
+
1037
1053
  ## Messages and Media
1038
1054
 
1039
1055
  ### Message
@@ -1092,7 +1108,7 @@ Supported content parts include:
1092
1108
 
1093
1109
  `inferMimeType(path)` infers the MIME type from a file extension.
1094
1110
 
1095
- Media normalization is handled automatically by providers (mapped to Vercel V4 `file` parts). Thinking traces are echoed in follow-up turns only where accepted — strict endpoints receive tool calls without `reasoning_content`.
1111
+ Media normalization is handled automatically by providers (mapped to provider-native media shapes). Thinking traces are echoed in follow-up turns only where accepted — strict endpoints receive tool calls without `reasoning_content`.
1096
1112
 
1097
1113
  Provider matrix: text + image + wav/mp3 audio + PDF work on all supported
1098
1114
  providers. Video works on Gemini only.
@@ -1106,40 +1122,31 @@ its verdict surfaces as a concise error (see [Errors](#errors)). Verified
1106
1122
  catalog corrections live in `MODALITY_OVERRIDES` (`src/models/catalog.ts`),
1107
1123
  never in the gitignored snapshot.
1108
1124
 
1109
- ---
1110
- ## Tokens
1111
-
1112
- Token counting is heuristic only.
1113
-
1114
- Actual billing information comes from `res.usage`.
1115
-
1116
- Available helpers:
1117
-
1118
- * `countTokens(string | Message[] | ProviderContext)` — useful for preflight sizing and history trimming.
1119
- * `estimateTokensFromText(text)`
1120
- * `estimateTokensFromMessage(msg)`
1121
- * `estimateTokensFromPart(part)`
1122
-
1123
1125
  ---
1124
1126
  ## Utils
1125
1127
 
1126
1128
  * `createSessionId(prefix="accel")` — creates a UUID-based session ID clamped to 64 characters for affinity.
1129
+ * `createTrackingId()` — system-generated 32-char TrackingID for one sub-agent worker (`NAME-{TrackingID}`).
1130
+ * `createChildSessionId(parentId, tag)` / `createFixedChildSessionId(parentId, name)` / `isSessionDescendant(child, parent)` — provider-safe (≤64 chars) child session IDs with parent-hash lineage.
1127
1131
  * `getEnv(key, fallback?)` — resolves an environment variable.
1128
1132
  * `getApiKey(provider, explicit?, env?)` — resolves API keys using the configured environment lookup order.
1129
1133
  * `buildSessionHeaders(provider, cache?, custom?, sessionId?)` — builds provider-specific affinity headers. Normally handled automatically.
1134
+ * `withRetries(fn, { maxRetries?, maxRetryDelayMs?, signal?, label? })` / `isTransientError(err)` — bounded retries for transient provider failures (defaults: 2 retries, 5s cap, aborts never retried).
1135
+ * `convertDocumentToMarkdown(input, { filename?, format?, mimeType?, maxChars? })` — converts PDF/Word/PowerPoint/Excel/OpenDocument/RTF/EPUB/CSV to Markdown via the optional `@firecrawl/anydoc` peer. Throws `DocumentConversionError` on failure.
1136
+ * `convert_document_to_markdown` — built-in model-callable version of the above (returns a `<Document>` envelope); auto-registered with `bypassInputFileModality: true`.
1130
1137
  * `z` — re-exported from Zod so tools do not require a separate Zod import.
1131
1138
 
1132
1139
  ---
1133
1140
  ## Examples
1134
1141
 
1135
1142
  ```bash
1136
- bun run examples/06-chat.ts
1143
+ bun run examples/05-chat.ts
1137
1144
  # persistent CLI, /model "..." /level <lvl> /help /exit
1138
1145
 
1139
- bun run examples/05-sub-agents.ts
1146
+ bun run examples/04-sub-agents.ts
1140
1147
  # fixed researcher + critic pipeline
1141
1148
 
1142
- bun run examples/04-multi_agent.ts
1149
+ bun run examples/03-multi_agent.ts
1143
1150
  # dynamic spawn_subagents demo
1144
1151
 
1145
1152
  bun run examples/01-metadata.ts
@@ -1148,17 +1155,23 @@ bun run examples/01-metadata.ts
1148
1155
  bun run examples/02-function_calling.ts
1149
1156
  # single tool call
1150
1157
 
1151
- bun run examples/03-multimodal_image.ts [./photo.png]
1158
+ bun run examples/06-multimodal_image.ts [./photo.png]
1152
1159
  # image input (remote URL default, local path optional)
1153
1160
 
1154
1161
  bun run examples/07-multimodal_audio.ts
1155
1162
  # audio input
1156
1163
 
1157
- bun run examples/08-multimodal_document.ts
1164
+ bun run examples/09-multimodal_document.ts
1158
1165
  # PDF/file input
1159
1166
 
1160
- bun run examples/09-multimodal_video.ts
1167
+ bun run examples/08-multimodal_video.ts
1161
1168
  # video input (video-capable model required)
1169
+
1170
+ bun run examples/10-document_markdown.ts
1171
+ # document → Markdown preprocessing (any model, optional @firecrawl/anydoc peer)
1172
+
1173
+ bun run examples/11-session-identity.ts
1174
+ # sub-agent TrackingIDs, live worker boxes, lineage, track(), durable sessions
1162
1175
  ```
1163
1176
 
1164
1177
  Every example ends its `run()` with `.catch(fail)` (`examples/_shared.ts`),
@@ -1167,17 +1180,54 @@ so failures print one line and exit `1` — no stack dumps.
1167
1180
  The chat example persists conversations to:
1168
1181
 
1169
1182
  ```text
1170
- .session.jsonl
1183
+ sessions/<sessionId>/session.json (+ media/ for images, audio, video, files)
1171
1184
  ```
1172
1185
 
1173
- It resumes from that file on next launch.
1186
+ It resumes the most recent session on next launch (legacy `.session.json`/`.session.jsonl` files still load) and prints a resume banner:
1187
+
1188
+ ```text
1189
+ ↺ Previous session loaded • accel-1a2b… (.session.json) • 12 messages • google/gemini-3.5-flash-lite • total-CH82.4% • $0.013 total
1190
+ ```
1174
1191
 
1175
- It also displays per-turn:
1192
+ It also displays per-turn and session totals on one line:
1176
1193
 
1177
1194
  ```text
1178
- input / output / cached / cost / context %
1195
+ ↑turn ↓turn CRturn turn-CH% | ↑total ↓total CRtotal total-CH% $total(+turn) ctx%/window
1196
+ ```
1197
+
1198
+ ### Session persistence
1199
+
1200
+ ```ts
1201
+ import {
1202
+ Agent,
1203
+ loadSessionFile,
1204
+ saveSessionFile,
1205
+ SessionTelemetry,
1206
+ formatSessionBanner,
1207
+ } from "agent-accelerator";
1208
+
1209
+ const saved = loadSessionFile(".session.json");
1210
+ const telemetry = SessionTelemetry.fromSaved(saved);
1211
+
1212
+ const agent = new Agent({
1213
+ model: saved?.model ?? process.env.MODEL,
1214
+ sessionId: saved?.sessionId,
1215
+ });
1216
+
1217
+ if (saved) agent.importSession(saved);
1218
+
1219
+ const res = await agent.run("Hello");
1220
+ telemetry.add(res.usage, agent.modelStringOrSpec as string);
1221
+ saveSessionFile(".session.json", agent, telemetry);
1179
1222
  ```
1180
1223
 
1224
+ * `agent.exportSession(telemetry)` / `agent.importSession(saved)` round-trip messages, system prompt, model, thinking level, instructions, cache, worker model, and sub-agent traces without touching `AgentContext` internals.
1225
+ * `SessionTelemetry` accumulates `input / output / cacheRead / cacheWrite / reasoning / cost`, with clamped `turnHitRate()` / `totalHitRate()`, a dual `formatBar(res)`, and `formatSessionBanner(saved, telemetry, path)` for startup.
1226
+ * Files are pretty-printed JSON (2-space indent), written atomically (temp + rename). Cost prefers provider-reported totals and falls back to catalog pricing.
1227
+ * Binary media (bytes, data URLs, base64) is extracted to `media/` on save via `saveSessionDir("sessions", agent, telemetry)` → `sessions/<sessionId>/{session.json, media/*}`; remote URLs and local paths stay references. `loadSessionDir(dir)` resolves `media/…` refs back to absolute paths, and `findLatestSessionDir("sessions")` resumes the most recent session.
1228
+ * Sub-agent traces persist in a dedicated `subagents` section keyed by TrackingID (`{ trackingId, name, sessionId, parentSessionId, status, task, turns, usage, steps, text }`). Files stay lean: redundant `rawArguments` and repeated step text are dropped on save (rebuilt/kept live in memory).
1229
+ * With `persist: { dir }` or `{ file }`, the session file is rewritten after every step, so a crash loses at most the in-flight step.
1230
+
1181
1231
  ---
1182
1232
  ## Scripts and Structure
1183
1233
 
@@ -1193,20 +1243,21 @@ bun run update-models # refresh model catalog cache (supports --force, --ttl=24h
1193
1243
  ```text
1194
1244
  src/
1195
1245
  ├── agent/ # Agent, context, loop, delegation, subagent
1196
- ├── ai-sdk/ # Provider backend: provider factories, converters, executor, registry
1246
+ ├── session/ # Session persistence + telemetry (snapshots, hit rates, .session.json store)
1247
+ ├── providers/ # native REST adapters (google/openai/openrouter/openai-compat) + registry + canonical contract
1197
1248
  ├── models/ # Dynamic catalog cache, parser, verified overrides
1198
1249
  ├── data/ # Dynamic model catalog cache (gitignored, excluded from bundle)
1199
1250
  ├── tools/ # tool(), schema, executor
1200
1251
  ├── streaming/ # event stream, SSE parser
1201
- ├── tokens/ # estimator
1202
1252
  ├── types/ # agent, core, message, model, response, tool
1203
- └── utils/ # base64, cache, env, headers, media, serialization, session
1253
+ └── utils/ # base64, cache, env, headers, media, serialization, session, thought-signature, documents, retry, errors
1204
1254
  examples/
1205
- ├── 01-metadata.ts 02-function_calling.ts 03-multimodal_image.ts
1206
- ├── 04-multi_agent.ts 05-sub-agents.ts 06-chat.ts
1207
- ├── 07-multimodal_audio.ts 08-multimodal_document.ts
1208
- ├── 09-multimodal_video.ts _shared.ts
1209
- test/ # 105 tests mirroring the above
1255
+ ├── 01-metadata.ts 02-function_calling.ts 03-multi_agent.ts
1256
+ ├── 04-sub-agents.ts 05-chat.ts 06-multimodal_image.ts
1257
+ ├── 07-multimodal_audio.ts 08-multimodal_video.ts
1258
+ ├── 09-multimodal_document.ts 10-document_markdown.ts
1259
+ ├── files/ prompts/ research-agent.ts _shared.ts
1260
+ test/ # unit + mocked-provider tests mirroring src/
1210
1261
  ```
1211
1262
 
1212
1263
  ---
@@ -5,7 +5,7 @@ You are an Agent — you evaluate user objectives and decide whether to solve th
5
5
  - Single-focus, factual, code-generation, or conversational prompts → Answer directly, concisely, and completely.
6
6
  - Do NOT spawn sub-agents for trivial, single-step tasks.
7
7
  2. **Delegate**:
8
- - Complex research, multi-angle analysis, deep technical trade-offs, or parallel explorations → Invoke `spawn_subagents` with 2 to 5 focused sub-agents in a single batched call.
8
+ - Complex research, multi-angle analysis, deep technical trade-offs, or parallel explorations → Invoke `spawn_subagents` with 2 to 4 focused sub-agents in a single batched call.
9
9
  - For each sub-agent define:
10
10
  - `name`: `UPPER_SNAKE_CASE` identifier describing domain focus (e.g., `MARKET_ANALYST`, `SYSTEMS_ARCHITECT`).
11
11
  - `role`: Distinct specialized persona.