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.
@@ -24,7 +24,7 @@
24
24
  import * as fs from "node:fs";
25
25
  import * as path from "node:path";
26
26
  import type { Message, ContentPart } from "../types/message.ts";
27
- import type { TokenUsage, CacheConfig, ServiceTier } from "../types/core.ts";
27
+ import { CACHE_OPTIONS, type TokenUsage, type CacheOption, type ServiceTier } from "../types/core.ts";
28
28
  import type { ModelSpec } from "../types/model.ts";
29
29
  import type { AgentResponse } from "../types/response.ts";
30
30
  import { base64ToBytes, bytesToBase64 } from "../utils/base64.ts";
@@ -68,12 +68,11 @@ export interface PersistedAgentSession {
68
68
  model: string;
69
69
  subagentModel?: string;
70
70
  thinkingLevel?: string;
71
- cache?: CacheConfig;
71
+ cache?: CacheOption;
72
72
  /** Legacy read-only: pre-compact files duplicated base instructions here;
73
73
  * no longer written (`systemPrompt` already embeds them). */
74
74
  instructions?: string;
75
75
  systemPrompt?: string;
76
- cachedContentId?: string;
77
76
  messages: Message[];
78
77
  totals?: SessionTotals;
79
78
  /** Parent session this snapshot was spawned from, when applicable. */
@@ -283,11 +282,11 @@ export interface SessionAgentLike {
283
282
  modelStringOrSpec: unknown;
284
283
  subagentModel?: unknown;
285
284
  thinkingConfig?: { level?: string };
286
- cacheConfig?: CacheConfig;
285
+ cache?: CacheOption;
287
286
  instructions?: string;
288
287
  parentSessionId?: unknown;
289
288
  subagentTraces?: Record<string, PersistedSubAgentTrace>;
290
- context: { systemPrompt?: string; messages: Message[]; cachedContentId?: string };
289
+ context: { systemPrompt?: string; messages: Message[] };
291
290
  }
292
291
 
293
292
  function snapshotSubagents(traces: Record<string, PersistedSubAgentTrace> | undefined): Record<string, PersistedSubAgentTrace> | undefined {
@@ -416,17 +415,6 @@ export function buildSessionData(agent: SessionAgentLike, telemetry?: SessionTel
416
415
  typeof (agent as any)?.parentSessionId === "string" ? (agent as any).parentSessionId as string : undefined;
417
416
  const subagents = snapshotSubagents((agent as any)?.subagentTraces as Record<string, PersistedSubAgentTrace> | undefined);
418
417
  const messages = inlineBinaryMedia(stripRedundantRawArguments(agent.context.messages));
419
- // `cache.sessionId` echoes the top-level `sessionId` (affinity alias): drop
420
- // it from the file when identical so it isn't stored twice. Readers still
421
- // accept legacy files carrying it (`importSession`, loop fallbacks).
422
- const cacheForFile = (() => {
423
- if (!agent.cacheConfig) return undefined;
424
- if (agent.cacheConfig.sessionId === agent.sessionId) {
425
- const { sessionId: _dropped, ...rest } = agent.cacheConfig;
426
- return Object.keys(rest).length > 0 ? rest : undefined;
427
- }
428
- return agent.cacheConfig;
429
- })();
430
418
  // Field order is the on-disk layout contract: identity → config →
431
419
  // systemPrompt → totals → messages → lineage/traces. `instructions` is
432
420
  // intentionally never written: `systemPrompt` already embeds it (plus the
@@ -438,9 +426,8 @@ export function buildSessionData(agent: SessionAgentLike, telemetry?: SessionTel
438
426
  model,
439
427
  ...(subagentModel ? { subagentModel: String(subagentModel) } : {}),
440
428
  ...(agent.thinkingConfig?.level ? { thinkingLevel: agent.thinkingConfig.level as string } : {}),
441
- ...(cacheForFile ? { cache: cacheForFile } : {}),
429
+ ...(agent.cache ? { cache: agent.cache } : {}),
442
430
  ...(agent.context.systemPrompt ? { systemPrompt: agent.context.systemPrompt } : {}),
443
- ...(agent.context.cachedContentId ? { cachedContentId: agent.context.cachedContentId } : {}),
444
431
  ...(totals ? { totals } : {}),
445
432
  messages,
446
433
  ...(parentSessionId ? { parentSessionId } : {}),
@@ -511,6 +498,14 @@ export interface SessionLimits {
511
498
  /** Marker for a structurally valid payload that exceeds the configured limits. */
512
499
  const OVER_LIMIT = Symbol("session-over-limit");
513
500
 
501
+ // Reads a stored `cache` field: a current string value, or a pre-0.5.1 `{ retention }` object (short=5m, medium=1h, long=12h); in: a parsed session file, out: `PersistedAgentSession.cache`.
502
+ function toCacheOption(raw: unknown): CacheOption | undefined {
503
+ if (typeof raw === "string") return (CACHE_OPTIONS as readonly string[]).includes(raw) ? (raw as CacheOption) : undefined;
504
+ const legacy: Record<string, CacheOption> = { implicit: "implicit", short: "5m", medium: "1h", long: "12h" };
505
+ const retention = (raw as { retention?: unknown } | null)?.retention;
506
+ return typeof retention === "string" ? legacy[retention] : undefined;
507
+ }
508
+
514
509
  function parseSession(raw: string, limits?: SessionLimits): PersistedAgentSession | null | typeof OVER_LIMIT {
515
510
  const maxMessages = limits?.maxMessages ?? MAX_SESSION_MESSAGES;
516
511
  const maxBytes = limits?.maxBytes ?? MAX_SESSION_JSON_BYTES;
@@ -525,8 +520,7 @@ function parseSession(raw: string, limits?: SessionLimits): PersistedAgentSessio
525
520
  let model = "";
526
521
  let subagentModel: string | undefined;
527
522
  let thinkingLevel: string | undefined;
528
- let cache: CacheConfig | undefined;
529
- let cachedContentId: string | undefined;
523
+ let cache: CacheOption | undefined;
530
524
  let systemPrompt: string | undefined;
531
525
  let instructions: string | undefined;
532
526
  let parentSessionId: string | undefined;
@@ -540,8 +534,7 @@ function parseSession(raw: string, limits?: SessionLimits): PersistedAgentSessio
540
534
  const obj: any = JSON.parse(t);
541
535
  if (obj.type === "session") {
542
536
  sessionId = obj.id ?? obj.sessionId ?? sessionId;
543
- cache = obj.cache ?? cache;
544
- cachedContentId = obj.cachedContentId ?? cachedContentId;
537
+ cache = toCacheOption(obj.cache) ?? cache;
545
538
  model = obj.model ?? model;
546
539
  thinkingLevel = obj.thinkingLevel ?? thinkingLevel;
547
540
  parentSessionId = obj.parentSessionId ?? parentSessionId;
@@ -553,8 +546,7 @@ function parseSession(raw: string, limits?: SessionLimits): PersistedAgentSessio
553
546
  subagentModel = obj.id ?? obj.model ?? subagentModel;
554
547
  } else if (obj.type === "metrics" || obj.type === "totals") {
555
548
  totals = (obj.metrics ?? obj.totals ?? totals) as SessionTotals | undefined;
556
- cache = obj.cache ?? cache;
557
- cachedContentId = obj.cachedContentId ?? cachedContentId;
549
+ cache = toCacheOption(obj.cache) ?? cache;
558
550
  } else if (obj.type === "modelChange") {
559
551
  model = obj.modelId ?? obj.model ?? model;
560
552
  } else if (obj.type === "thinkingLevelChange") {
@@ -581,7 +573,6 @@ function parseSession(raw: string, limits?: SessionLimits): PersistedAgentSessio
581
573
  ...(cache ? { cache } : {}),
582
574
  ...(instructions ? { instructions } : {}),
583
575
  ...(systemPrompt ? { systemPrompt } : {}),
584
- ...(cachedContentId ? { cachedContentId } : {}),
585
576
  messages,
586
577
  ...(totals ? { totals } : {}),
587
578
  ...(parentSessionId ? { parentSessionId } : {}),
@@ -602,10 +593,9 @@ function parseSession(raw: string, limits?: SessionLimits): PersistedAgentSessio
602
593
  model: obj.model ?? "",
603
594
  subagentModel: obj.subagentModel,
604
595
  thinkingLevel: obj.thinkingLevel ?? obj.thinkingLevelChange,
605
- cache: obj.cache,
596
+ cache: toCacheOption(obj.cache),
606
597
  instructions: obj.instructions,
607
598
  systemPrompt: obj.context.systemPrompt,
608
- cachedContentId: obj.cachedContentId ?? obj.context.cachedContentId,
609
599
  messages: obj.context.messages as Message[],
610
600
  totals: obj.totals ?? obj.metrics,
611
601
  parentSessionId: obj.parentSessionId,
@@ -622,10 +612,9 @@ function parseSession(raw: string, limits?: SessionLimits): PersistedAgentSessio
622
612
  model: obj.model ?? "",
623
613
  subagentModel: obj.subagentModel,
624
614
  thinkingLevel: obj.thinkingLevel,
625
- cache: obj.cache,
615
+ cache: toCacheOption(obj.cache),
626
616
  instructions: obj.instructions,
627
617
  systemPrompt: obj.systemPrompt,
628
- cachedContentId: obj.cachedContentId,
629
618
  messages: Array.isArray(obj.messages) ? (obj.messages as Message[]) : [],
630
619
  totals: obj.totals,
631
620
  parentSessionId: obj.parentSessionId,
@@ -2,7 +2,7 @@ import type { ModelSpec } from "./model.ts";
2
2
  import type { ToolDefinition } from "./tool.ts";
3
3
  import type {
4
4
  ThinkingLevel,
5
- CacheConfig,
5
+ CacheOption,
6
6
  ServiceTier,
7
7
  } from "./core.ts";
8
8
  import type { ModelProviderInstance } from "../providers/registry.ts";
@@ -17,7 +17,7 @@ import type { z } from "zod";
17
17
  // is a deprecated alias (still honored: dynamicSubagents.model ??
18
18
  // subagentModel ?? SUB_AGENT_MODEL ?? parent model).
19
19
  // - Session identity: agent-level `sessionId` only (per-run `sessionId`
20
- // selects a named session entry; `cache.sessionId` is a deprecated alias).
20
+ // selects a named session entry).
21
21
  // - Model identity: `ModelRef` = string (`provider/model`) | catalog
22
22
  // `ModelSpec` | `ModelProviderInstance` ({ provider, model, apiKey?,
23
23
  // baseUrl? }). Explicit `Agent` config always wins over env; constructing
@@ -96,17 +96,13 @@ export interface AgentConfig {
96
96
  * See `normalizeThinkingV2` (re-exported from the root entry).
97
97
  */
98
98
  thinking?: ThinkingOption;
99
- /** Prompt-cache retention and session-affinity settings. */
100
- cache?: CacheConfig;
101
- /** Provider service tier, when supported. */
102
- serviceTier?: ServiceTier;
103
99
  /**
104
- * When true, `file` parts are converted client-side to `<Document>` Markdown
105
- * for models lacking native support (capable models still receive files
106
- * natively; unknown models count as capable). Also auto-registers the
107
- * `convert_document_to_markdown` tool for path/URL mentions in plain text.
100
+ * Prompt-cache lifetime: `"implicit" | "5m" | "30m" | "1h" | "12h"`. Omit for the provider default.
101
+ * A value the provider does not support falls back to its default with one `provider_warning`.
108
102
  */
109
- bypassInputFileModality?: boolean;
103
+ cache?: CacheOption;
104
+ /** Provider service tier, when supported. */
105
+ serviceTier?: ServiceTier;
110
106
  /** Stable conversation/cache session ID. */
111
107
  sessionId?: string;
112
108
  /** Headers merged into every provider request. */
@@ -186,10 +182,9 @@ export interface AgentConfig {
186
182
  */
187
183
  telemetry?: { persist?: boolean };
188
184
  /**
189
- * Local file policy. With `roots` set, every local-path media part and the
190
- * built-in `convert_document_to_markdown` tool must resolve inside them
191
- * (`[]` denies all local paths). Without it, developer-supplied parts are
192
- * unrestricted and the model-callable tool is limited to `process.cwd()`.
185
+ * Local file policy. With `roots` set, every local-path media part must
186
+ * resolve inside them (`[]` denies all local paths). Without it, local
187
+ * paths in message parts are unrestricted.
193
188
  */
194
189
  fileAccess?: { roots?: string[] };
195
190
  /**
package/src/types/core.ts CHANGED
@@ -24,40 +24,13 @@ export interface ThinkingConfig {
24
24
  }
25
25
 
26
26
  /**
27
- * Cache retention:
28
- * - "implicit": automatic prefix caching ($0.00 storage fee, session affinity preserved)
29
- * - "short": 5 minutes explicit TTL
30
- * - "medium": 1 hour explicit TTL
31
- * - "long": 12 hours explicit TTL
32
- * - undefined: no explicit caching enforced (implicit may still happen)
27
+ * Prompt-cache lifetime: `"implicit"` (automatic prefix caching) or an explicit TTL. Each provider honours only
28
+ * the values it supports; others fall back to its default with one warning. Omit for the provider default.
33
29
  */
34
- /** Prompt-cache retention policy. */
35
- export type CacheRetention = "implicit" | "short" | "medium" | "long";
30
+ export type CacheOption = "implicit" | "5m" | "30m" | "1h" | "12h";
36
31
 
37
- /** Prompt-cache IDs, retention, TTL, and session-affinity settings. */
38
- export interface CacheConfig {
39
- /**
40
- * Retention duration:
41
- * - "implicit": automatic prefix caching ($0.00 storage fee, no explicit cloud cache entities created)
42
- * - "short": 5 minutes TTL
43
- * - "medium": 1 hour TTL
44
- * - "long": 12 hours TTL
45
- * - undefined: no explicit caching enforced (implicit may still happen)
46
- */
47
- retention?: CacheRetention;
48
- /**
49
- * Explicit cache ID / reference if using pre-created context cache
50
- */
51
- cachedContentId?: string;
52
- /**
53
- * Session ID for cache affinity routing (e.g. x-session-id)
54
- */
55
- sessionId?: string;
56
- /**
57
- * Explicit TTL in seconds for created caches (overrides retention mapping)
58
- */
59
- ttlSeconds?: number;
60
- }
32
+ /** Every accepted {@link CacheOption}, for runtime validation. */
33
+ export const CACHE_OPTIONS: readonly CacheOption[] = ["implicit", "5m", "30m", "1h", "12h"];
61
34
 
62
35
  /**
63
36
  * Service tier controls — bloatfree: only flex / priority (standard is default, no flag needed)
@@ -9,6 +9,9 @@ export interface TextPart {
9
9
  thoughtSignature?: string;
10
10
  }
11
11
 
12
+ /** Detail level a provider spends on one image or video (more detail = more input tokens). Google only; other providers ignore it with a warning. */
13
+ export type MediaResolution = "low" | "medium" | "high" | "ultra_high";
14
+
12
15
  /** Image content accepted as a URL, data, path, or binary value. */
13
16
  export interface ImagePart {
14
17
  type: "image";
@@ -17,6 +20,8 @@ export interface ImagePart {
17
20
  */
18
21
  image: string | Uint8Array | ArrayBuffer;
19
22
  mimeType?: string;
23
+ /** Detail level for this image (Google: `low` 280, `medium` 560, `high` 1120, `ultra_high` 2240 tokens). */
24
+ resolution?: MediaResolution;
20
25
  }
21
26
 
22
27
  /** Audio content accepted as a URL, data, path, or binary value. */
@@ -48,6 +53,8 @@ export interface VideoPart {
48
53
  */
49
54
  video: string | Uint8Array | ArrayBuffer;
50
55
  mimeType?: string;
56
+ /** Detail level per frame (Google: `low`/`medium` 70, `high` 280 tokens). */
57
+ resolution?: MediaResolution;
51
58
  }
52
59
 
53
60
  /** Assistant-generated structured tool invocation. */
@@ -100,12 +107,20 @@ export type ContentPart =
100
107
 
101
108
  export type MessageRole = "system" | "user" | "assistant" | "tool";
102
109
 
110
+ /** A provider's raw output steps for one assistant turn, kept to replay history byte-exact (only the tagged provider reads them). */
111
+ export interface ProviderSteps {
112
+ provider: string;
113
+ steps: unknown[];
114
+ }
115
+
103
116
  /** Normalized conversation message. */
104
117
  export interface Message {
105
118
  role: MessageRole;
106
119
  content: string | ContentPart[];
107
120
  name?: string;
108
121
  thoughtSignature?: string;
122
+ /** Raw provider output steps of an assistant turn (opaque; e.g. Google `steps`). */
123
+ providerSteps?: ProviderSteps;
109
124
  }
110
125
 
111
126
  /**
@@ -116,5 +131,4 @@ export interface ProviderContext {
116
131
  systemPrompt?: string;
117
132
  messages: Message[];
118
133
  tools?: Record<string, unknown>[];
119
- cachedContentId?: string;
120
134
  }
@@ -1,5 +1,5 @@
1
- import type { ThinkingConfig, CacheConfig, ServiceTier, TokenUsage } from "./core.ts";
2
- import type { ProviderContext } from "./message.ts";
1
+ import type { ThinkingConfig, CacheOption, ServiceTier, TokenUsage } from "./core.ts";
2
+ import type { ProviderContext, ProviderSteps } from "./message.ts";
3
3
  import type { StandardToolDeclaration, ToolCallRecord } from "./tool.ts";
4
4
  import type { AssistantMessageEventStream } from "../streaming/event-stream.ts";
5
5
 
@@ -166,7 +166,7 @@ export interface ProviderRequestOptions {
166
166
  baseUrl?: string;
167
167
  headers?: Record<string, string>;
168
168
  thinking?: ThinkingConfig;
169
- cache?: CacheConfig;
169
+ cache?: CacheOption;
170
170
  serviceTier?: ServiceTier;
171
171
  tools?: StandardToolDeclaration[];
172
172
  toolChoice?: "auto" | "none" | "required" | { type: "function"; function: { name: string } };
@@ -226,6 +226,8 @@ export interface ProviderGenerateResult {
226
226
  provider: ProviderId;
227
227
  raw: ProviderRawData;
228
228
  durationMs: number;
229
+ /** Raw output steps for exact history replay (stored on the assistant message). */
230
+ providerSteps?: ProviderSteps;
229
231
  }
230
232
 
231
233
  /** Provider contract implemented by native REST transports. */
@@ -244,4 +246,6 @@ export interface Provider {
244
246
  context: ProviderContext,
245
247
  options?: ProviderRequestOptions
246
248
  ): AssistantMessageEventStream;
249
+ /** True when this call may legitimately run far past the request timeouts (e.g. Google long decode); the loop then leaves timing to the adapter's own per-request timeouts. */
250
+ isLongRunning?(model: string | ModelSpec, options?: ProviderRequestOptions): boolean;
247
251
  }
@@ -1,6 +1,7 @@
1
1
  import type { TokenUsage } from "./core.ts";
2
2
  import type { ToolCallRecord, ToolResultRecord } from "./tool.ts";
3
3
  import type { ProviderRawData, ProviderId } from "./model.ts";
4
+ import type { ProviderSteps } from "./message.ts";
4
5
 
5
6
  /** One logged step inside a sub-agent worker run (surfaced via `agent.track(id)`). */
6
7
  export interface SubAgentStep {
@@ -142,6 +143,8 @@ export class AgentResponse {
142
143
  readonly durationMs: number;
143
144
  readonly raw: ProviderRawData;
144
145
  readonly turns: number;
146
+ /** Raw provider output steps of a single streamed turn (history replay only; not in `toJSON`). */
147
+ readonly providerSteps?: ProviderSteps;
145
148
 
146
149
  /**
147
150
  * Constructs a normalized response. Agent runs create this automatically;
@@ -167,6 +170,7 @@ export class AgentResponse {
167
170
  durationMs: number;
168
171
  raw: ProviderRawData;
169
172
  turns?: number;
173
+ providerSteps?: ProviderSteps;
170
174
  }) {
171
175
  this.text = data.text;
172
176
  if (data.parsed !== undefined) (this as { parsed?: unknown }).parsed = data.parsed;
@@ -184,6 +188,7 @@ export class AgentResponse {
184
188
  this.durationMs = data.durationMs;
185
189
  this.raw = data.raw;
186
190
  this.turns = data.turns ?? 1;
191
+ if (data.providerSteps) this.providerSteps = data.providerSteps;
187
192
  }
188
193
 
189
194
  /** Returns the final assistant text. */
@@ -1,14 +1,4 @@
1
- /**
2
- * Battle-tested cache helper — single source for 80-90% hit rate
3
- * Based on agent-accel: openai-prompt-cache.ts + applyAnthropicCacheControl
4
- * - First turn already cache-optimized: system + tools + first user get cache_control
5
- * - Stable sessionId (64 clamp) + prompt_cache_key ensures affinity
6
- * - 4 breakpoint cap (Anthropic limit)
7
- * - Retention mapping: short=5m (no ttl), medium=1h, long=24h (prompt) / 1h (anthropic)
8
- */
9
-
10
- import type { CacheRetention } from "../types/core.ts";
11
- import { getApiKey } from "./env.ts";
1
+ /** Cache-key clamping and central secret redaction shared by the provider adapters. */
12
2
 
13
3
  const CACHE_KEY_MAX = 64;
14
4
 
@@ -20,132 +10,6 @@ export function clampCacheKey(key?: string): string | undefined {
20
10
  return chars.slice(0, CACHE_KEY_MAX).join("");
21
11
  }
22
12
 
23
- /** Maps retention to explicit-cache TTL seconds. short=5m, medium=1h, long=12h. Explicit ttlSeconds wins. */
24
- export function retentionToTtlSeconds(retention?: CacheRetention, ttlSeconds?: number): number | undefined {
25
- if (ttlSeconds && ttlSeconds > 0) return Math.floor(ttlSeconds);
26
- if (!retention || retention === "implicit") return undefined;
27
- if (retention === "short") return 300;
28
- if (retention === "medium") return 3600;
29
- if (retention === "long") return 43200;
30
- return undefined;
31
- }
32
-
33
- /** Maps retention settings to OpenRouter prompt-cache TTL values. */
34
- export function getPromptCacheRetention(retention?: CacheRetention, supportsLong = true): "24h" | "1h" | undefined {
35
- if (!retention || retention === "implicit") return undefined;
36
- if (retention === "long" && supportsLong) return "24h";
37
- if (retention === "medium" && supportsLong) return "1h";
38
- if (retention === "long") return "24h"; // fallback even if supportsLong false, provider may ignore
39
- return undefined;
40
- }
41
-
42
- // ============================================================================
43
- // Explicit Context Caching (Google cachedContents API)
44
- // ============================================================================
45
-
46
- export interface CachedContentMetadata {
47
- name: string;
48
- displayName?: string;
49
- model: string;
50
- createTime: string;
51
- updateTime: string;
52
- expireTime: string;
53
- usageMetadata?: {
54
- totalTokenCount?: number;
55
- };
56
- }
57
-
58
- export interface CreateExplicitCacheOptions {
59
- model: string;
60
- contents?: any[];
61
- systemInstruction?: string;
62
- tools?: any[];
63
- toolConfig?: any;
64
- displayName?: string;
65
- ttlSeconds?: number;
66
- retention?: CacheRetention;
67
- expireTime?: string | Date;
68
- apiKey?: string;
69
- baseUrl?: string;
70
- }
71
-
72
- /**
73
- * Creates an explicit cached content object using Google Gemini's cachedContents API.
74
- * REST: POST https://generativelanguage.googleapis.com/v1beta/cachedContents (key in the `x-goog-api-key` header)
75
- */
76
- /**
77
- * Creates a Google Gemini cachedContents resource through the REST API.
78
- *
79
- * @example `const cache = await createExplicitCache({ model: "google/gemini-3.5-flash-lite", contents });`
80
- */
81
- export async function createExplicitCache(
82
- options: CreateExplicitCacheOptions
83
- ): Promise<CachedContentMetadata> {
84
- const apiKey = getApiKey("google", options.apiKey);
85
- if (!apiKey) {
86
- throw new Error("API key is required to create explicit cache (GEMINI_API_KEY)");
87
- }
88
-
89
- const baseUrl = options.baseUrl || "https://generativelanguage.googleapis.com/v1beta";
90
- const ttlSeconds = retentionToTtlSeconds(options.retention, options.ttlSeconds) ?? 3600;
91
- const ttl = options.expireTime ? undefined : `${ttlSeconds}s`;
92
-
93
- let modelName = options.model;
94
- if (!modelName.startsWith("models/")) {
95
- modelName = `models/${modelName.replace(/^google\//, "")}`;
96
- }
97
-
98
- const payload: Record<string, unknown> = {
99
- model: modelName,
100
- contents: options.contents ?? [],
101
- ...(ttl ? { ttl } : {}),
102
- ...(options.expireTime
103
- ? { expireTime: options.expireTime instanceof Date ? options.expireTime.toISOString() : options.expireTime }
104
- : {}),
105
- };
106
-
107
- if (options.displayName) {
108
- payload.displayName = options.displayName;
109
- (payload as any).display_name = options.displayName;
110
- }
111
-
112
- if (options.systemInstruction) {
113
- payload.systemInstruction = {
114
- parts: [{ text: options.systemInstruction }],
115
- };
116
- (payload as any).system_instruction = payload.systemInstruction;
117
- }
118
-
119
- if (options.tools && options.tools.length > 0) {
120
- payload.tools = options.tools;
121
- }
122
-
123
- if (options.toolConfig) {
124
- payload.toolConfig = options.toolConfig;
125
- (payload as any).tool_config = options.toolConfig;
126
- }
127
-
128
- // The key travels in a header, never in the URL (URLs end up in proxy and access logs).
129
- const url = `${baseUrl}/cachedContents`;
130
- const response = await fetch(url, {
131
- method: "POST",
132
- headers: {
133
- "Content-Type": "application/json",
134
- "x-goog-api-key": apiKey,
135
- },
136
- body: JSON.stringify(payload),
137
- });
138
-
139
- if (!response.ok) {
140
- const errorBody = await response.text();
141
- throw new Error(
142
- `Failed to create explicit cache (${response.status} ${response.statusText}): ${errorBody}`
143
- );
144
- }
145
-
146
- return (await response.json()) as CachedContentMetadata;
147
- }
148
-
149
13
  // ---------------------------------------------------------------------------
150
14
  // Central redaction helpers (Q-11, temporary home to avoid owner conflicts).
151
15
  // Providers must call these instead of maintaining local deny-lists.
@@ -140,11 +140,8 @@ export function assertModalitiesSupported(
140
140
  if (!supported) return;
141
141
  const missing = [...needed].filter((k) => !supported.includes(k));
142
142
  if (missing.length === 0) return;
143
- const docHint = missing.includes("pdf")
144
- ? " Documents can be converted client-side with the convert_document_to_markdown tool (bun add @firecrawl/anydoc) or Agent bypassInputFileModality: true."
145
- : "";
146
143
  const err = new Error(
147
- `[${displayModel(providerId, modelId)}] unsupported ${missing.join("+")} input (supports: ${supported.join(", ") || "text"}). Use a capable model or drop the ${missing.join("+")} part.${docHint}`
144
+ `[${displayModel(providerId, modelId)}] unsupported ${missing.join("+")} input (supports: ${supported.join(", ") || "text"}). Use a capable model or drop the ${missing.join("+")} part.`
148
145
  );
149
146
  err.name = "AgentAccelProviderError";
150
147
  Object.defineProperties(err, {
@@ -1,5 +1,4 @@
1
1
  import type { ProviderId } from "../types/model.ts";
2
- import type { CacheConfig } from "../types/core.ts";
3
2
  import { clampCacheKey } from "./cache.ts";
4
3
 
5
4
  export function isBrowserRuntime(): boolean {
@@ -24,7 +23,7 @@ export function getPackageVersion(): string {
24
23
  const v = (globalThis as any).process?.env?.npm_package_version;
25
24
  if (typeof v === "string" && v) return v;
26
25
  } catch {}
27
- return "0.5.0";
26
+ return "0.5.2";
28
27
  }
29
28
 
30
29
  function getAgentAccelUserAgent(): string {
@@ -106,19 +105,6 @@ export function setHeaderCaseInsensitive(
106
105
  // Thought-signature namespacing (Q-18).
107
106
  // ---------------------------------------------------------------------------
108
107
 
109
- /**
110
- * Tags a captured thought signature with its issuing provider so history
111
- * builders echo it only on the same provider. Untagged (legacy) signatures
112
- * echo everywhere for backward compat.
113
- */
114
- export function withProviderSignature(
115
- sig: string | undefined,
116
- provider: string
117
- ): { thoughtSignature?: string; thoughtSignatureProvider?: string } {
118
- if (!sig) return {};
119
- return { thoughtSignature: sig, thoughtSignatureProvider: provider };
120
- }
121
-
122
108
  /**
123
109
  * Returns true when a stored signature may be echoed on `currentProvider`:
124
110
  * untagged (legacy) echoes everywhere, tagged echoes only on a match.
@@ -163,11 +149,10 @@ function stripForBrowser(headers: Record<string, string>): Record<string, string
163
149
  * runtimes this returns only CORS-safe attribution headers (OpenRouter
164
150
  * `HTTP-Referer` / `X-Title`); session affinity still flows via `providerOptions`
165
151
  * (`promptCacheKey`), never via headers.
166
- * @example `const headers = buildSessionHeaders("google", { sessionId: "session-123" });`
152
+ * @example `const headers = buildSessionHeaders("google", undefined, "session-123");`
167
153
  */
168
154
  export function buildSessionHeaders(
169
155
  provider: ProviderId | string,
170
- cache?: CacheConfig,
171
156
  customHeaders?: Record<string, string>,
172
157
  explicitSessionId?: string
173
158
  ): Record<string, string> {
@@ -183,8 +168,7 @@ export function buildSessionHeaders(
183
168
  headers[k] = v;
184
169
  }
185
170
 
186
- const rawSessionId = explicitSessionId || cache?.sessionId;
187
- const sessionId = clampCacheKey(rawSessionId);
171
+ const sessionId = clampCacheKey(explicitSessionId);
188
172
  const isFirstClass = FIRST_CLASS.has(provider);
189
173
 
190
174
  const getHeader = (name: string): string | undefined => {
@@ -43,7 +43,8 @@ function readRetryAfterMs(error: unknown): number | undefined {
43
43
  return Math.min(60_000, secs * 1000);
44
44
  }
45
45
 
46
- function sleep(ms: number, signal?: AbortSignal): Promise<void> {
46
+ // Waits `ms`, rejecting with an AbortError as soon as `signal` aborts; in: retry backoff and Google background polling, out: the awaiting caller.
47
+ export function sleep(ms: number, signal?: AbortSignal): Promise<void> {
47
48
  if (ms <= 0) return Promise.resolve();
48
49
  return new Promise((resolve, reject) => {
49
50
  const timer = setTimeout(() => {
@@ -3,11 +3,11 @@
3
3
  import type { Message } from "../types/message.ts";
4
4
  import { SecurityPolicyError } from "../types/errors.ts";
5
5
 
6
- /** Default cap for one remote media/document download (bytes). */
6
+ /** Default cap for one remote media download (bytes). */
7
7
  export const MAX_REMOTE_FETCH_BYTES = 200_000_000;
8
8
 
9
9
  /**
10
- * True when a media/document string would be read from the local filesystem
10
+ * True when a media string would be read from the local filesystem
11
11
  * by `normalizeMediaInput` (i.e. it is not a data URL, an http(s) URL, or an
12
12
  * embedded base64 payload). Mirrors the classification order used there.
13
13
  */