agent-accelerator 0.5.0 → 0.5.2
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 +66 -59
- package/package.json +7 -14
- package/src/agent/agent.ts +14 -49
- package/src/agent/context.ts +5 -4
- package/src/agent/delegation.ts +1 -9
- package/src/agent/loop.ts +22 -84
- package/src/agent/subagent.ts +1 -2
- package/src/agent/worker.ts +3 -6
- package/src/index.ts +6 -41
- package/src/providers/google.ts +390 -154
- package/src/providers/openai-compat.ts +12 -27
- package/src/providers/openai.ts +13 -35
- package/src/providers/openrouter.ts +11 -29
- package/src/providers.ts +32 -124
- package/src/session/store.ts +18 -29
- package/src/types/agent.ts +10 -15
- package/src/types/core.ts +5 -32
- package/src/types/message.ts +15 -1
- package/src/types/model.ts +7 -3
- package/src/types/response.ts +5 -0
- package/src/utils/cache.ts +1 -137
- package/src/utils/errors.ts +1 -4
- package/src/utils/headers.ts +3 -19
- package/src/utils/retry.ts +2 -1
- package/src/utils/safe-io.ts +2 -2
- package/src/utils/documents.ts +0 -577
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ import { Agent } from "agent-accelerator";
|
|
|
17
17
|
const agent = new Agent({
|
|
18
18
|
model: "google/gemini-3.5-flash-lite",
|
|
19
19
|
instructions: "You are a concise research engineer.",
|
|
20
|
-
cache:
|
|
20
|
+
cache: "implicit",
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
const res = await agent.run("Explain HBM pricing in 3 bullets");
|
|
@@ -32,10 +32,10 @@ console.log(res.usage);
|
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
34
|
# Bun (recommended)
|
|
35
|
-
bun add agent-accelerator
|
|
35
|
+
bun add agent-accelerator zod
|
|
36
36
|
|
|
37
37
|
# npm
|
|
38
|
-
npm install agent-accelerator
|
|
38
|
+
npm install agent-accelerator zod
|
|
39
39
|
|
|
40
40
|
# pnpm
|
|
41
41
|
pnpm add agent-accelerator
|
|
@@ -46,7 +46,7 @@ yarn add agent-accelerator
|
|
|
46
46
|
|
|
47
47
|
Requires `bun` or `node 22+`.
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
The only dependency is `zod` (a peer dependency: install it next to the SDK and import `z` from `"zod"`). All provider transports are native REST (`fetch`, no SDK).
|
|
50
50
|
|
|
51
51
|
---
|
|
52
52
|
|
|
@@ -123,9 +123,8 @@ An `Agent` holds:
|
|
|
123
123
|
| `subagentModel` | `string \| ModelSpec \| ModelProviderInstance` | Developer-only model for dynamically spawned workers. Never choosable by the Main Agent. Deprecated alias of `dynamicSubagents.model` (which wins). Falls back to `SUB_AGENT_MODEL`. |
|
|
124
124
|
| `dynamicSubagents` | `DynamicSubagentsConfig` | Enables and constrains LLM-spawned stateless workers: `{ enabled, model?, maxSpawn?, thinkingLevel?, tools?, timeout?, allowScheduledActions? }`. See [Pre-defined vs Dynamic Delegation](#pre-defined-vs-dynamic-delegation) and [Scheduled actions](#scheduled-actions). |
|
|
125
125
|
| `thinking` | `ThinkingOption` | Canonical reasoning option: `none \| dynamic \| minimal \| low \| medium \| high \| xhigh \| max`, or `{ level, budgetTokens }`. Legacy `thinkingLevel` still works (canonical wins). Validated against the model catalog before a request. |
|
|
126
|
-
| `cache` | `
|
|
126
|
+
| `cache` | `CacheOption` | `"implicit" \| "5m" \| "30m" \| "1h" \| "12h"`. Prompt-cache lifetime; unsupported values warn and fall back (see [Cache](#cache)). |
|
|
127
127
|
| `serviceTier` | `"flex" \| "priority"` | Cost / priority routing where supported. Omit for standard routing. |
|
|
128
|
-
| `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`. |
|
|
129
128
|
| `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"`. |
|
|
130
129
|
| `sessionId` | `string` | Stable identifier used for cache affinity. Auto-generated when omitted. |
|
|
131
130
|
| `headers` | `Record<string,string>` | Additional headers merged into every request. |
|
|
@@ -239,7 +238,6 @@ const lead = new Agent({
|
|
|
239
238
|
### Differences from Agent
|
|
240
239
|
|
|
241
240
|
* `model` resolves as `config.model ?? SUB_AGENT_MODEL ?? MODEL` and throws if empty.
|
|
242
|
-
* `cache` defaults to `{ retention: "short" }`.
|
|
243
241
|
* `.asTool(name?, desc?)` / `.toTool(name?, desc?)` converts the subagent into a `ToolDefinition` for manual registration.
|
|
244
242
|
* `stateless: true` is supported for one-shot judges that must not retain history.
|
|
245
243
|
|
|
@@ -378,7 +376,8 @@ telemetryBus.onEvent((e) => {
|
|
|
378
376
|
## Tools
|
|
379
377
|
|
|
380
378
|
```ts
|
|
381
|
-
import { Agent, tool
|
|
379
|
+
import { Agent, tool } from "agent-accelerator";
|
|
380
|
+
import { z } from "zod";
|
|
382
381
|
|
|
383
382
|
const agent = new Agent({
|
|
384
383
|
model: "google/gemini-3.5-flash-lite",
|
|
@@ -404,7 +403,6 @@ const agent = new Agent({
|
|
|
404
403
|
* `zodToJsonSchema(schema)` — converts Zod schemas using native conversion with a fallback extractor.
|
|
405
404
|
* `cleanJsonSchema(schema)` — removes `$schema`, `$defs`, and `definitions`, resolves `$ref`, and preserves explicit `additionalProperties`.
|
|
406
405
|
* `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.
|
|
407
|
-
* `convert_document_to_markdown` — built-in, model-callable version of `convertDocumentToMarkdown` (PDF/Word/PowerPoint/Excel/OpenDocument/RTF/EPUB/CSV, local path or URL) for models without native document parsing. Returns a `<Document>` envelope, is auto-registered with `bypassInputFileModality: true`, and requires the optional `@firecrawl/anydoc` peer.
|
|
408
406
|
|
|
409
407
|
The agent loop answers the 3rd consecutive identical call (same name and arguments) with a `repeat_blocked` error, so the model can reuse the prior result or change its arguments. Tools marked `repeatable: true`, or `idempotent: true` unless `repeatable` is set, are exempt.
|
|
410
408
|
|
|
@@ -522,6 +520,24 @@ Model resolution never silently selects a default model: an empty model throws.
|
|
|
522
520
|
|
|
523
521
|
An unknown prefix with no catalog match still routes to a custom provider, allowing private model IDs and endpoints.
|
|
524
522
|
|
|
523
|
+
### Google long decode (Gemini 4)
|
|
524
|
+
|
|
525
|
+
Google caps one request at 65,536 output tokens. Set `maxOutputTokens` above
|
|
526
|
+
that on a `gemini-4-*` model and the SDK runs the request as a background
|
|
527
|
+
interaction automatically (no extra option): up to 1,048,576 tokens minus the
|
|
528
|
+
input, for up to 24 hours. `run()` polls until it finishes (2 s, then every
|
|
529
|
+
5 s); `stream()` reconnects after a dropped or silent connection
|
|
530
|
+
(`last_event_id`, 15 min of silence counts as dropped). Aborting cancels the
|
|
531
|
+
interaction on Google's side, so it stops billing. Each HTTP request is still
|
|
532
|
+
timed by `limits.requestTimeoutMs`, but the whole run is not. Any other Google
|
|
533
|
+
model with `maxOutputTokens` above 65,536 fails before the network with a
|
|
534
|
+
`ConfigError`. Use it for hard reasoning, not chat: you pay for every token of
|
|
535
|
+
every 64K hop.
|
|
536
|
+
|
|
537
|
+
A custom `Provider` can opt into the same treatment with the optional
|
|
538
|
+
`isLongRunning(model, options)` method: when it returns `true`, the loop skips
|
|
539
|
+
its whole-call, first-byte and idle timers and leaves timing to the adapter.
|
|
540
|
+
|
|
525
541
|
### Registry
|
|
526
542
|
|
|
527
543
|
* `resolveModel("google/x" | ModelSpec)` → `{ provider, modelId, modelSpec? }`. Use to inspect routing before execution.
|
|
@@ -587,11 +603,10 @@ Google-specific handling includes:
|
|
|
587
603
|
|
|
588
604
|
* Isolating `thoughtSignature` per part for prefix stability.
|
|
589
605
|
* Converting JSON Schema to OpenAPI 3.0 through `stripSchemaForGoogle`.
|
|
590
|
-
* Implicit
|
|
606
|
+
* Implicit caching only; other `cache` values warn and fall back (see [Cache](#cache)).
|
|
591
607
|
|
|
592
608
|
Helpers:
|
|
593
609
|
|
|
594
|
-
* `createExplicitCache({ model, systemInstruction?, contents?, tools?, displayName?, ttlSeconds?, expireTime?, apiKey?, baseUrl? })`
|
|
595
610
|
* `isValidThoughtSignature(sig)`
|
|
596
611
|
* `retainThoughtSignature(existing, incoming)`
|
|
597
612
|
* `extractGoogleThoughtSignature(obj)`
|
|
@@ -724,26 +739,20 @@ Fixed-reasoning models reject `none`.
|
|
|
724
739
|
## Cache
|
|
725
740
|
|
|
726
741
|
```ts
|
|
727
|
-
|
|
728
|
-
retention?,
|
|
729
|
-
cachedContentId?,
|
|
730
|
-
sessionId?,
|
|
731
|
-
ttlSeconds?
|
|
732
|
-
}
|
|
742
|
+
cache?: "implicit" | "5m" | "30m" | "1h" | "12h" // CacheOption; omit for the provider default
|
|
733
743
|
```
|
|
734
744
|
|
|
735
|
-
|
|
736
|
-
CacheRetention =
|
|
737
|
-
| "implicit"
|
|
738
|
-
| "short"
|
|
739
|
-
| "medium"
|
|
740
|
-
| "long";
|
|
741
|
-
```
|
|
745
|
+
One value sets the prompt-cache lifetime. Each provider honours only the values it supports; any other value falls back to the provider default and emits one `provider_warning` naming the supported values.
|
|
742
746
|
|
|
743
|
-
|
|
747
|
+
| Provider | Supported | Sent on the wire |
|
|
748
|
+
| --- | --- | --- |
|
|
749
|
+
| Google (Interactions) | `implicit` | nothing (implicit caching is always on) |
|
|
750
|
+
| OpenRouter, `anthropic/*` models | `implicit`, `5m`, `1h` | top-level `cache_control: { type: "ephemeral", ttl }` |
|
|
751
|
+
| OpenRouter, other models | `implicit` | nothing (automatic caching + sticky routing) |
|
|
752
|
+
| OpenAI | `implicit`, `12h` | `12h` sends `prompt_cache_retention: "24h"` when the catalog allows long retention |
|
|
753
|
+
| Custom endpoints | `implicit` | nothing (strict endpoints reject unknown fields) |
|
|
744
754
|
|
|
745
|
-
|
|
746
|
-
* `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.
|
|
755
|
+
Session files written before 0.5.1 with the old `{ retention }` object still load (`short`=`5m`, `medium`=`1h`, `long`=`12h`). Passing the object form to `new Agent()` throws `ConfigError`.
|
|
747
756
|
|
|
748
757
|
### Session Affinity
|
|
749
758
|
|
|
@@ -757,26 +766,7 @@ Reuse the same session ID across turns when cache affinity is desired.
|
|
|
757
766
|
|
|
758
767
|
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.
|
|
759
768
|
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
`createExplicitCache` mints a Google `cachedContents/...` resource directly (TTL via `retention`/`ttlSeconds`).
|
|
763
|
-
|
|
764
|
-
`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.
|
|
765
|
-
|
|
766
|
-
`ttlSeconds` overrides the retention mapping.
|
|
767
|
-
|
|
768
|
-
### Provider Cache Mechanisms
|
|
769
|
-
|
|
770
|
-
* **Google** keeps system prompts and tools stable and isolates signatures (implicit caching only).
|
|
771
|
-
* **OpenAI** pins affinity with `prompt_cache_key`.
|
|
772
|
-
* **OpenRouter** pins affinity with body `session_id` plus headers (sticky routing from the first request).
|
|
773
|
-
* **Custom endpoints** get headers-only affinity; anything else cache-related is warned about and dropped.
|
|
774
|
-
|
|
775
|
-
The following cache helpers are exported:
|
|
776
|
-
|
|
777
|
-
* `getPromptCacheRetention`
|
|
778
|
-
* `retentionToTtlSeconds`
|
|
779
|
-
* `clampCacheKey`
|
|
769
|
+
`clampCacheKey` (exported) shortens affinity keys to the provider-safe 64 characters.
|
|
780
770
|
|
|
781
771
|
For the best cache reuse, keep `instructions` and the tool set stable. Put changing data in user messages or `additionalContext`.
|
|
782
772
|
|
|
@@ -1146,18 +1136,26 @@ Message {
|
|
|
1146
1136
|
role: "system" | "user" | "assistant" | "tool",
|
|
1147
1137
|
content: string | ContentPart[],
|
|
1148
1138
|
name?,
|
|
1149
|
-
thoughtSignature
|
|
1139
|
+
thoughtSignature?,
|
|
1140
|
+
providerSteps? // { provider, steps }: raw output steps of an assistant turn
|
|
1150
1141
|
}
|
|
1151
1142
|
```
|
|
1152
1143
|
|
|
1144
|
+
`providerSteps` keeps a provider's raw output for one assistant turn (today:
|
|
1145
|
+
Google's `steps`, including thought signatures). When Google needs the full
|
|
1146
|
+
history again (after a restart, an expired chain or a provider switch), those
|
|
1147
|
+
turns are resent exactly as received, which keeps reasoning continuity and
|
|
1148
|
+
the implicit-cache prefix intact. Other providers ignore it. Adapters return
|
|
1149
|
+
it on `ProviderGenerateResult` / per-turn stream `AgentResponse`; it is never
|
|
1150
|
+
part of `toJSON()`.
|
|
1151
|
+
|
|
1153
1152
|
### ProviderContext
|
|
1154
1153
|
|
|
1155
1154
|
```ts
|
|
1156
1155
|
ProviderContext {
|
|
1157
1156
|
systemPrompt?,
|
|
1158
1157
|
messages,
|
|
1159
|
-
tools
|
|
1160
|
-
cachedContentId?
|
|
1158
|
+
tools?
|
|
1161
1159
|
}
|
|
1162
1160
|
```
|
|
1163
1161
|
|
|
@@ -1169,9 +1167,9 @@ Supported content parts include:
|
|
|
1169
1167
|
* `ThinkingPart { type:"thinking", thinking, thoughtSignature? }` — preserved reasoning.
|
|
1170
1168
|
* `ToolCallPart { type:"tool_call", id, name, arguments, rawArguments?, thoughtSignature? }`
|
|
1171
1169
|
* `ToolResultPart { type:"tool_result", id, name, result, isError? }`
|
|
1172
|
-
* `ImagePart { type:"image", image, mimeType? }`
|
|
1170
|
+
* `ImagePart { type:"image", image, mimeType?, resolution? }`
|
|
1173
1171
|
* `AudioPart { type:"audio", audio, mimeType? }`
|
|
1174
|
-
* `VideoPart { type:"video", video, mimeType? }`
|
|
1172
|
+
* `VideoPart { type:"video", video, mimeType?, resolution? }`
|
|
1175
1173
|
* `FilePart { type:"file", file, mimeType?, filename? }` — PDFs/documents.
|
|
1176
1174
|
|
|
1177
1175
|
`image`, `audio`, `video`, and `file` inputs accept:
|
|
@@ -1200,6 +1198,20 @@ Media normalization is handled automatically by providers (mapped to provider-na
|
|
|
1200
1198
|
Provider matrix: text + image + wav/mp3 audio + PDF work on all supported
|
|
1201
1199
|
providers. Video works on Gemini only.
|
|
1202
1200
|
|
|
1201
|
+
On Google, links Google fetches itself go as a `uri` without downloading:
|
|
1202
|
+
YouTube links, Files API links, `gs://` objects and public `https://` URLs of
|
|
1203
|
+
URL-supported types (PDF, CSV, text, JSON, PNG/JPEG/WebP/BMP, common video;
|
|
1204
|
+
max 15 MB). Audio URLs and `http://` links are downloaded and inlined. Inline
|
|
1205
|
+
types are checked before the network; Google reads only PDF and CSV
|
|
1206
|
+
documents. The supported lists are the `GOOGLE_*_MIME` constants at the top of
|
|
1207
|
+
`src/providers/google.ts`.
|
|
1208
|
+
|
|
1209
|
+
`resolution` (`MediaResolution`: `"low" | "medium" | "high" | "ultra_high"`)
|
|
1210
|
+
sets how much detail Google spends on one image or video, and so how many
|
|
1211
|
+
input tokens it costs (image: 280 / 560 / 1120 / 2240; video per frame:
|
|
1212
|
+
`low` and `medium` 70, `high` 280). Omit it for Google's default. Other
|
|
1213
|
+
providers ignore it with one `provider_warning`.
|
|
1214
|
+
|
|
1203
1215
|
Before any network call, the executor checks `image` / `audio` / `video` /
|
|
1204
1216
|
`file`-as-PDF parts against the catalog's `modalities.input` for that
|
|
1205
1217
|
provider/model and fails fast with a one-line error naming the gap
|
|
@@ -1219,8 +1231,6 @@ never in the gitignored snapshot.
|
|
|
1219
1231
|
* `getApiKey(provider, explicit?, env?)` — resolves API keys using the configured environment lookup order.
|
|
1220
1232
|
* `buildSessionHeaders(provider, cache?, custom?, sessionId?)` — builds provider-specific affinity headers. Normally handled automatically.
|
|
1221
1233
|
* `withRetries(fn, { maxRetries?, maxRetryDelayMs?, signal?, label? })` / `isTransientError(err)` — bounded retries for transient provider failures (defaults: 2 retries, 5s cap, aborts never retried).
|
|
1222
|
-
* `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.
|
|
1223
|
-
* `z` — re-exported from Zod so tools do not require a separate Zod import.
|
|
1224
1234
|
|
|
1225
1235
|
---
|
|
1226
1236
|
## Examples
|
|
@@ -1253,9 +1263,6 @@ bun run examples/09-multimodal_document.ts
|
|
|
1253
1263
|
bun run examples/08-multimodal_video.ts
|
|
1254
1264
|
# video input (video-capable model required)
|
|
1255
1265
|
|
|
1256
|
-
bun run examples/10-document_markdown.ts
|
|
1257
|
-
# document → Markdown preprocessing (any model, optional @firecrawl/anydoc peer)
|
|
1258
|
-
|
|
1259
1266
|
bun run examples/11-session-identity.ts
|
|
1260
1267
|
# sub-agent TrackingIDs, live worker boxes, lineage, track(), durable sessions
|
|
1261
1268
|
|
|
@@ -1319,7 +1326,7 @@ saveSessionFile(".session.json", agent, telemetry);
|
|
|
1319
1326
|
|
|
1320
1327
|
* `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.
|
|
1321
1328
|
* `SessionTelemetry` accumulates `input / output / cacheRead / cacheWrite / reasoning / cost`, with clamped `turnHitRate()` / `totalHitRate()`, a dual `formatBar(res)`, and `formatSessionBanner(saved, telemetry, path)` for startup. Cost follows the [TokenUsage](#response-usage-and-raw-data) rules.
|
|
1322
|
-
* Files are JSON with one line per top-level field and one line per turn (2-space indent), written atomically (temp + rename).
|
|
1329
|
+
* Files are JSON with one line per top-level field and one line per turn (2-space indent), written atomically (temp + rename). Google turns also store their raw `providerSteps`, so a resumed session replays them exactly.
|
|
1323
1330
|
* 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.
|
|
1324
1331
|
* 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).
|
|
1325
1332
|
* With `persist: { dir }` or `{ file }`, the session file is rewritten after every step, so a crash loses at most the in-flight step.
|
|
@@ -1347,7 +1354,7 @@ src/
|
|
|
1347
1354
|
├── tools/ # tool(), schema, executor
|
|
1348
1355
|
├── streaming/ # event stream, SSE parser
|
|
1349
1356
|
├── types/ # agent, core, message, model, response, tool
|
|
1350
|
-
└── utils/ # base64, cache, env, headers, media, serialization, session, thought-signature,
|
|
1357
|
+
└── utils/ # base64, cache, env, headers, media, serialization, session, thought-signature, retry, errors
|
|
1351
1358
|
examples/ # live demos 01-14 (see Examples), plus files/, prompts/, research-agent.ts, _shared.ts
|
|
1352
1359
|
test/ # unit + mocked-provider tests mirroring src/
|
|
1353
1360
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-accelerator",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "High-performance SDK for AI agents with a unified API across AI providers. Optimized for high cache hit rates, observability, and seamless agent orchestration. Built to power production-grade agentic systems and harnesses for teams at any scale.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Sashvat Bharat",
|
|
@@ -42,22 +42,15 @@
|
|
|
42
42
|
"scripts": {
|
|
43
43
|
"typecheck": "tsc --noEmit",
|
|
44
44
|
"test": "bun test test/",
|
|
45
|
-
"update-models": "bun src/update-models.ts"
|
|
46
|
-
|
|
47
|
-
"devDependencies": {
|
|
48
|
-
"@firecrawl/anydoc": "^0.2.4",
|
|
49
|
-
"@types/bun": "latest",
|
|
50
|
-
"typescript": "^7.0.0"
|
|
45
|
+
"update-models": "bun src/update-models.ts",
|
|
46
|
+
"fetch-latest-provider-docs": "bun references/documentations/fetch-latest.ts"
|
|
51
47
|
},
|
|
52
48
|
"peerDependencies": {
|
|
53
|
-
"
|
|
54
|
-
},
|
|
55
|
-
"peerDependenciesMeta": {
|
|
56
|
-
"@firecrawl/anydoc": {
|
|
57
|
-
"optional": true
|
|
58
|
-
}
|
|
49
|
+
"zod": "^4.4.3"
|
|
59
50
|
},
|
|
60
|
-
"
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@types/bun": "latest",
|
|
53
|
+
"typescript": "^7.0.0",
|
|
61
54
|
"zod": "^4.4.3"
|
|
62
55
|
}
|
|
63
56
|
}
|
package/src/agent/agent.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { TokenUsage } from "../types/core.ts";
|
|
|
3
3
|
import type { ProviderRequestOptions } from "../types/model.ts";
|
|
4
4
|
import { normalizeThinkingV2, resolveWhenBusy, normalizeWorkerTimeout } from "../tools/tool.ts";
|
|
5
5
|
import type { ToolDefinition } from "../types/tool.ts";
|
|
6
|
-
import type
|
|
6
|
+
import { CACHE_OPTIONS, type ThinkingLevel, type ThinkingConfig, type CacheOption, type ServiceTier } from "../types/core.ts";
|
|
7
7
|
import type { ContentPart } from "../types/message.ts";
|
|
8
8
|
import { AgentResponse, type StreamEvent } from "../types/response.ts";
|
|
9
9
|
import { AssistantMessageEventStream } from "../streaming/event-stream.ts";
|
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
resolveMainModel,
|
|
17
17
|
} from "./worker.ts";
|
|
18
18
|
import * as path from "node:path";
|
|
19
|
-
import { createConvertDocumentTool } from "../utils/documents.ts";
|
|
20
19
|
import { registerAgent } from "../scheduler/scheduler.ts";
|
|
21
20
|
import { resolveHome } from "../scheduler/store.ts";
|
|
22
21
|
import { persistTelemetry } from "../telemetry-file.ts";
|
|
@@ -171,17 +170,13 @@ export class Agent {
|
|
|
171
170
|
readonly output?: unknown;
|
|
172
171
|
/** Normalized structured-output spec sent to providers. */
|
|
173
172
|
readonly outputSpec?: StructuredOutputSpec;
|
|
174
|
-
/**
|
|
175
|
-
readonly
|
|
173
|
+
/** Prompt-cache lifetime (see `AgentConfig.cache`); unset = provider default. */
|
|
174
|
+
readonly cache?: CacheOption;
|
|
176
175
|
/** Provider service tier. */
|
|
177
176
|
readonly serviceTier?: ServiceTier;
|
|
178
|
-
/** Convert `file` parts client-side for pdf-incapable models. */
|
|
179
|
-
readonly bypassInputFileModality: boolean;
|
|
180
177
|
/**
|
|
181
|
-
* Local-file policy. `roots` set: every local-path media part
|
|
182
|
-
*
|
|
183
|
-
* Unset: developer-supplied parts are unrestricted and the model-callable
|
|
184
|
-
* tool is limited to the working directory.
|
|
178
|
+
* Local-file policy. `roots` set: every local-path media part must resolve
|
|
179
|
+
* inside them (`[]` denies all paths). Unset: local paths are unrestricted.
|
|
185
180
|
*/
|
|
186
181
|
readonly fileAccess?: { roots?: string[] };
|
|
187
182
|
/** Failure policy for the conversation (see `AgentConfig.onFailure`). */
|
|
@@ -310,7 +305,7 @@ export class Agent {
|
|
|
310
305
|
: Number.isFinite(config.maxTurns as number)
|
|
311
306
|
? Math.max(1, Math.floor(config.maxTurns as number))
|
|
312
307
|
: Infinity;
|
|
313
|
-
this.sessionId = config.sessionId ||
|
|
308
|
+
this.sessionId = config.sessionId || createSessionId();
|
|
314
309
|
(this as any).subagentTraces = {};
|
|
315
310
|
this.home = resolveHome(config.home);
|
|
316
311
|
// `persist: {}` (neither dir nor file) means the default sessions folder under home.
|
|
@@ -346,16 +341,14 @@ export class Agent {
|
|
|
346
341
|
this.outputSpec = normalizeStructuredOutput(config.output);
|
|
347
342
|
}
|
|
348
343
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
const initialCachedId = (this.cacheConfig as any)?.cachedContentId;
|
|
344
|
+
if (config.cache !== undefined && !CACHE_OPTIONS.includes(config.cache)) {
|
|
345
|
+
throw new ConfigError(
|
|
346
|
+
`[Agent Accelerator] Invalid cache ${JSON.stringify(config.cache)}: expected one of ${CACHE_OPTIONS.map((v) => `"${v}"`).join(", ")}, or omit it for the provider default.`
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
this.cache = config.cache;
|
|
356
350
|
|
|
357
351
|
this.serviceTier = config.serviceTier;
|
|
358
|
-
this.bypassInputFileModality = config.bypassInputFileModality ?? false;
|
|
359
352
|
this.onFailure =
|
|
360
353
|
config.onFailure === "rollback" || config.onFailure === "keep" ? config.onFailure : "auto";
|
|
361
354
|
this.forkConfig = { ...config };
|
|
@@ -400,10 +393,6 @@ export class Agent {
|
|
|
400
393
|
}
|
|
401
394
|
}
|
|
402
395
|
|
|
403
|
-
if (this.bypassInputFileModality && !this.tools["convert_document_to_markdown"]) {
|
|
404
|
-
this.tools["convert_document_to_markdown"] = createConvertDocumentTool({ roots: this.fileAccess?.roots });
|
|
405
|
-
}
|
|
406
|
-
|
|
407
396
|
const dyn = this.dynamicSubagents;
|
|
408
397
|
if ((dyn?.enabled === true || dyn?.allowScheduledActions) && !this.subagentModel) {
|
|
409
398
|
throw new SubAgentModelError(
|
|
@@ -425,9 +414,6 @@ export class Agent {
|
|
|
425
414
|
assertNoToolCollisions(this.tools);
|
|
426
415
|
|
|
427
416
|
this.context = new AgentContext(this.getFullInstructions());
|
|
428
|
-
if (initialCachedId) {
|
|
429
|
-
this.context.cachedContentId = initialCachedId;
|
|
430
|
-
}
|
|
431
417
|
if (dyn?.allowScheduledActions) registerAgent(this);
|
|
432
418
|
}
|
|
433
419
|
|
|
@@ -474,7 +460,6 @@ export class Agent {
|
|
|
474
460
|
const sid = this.sessionId;
|
|
475
461
|
this.context.messages = [];
|
|
476
462
|
this.context.thoughtSignatures = [];
|
|
477
|
-
this.context.cachedContentId = (this.cacheConfig as any)?.cachedContentId;
|
|
478
463
|
this.context.systemPrompt = this.getFullInstructions();
|
|
479
464
|
// Q-25: reset also drops session-scoped provider chaining/routing.
|
|
480
465
|
try { clearInteractionChains(sid); } catch {}
|
|
@@ -533,10 +518,6 @@ export class Agent {
|
|
|
533
518
|
return existing.context;
|
|
534
519
|
}
|
|
535
520
|
const fresh = new AgentContext(this.getFullInstructions());
|
|
536
|
-
try {
|
|
537
|
-
const cached = (this.cacheConfig as unknown as { cachedContentId?: string })?.cachedContentId;
|
|
538
|
-
if (cached) fresh.cachedContentId = cached;
|
|
539
|
-
} catch {}
|
|
540
521
|
this.sessions.set(sid, { context: fresh, lastAccess: now });
|
|
541
522
|
// LRU eviction (oldest lastAccess first).
|
|
542
523
|
try {
|
|
@@ -961,9 +942,7 @@ export class Agent {
|
|
|
961
942
|
baseUrl: this.baseUrl,
|
|
962
943
|
headers: { ...(this.customHeaders ?? {}), ...(runOptions?.headers ?? {}) },
|
|
963
944
|
thinking: resolveEffectiveThinking(this.thinkingConfig, runOptions?.thinkingLevel),
|
|
964
|
-
cache: this.
|
|
965
|
-
? { sessionId }
|
|
966
|
-
: { ...this.cacheConfig, sessionId },
|
|
945
|
+
...(this.cache ? { cache: this.cache } : {}),
|
|
967
946
|
serviceTier: this.serviceTier,
|
|
968
947
|
sessionId,
|
|
969
948
|
...(this.outputSpec ? { output: this.outputSpec } : {}),
|
|
@@ -1013,7 +992,6 @@ export class Agent {
|
|
|
1013
992
|
options: providerOptions,
|
|
1014
993
|
runOptions,
|
|
1015
994
|
maxTurns: this.maxTurns,
|
|
1016
|
-
bypassInputFileModality: this.bypassInputFileModality,
|
|
1017
995
|
...(this.fileAccess ? { fileAccess: this.fileAccess } : {}),
|
|
1018
996
|
onFailure: this.onFailure,
|
|
1019
997
|
...(this.captureRaw !== undefined ? { captureRaw: this.captureRaw } : {}),
|
|
@@ -1076,7 +1054,6 @@ export class Agent {
|
|
|
1076
1054
|
options: providerOptions,
|
|
1077
1055
|
runOptions,
|
|
1078
1056
|
maxTurns: this.maxTurns,
|
|
1079
|
-
bypassInputFileModality: this.bypassInputFileModality,
|
|
1080
1057
|
...(this.fileAccess ? { fileAccess: this.fileAccess } : {}),
|
|
1081
1058
|
onFailure: this.onFailure,
|
|
1082
1059
|
...(this.captureRaw !== undefined ? { captureRaw: this.captureRaw } : {}),
|
|
@@ -1291,13 +1268,7 @@ export class Agent {
|
|
|
1291
1268
|
: { enabled: true, level: lvl };
|
|
1292
1269
|
}
|
|
1293
1270
|
if (typeof data.instructions === "string") this.instructions = data.instructions;
|
|
1294
|
-
if (data.cache) {
|
|
1295
|
-
(this as any).cacheConfig = {
|
|
1296
|
-
...this.cacheConfig,
|
|
1297
|
-
...data.cache,
|
|
1298
|
-
sessionId: data.sessionId ?? this.sessionId,
|
|
1299
|
-
};
|
|
1300
|
-
}
|
|
1271
|
+
if (data.cache) (this as { cache?: CacheOption }).cache = data.cache;
|
|
1301
1272
|
if (data.subagentModel) {
|
|
1302
1273
|
(this as any).subagentModel = data.subagentModel;
|
|
1303
1274
|
const dyn = (this as any).dynamicSubagents;
|
|
@@ -1319,8 +1290,6 @@ export class Agent {
|
|
|
1319
1290
|
} else {
|
|
1320
1291
|
this.context.systemPrompt = this.getFullInstructions();
|
|
1321
1292
|
}
|
|
1322
|
-
this.context.cachedContentId =
|
|
1323
|
-
data.cachedContentId ?? (this.cacheConfig as any)?.cachedContentId;
|
|
1324
1293
|
// Q-25: importing a snapshot invalidates prior provider chaining/routing
|
|
1325
1294
|
// for both the previous and the restored session.
|
|
1326
1295
|
try { clearInteractionChains(prevSid); } catch {}
|
|
@@ -1383,10 +1352,6 @@ export class Agent {
|
|
|
1383
1352
|
} else if (ctx.systemPrompt !== fullInstructions) {
|
|
1384
1353
|
ctx.systemPrompt = fullInstructions;
|
|
1385
1354
|
}
|
|
1386
|
-
// C11: keep context cachedContentId in sync with cacheConfig if updated via options
|
|
1387
|
-
if (options?.headers && (this.cacheConfig as any)?.cachedContentId && !ctx.cachedContentId) {
|
|
1388
|
-
ctx.cachedContentId = (this.cacheConfig as any).cachedContentId;
|
|
1389
|
-
}
|
|
1390
1355
|
ctx.addUserMessage(prompt);
|
|
1391
1356
|
}
|
|
1392
1357
|
|
package/src/agent/context.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Message, ContentPart } from "../types/message.ts";
|
|
1
|
+
import type { Message, ContentPart, ProviderSteps } from "../types/message.ts";
|
|
2
2
|
import type { ToolCallRecord, ToolResultRecord } from "../types/tool.ts";
|
|
3
3
|
import { safeStringify } from "../utils/serialization.ts";
|
|
4
4
|
import { clearSessionRouting } from "../providers.ts";
|
|
@@ -27,7 +27,6 @@ export class AgentContext {
|
|
|
27
27
|
systemPrompt?: string;
|
|
28
28
|
messages: Message[] = [];
|
|
29
29
|
thoughtSignatures: string[] = [];
|
|
30
|
-
cachedContentId?: string;
|
|
31
30
|
|
|
32
31
|
constructor(systemPrompt?: string) {
|
|
33
32
|
this.systemPrompt = systemPrompt;
|
|
@@ -57,11 +56,13 @@ export class AgentContext {
|
|
|
57
56
|
});
|
|
58
57
|
}
|
|
59
58
|
|
|
59
|
+
// Stores one model turn as an assistant message (text, thinking, tool calls, raw provider steps for replay); in: a provider turn from the loop, out: history.
|
|
60
60
|
addAssistantMessage(
|
|
61
61
|
text: string,
|
|
62
62
|
toolCalls?: ToolCallRecord[],
|
|
63
63
|
thinking?: string,
|
|
64
|
-
thoughtSignature?: string
|
|
64
|
+
thoughtSignature?: string,
|
|
65
|
+
providerSteps?: ProviderSteps
|
|
65
66
|
): void {
|
|
66
67
|
const parts: ContentPart[] = [];
|
|
67
68
|
const hasToolCalls = Boolean(toolCalls && toolCalls.length > 0);
|
|
@@ -111,6 +112,7 @@ export class AgentContext {
|
|
|
111
112
|
role: "assistant",
|
|
112
113
|
content: parts.length > 0 ? parts : text,
|
|
113
114
|
thoughtSignature,
|
|
115
|
+
...(providerSteps ? { providerSteps } : {}),
|
|
114
116
|
});
|
|
115
117
|
|
|
116
118
|
if (thoughtSignature) {
|
|
@@ -158,7 +160,6 @@ export class AgentContext {
|
|
|
158
160
|
}
|
|
159
161
|
}
|
|
160
162
|
next.thoughtSignatures = [...this.thoughtSignatures];
|
|
161
|
-
next.cachedContentId = this.cachedContentId;
|
|
162
163
|
return next;
|
|
163
164
|
}
|
|
164
165
|
|
package/src/agent/delegation.ts
CHANGED
|
@@ -140,10 +140,6 @@ export const SUBAGENT_SUBSCRIBE_TTL_MS = 5 * 60 * 1000;
|
|
|
140
140
|
/** Last-write wall-clock per canonical trackingId (drives TTL; reads do not extend it). */
|
|
141
141
|
const traceTouchedAt = new Map<string, number>();
|
|
142
142
|
|
|
143
|
-
function canonicalOf(trace: SubAgentTrace): string {
|
|
144
|
-
return trace.trackingId;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
143
|
function deleteTraceByCanonical(canonical: string): void {
|
|
148
144
|
for (const [key, t] of [...subagentTraces]) {
|
|
149
145
|
if (t.trackingId === canonical) subagentTraces.delete(key);
|
|
@@ -381,10 +377,6 @@ function readBudget(parentAgent: Agent): Budget | undefined {
|
|
|
381
377
|
return (parentAgent as unknown as { budget?: Budget }).budget;
|
|
382
378
|
}
|
|
383
379
|
|
|
384
|
-
function readBudgetState(parentAgent: Agent): BudgetState | undefined {
|
|
385
|
-
return (parentAgent as unknown as { budgetState?: BudgetState }).budgetState;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
380
|
function ensureBudgetState(parentAgent: Agent): BudgetState {
|
|
389
381
|
const host = parentAgent as unknown as { budgetState?: BudgetState };
|
|
390
382
|
if (!host.budgetState) {
|
|
@@ -711,7 +703,7 @@ export function createSubagentSpawnTool(parentAgent: Agent): ToolDefinition {
|
|
|
711
703
|
try { (parentAgent as any).persistNow?.(); } catch {}
|
|
712
704
|
};
|
|
713
705
|
// Unified live worker state machine (shared with fixed workers).
|
|
714
|
-
const { onWorkerTurn,
|
|
706
|
+
const { onWorkerTurn, attachToStream } = createLiveWorker(trace, trackingId, displayId, {
|
|
715
707
|
trim: (t) => trimTraceSteps(t),
|
|
716
708
|
touch: (id) => touchTrace(id),
|
|
717
709
|
notify: (id) => notifyTrace(id),
|