@elevasis/sdk 1.41.1 → 1.43.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.
@@ -289,16 +289,12 @@ type OpenAIModel = 'gpt-5' | 'gpt-5.4-mini' | 'gpt-5.4-nano';
289
289
  * Supported OpenRouter models (explicit union for type safety)
290
290
  */
291
291
  type OpenRouterModel = 'openrouter/z-ai/glm-5';
292
- /**
293
- * Supported Google models (direct SDK access)
294
- */
295
- type GoogleModel = 'gemini-3-flash-preview' | 'gemini-3.1-flash-lite-preview';
296
292
  /**
297
293
  * Supported Anthropic models (direct SDK access via @anthropic-ai/sdk)
298
294
  */
299
295
  type AnthropicModel = 'claude-opus-5' | 'claude-sonnet-5' | 'claude-haiku-4-5-20251001' | 'claude-haiku-4-5';
300
296
  /** Supported LLM models */
301
- type LLMModel = OpenAIModel | OpenRouterModel | GoogleModel | AnthropicModel | 'mock';
297
+ type LLMModel = OpenAIModel | OpenRouterModel | AnthropicModel | 'mock';
302
298
  /**
303
299
  * GPT-5 model options schema
304
300
  */
@@ -325,18 +321,6 @@ declare const OpenRouterOptionsSchema: z.ZodObject<{
325
321
  fallback: "fallback";
326
322
  }>>;
327
323
  }, z.core.$strip>;
328
- /**
329
- * Google model options schema
330
- * Gemini 3 specific options for thinking depth control
331
- */
332
- declare const GoogleOptionsSchema: z.ZodObject<{
333
- thinkingLevel: z.ZodOptional<z.ZodEnum<{
334
- minimal: "minimal";
335
- low: "low";
336
- medium: "medium";
337
- high: "high";
338
- }>>;
339
- }, z.core.$strip>;
340
324
  /**
341
325
  * Anthropic model options schema
342
326
  * Currently empty - future options must be added per supported model family
@@ -348,16 +332,15 @@ declare const AnthropicOptionsSchema: z.ZodObject<{}, z.core.$strict>;
348
332
  type GPT5Options = z.infer<typeof GPT5OptionsSchema>;
349
333
  type MockOptions = Record<string, never>;
350
334
  type OpenRouterOptions = z.infer<typeof OpenRouterOptionsSchema>;
351
- type GoogleOptions = z.infer<typeof GoogleOptionsSchema>;
352
335
  type AnthropicOptions = z.infer<typeof AnthropicOptionsSchema>;
353
- type ModelSpecificOptions = GPT5Options | MockOptions | OpenRouterOptions | GoogleOptions | AnthropicOptions;
336
+ type ModelSpecificOptions = GPT5Options | MockOptions | OpenRouterOptions | AnthropicOptions;
354
337
  /**
355
338
  * Model configuration for LLM execution
356
339
  * Belongs in resource definition (AgentDefinition, WorkflowDefinition, etc.)
357
340
  */
358
341
  interface ModelConfig {
359
342
  model: LLMModel;
360
- provider: 'openai' | 'anthropic' | 'openrouter' | 'google' | 'mock';
343
+ provider: 'openai' | 'anthropic' | 'openrouter' | 'mock';
361
344
  apiKey: string;
362
345
  temperature?: number;
363
346
  /** Maximum output tokens per LLM call. NOT the model's context window — see ModelInfo.maxTokens for that. */
@@ -372,14 +355,70 @@ interface ModelConfig {
372
355
  modelOptions?: ModelSpecificOptions;
373
356
  }
374
357
 
358
+ /**
359
+ * Types for the schema compiler. `compile.ts` walks a `JsonSchema` once, driven entirely by a
360
+ * `ProviderDialect`, and every server adapter compiles through it.
361
+ */
375
362
  /**
376
363
  * What happened to `strict` on a request, recorded per call rather than inferred.
377
364
  *
378
- * `applied` and `notAttempted` are the two states that a refusal-only field cannot tell apart
365
+ * `applied` and `notAttempted` are the two states that a refusal-only field cannot tell apart --
379
366
  * both leave `strictRefusalReasons` empty. Recording the verdict positively is what makes "was
380
367
  * this agent's output actually enforced?" answerable from an `ai_calls` row.
381
368
  */
382
369
  type StrictStatus = 'applied' | 'refused' | 'compileRejected' | 'notAttempted';
370
+ /**
371
+ * A JSON Schema node, typed enough to be useful without pretending to validate the spec.
372
+ *
373
+ * The compiler has to accept schemas that arrive OUTSIDE the strict subset (that is the whole
374
+ * point of a dialect that can refuse or rewrite them) as well as the `$ref`/`$defs`/`const`/
375
+ * `$schema` shapes the strict subset has no vocabulary for at all. The index signature exists
376
+ * because tenant schemas carry keywords (`minLength`, `pattern`, `minimum`, ...) this compiler
377
+ * drops or refuses on, and they still need somewhere to type-check while they pass through
378
+ * `Object.entries`.
379
+ */
380
+ interface JsonSchema {
381
+ type?: string | string[];
382
+ /**
383
+ * The value is `JsonSchema | undefined`, not `JsonSchema`, because a property really can be
384
+ * declared with nothing describing it. `buildIterationResponseSchema` emits one per tool as
385
+ * `input: tool.inputSchema`, and `ToolDefinition.inputSchema` is typed `unknown` -- a tool
386
+ * deployed without one puts `undefined` under a key that exists.
387
+ *
388
+ * Both readers already handle it: `compileSchema` passes each value through `convertNode`, which
389
+ * takes `unknown`, and `collectErrors` opens with `if (!schema || typeof schema !== 'object')`
390
+ * above a comment naming this exact case. Declaring the value non-optional only hid that they
391
+ * were right to.
392
+ */
393
+ properties?: Record<string, JsonSchema | undefined>;
394
+ items?: JsonSchema;
395
+ anyOf?: JsonSchema[];
396
+ oneOf?: JsonSchema[];
397
+ allOf?: JsonSchema[];
398
+ required?: string[];
399
+ additionalProperties?: boolean | JsonSchema;
400
+ minItems?: number;
401
+ maxItems?: number;
402
+ format?: string;
403
+ enum?: unknown[];
404
+ const?: unknown;
405
+ description?: string;
406
+ default?: unknown;
407
+ $ref?: string;
408
+ $defs?: Record<string, JsonSchema>;
409
+ definitions?: Record<string, JsonSchema>;
410
+ $schema?: string;
411
+ $id?: string;
412
+ $anchor?: string;
413
+ /**
414
+ * OpenAPI's nullability spelling, which is not JSON Schema's. It is declared because
415
+ * `response-schema-validator.ts` READS it (`schemaPermitsNull`) -- Google's schema dialect is
416
+ * OpenAPI-derived, so a schema that reaches the validator can carry it. No dialect in `compile.ts`
417
+ * writes or rewrites it; the canonical spelling this compiler emits is `type: ['x', 'null']`.
418
+ */
419
+ nullable?: boolean;
420
+ [key: string]: unknown;
421
+ }
383
422
 
384
423
  declare const ResourceGovernanceStatusSchema: z.ZodEnum<{
385
424
  active: "active";
@@ -923,16 +962,86 @@ interface LLMMessage {
923
962
  */
924
963
  interface LLMGenerateRequest {
925
964
  messages: LLMMessage[];
926
- responseSchema: unknown;
965
+ /**
966
+ * JSON Schema for structured output. Omit it for an unstructured call.
967
+ *
968
+ * Absence is what turns validation off: `runGeneratePipeline` skips `validateResponseSchema`
969
+ * entirely when this is missing, whatever `validationSchema` holds.
970
+ *
971
+ * This was declared `responseSchema: unknown` -- required, and typed as nothing. `unknown` admits
972
+ * `undefined`, so "required" only ever forced the KEY to be written, and `createLLMCallTool`
973
+ * writes it as `undefined` on every call where the model supplies no usable schema. There was no
974
+ * type error available for that, and three separate layers re-derived the same nullability at
975
+ * runtime under three different rules -- truthiness in the pipeline, an object check in the
976
+ * validator, and a `'type'`-key check in the tool. Because the pipeline's was truthiness, `null`,
977
+ * `0` and `''` all quietly meant "no structured output" while the type insisted a schema was
978
+ * mandatory. Optional-and-typed is what those three were compensating for.
979
+ */
980
+ responseSchema?: JsonSchema;
927
981
  /** Maximum output tokens per LLM call. NOT the model's context window — see ModelInfo.maxTokens for that. */
928
982
  maxOutputTokens?: number;
929
983
  temperature?: number;
930
984
  topP?: number;
931
985
  signal?: AbortSignal;
986
+ /**
987
+ * Caller-supplied acceptance step (Wave D2b / decision A15). A pipeline-aware adapter
988
+ * (`UniversalLLMAdapter`, via `runGeneratePipeline`) runs this once per retry attempt, right
989
+ * after the response has passed `responseSchema` validation. Throw to reject the attempt --
990
+ * rejection is classified exactly like a thrown `LLMResponseParseError` from
991
+ * `validateResponseSchema`: retryable, no circuit-breaker verdict, and the attempt is recorded as
992
+ * a failure (`ai_calls` validation-failure row) rather than a clean success. Returning normally
993
+ * (including `undefined`) accepts the response.
994
+ *
995
+ * Optional, and a HINT rather than a dependency -- an adapter that does not read this field
996
+ * simply ignores it, so a caller must not assume it ran:
997
+ * - A bare test-stub `LLMAdapter` (many exist in this codebase) does not invoke it.
998
+ * - `PostMessageLLMAdapter` (`packages/sdk/src/worker/llm-adapter.ts`) cannot forward it at all --
999
+ * functions cannot be structured-cloned across the worker `postMessage` boundary, so its
1000
+ * `params` object is built from an explicit allowlist that omits `accept`. The field is dropped
1001
+ * before `postMessage` is ever called (no `DataCloneError`), and the parent-side handler that
1002
+ * fulfils the call (`tool-dispatcher.ts`'s `case 'llm'`) rebuilds its own `LLMGenerateRequest`
1003
+ * from that allowlisted payload, so there is nothing to forward even in principle. This is the
1004
+ * path every deployed org-bundle agent and the `command-center-assistant` static module run
1005
+ * through today -- `accept` does not reach their retry loop.
1006
+ *
1007
+ * This is not a validation mechanism on its own: it does not decide whether output is acceptable,
1008
+ * the caller's function does, by throwing or not. `callLLMForAgentIteration`
1009
+ * (`execution/engine/agent/reasoning/adapters/agent-adapter-helpers.ts`) passes its Zod parse of
1010
+ * the iteration response as this field, so a malformed-but-schema-valid iteration is re-sampled
1011
+ * inside the retry loop instead of losing the turn -- for the in-process callers that can see it.
1012
+ */
1013
+ accept?: (output: unknown) => void;
1014
+ /**
1015
+ * The schema the RESPONSE is validated against, when that must differ from the schema the
1016
+ * provider was asked to sample against. Defaults to `responseSchema` when omitted.
1017
+ *
1018
+ * **This does not affect what is sent to the provider.** `responseSchema` remains the only schema
1019
+ * an adapter puts on the wire; this one is read solely by `runGeneratePipeline`'s validation step.
1020
+ * Whether validation happens at all is still decided by `responseSchema` -- a request with no
1021
+ * `responseSchema` is unstructured and stays unvalidated, whatever this field holds.
1022
+ *
1023
+ * A caller may legitimately ACCEPT A SUPERSET of what it ASKS FOR -- a document that validates a
1024
+ * response more leniently than the one the provider was asked to sample against. No caller in this
1025
+ * codebase supplies one today (agent iterations validate with a single Zod parse instead, see
1026
+ * `agent-adapter-helpers.ts`), but the mechanism stays: `validateResponseSchema` does not descend
1027
+ * into `anyOf`/`oneOf` regardless of which document is supplied here, so this field only ever
1028
+ * changes which top-level/required/type keywords are checked, never which acceptance contract a
1029
+ * union is read as.
1030
+ *
1031
+ * Unlike `accept` above, this is DATA. It is structured-cloneable, so it survives the worker
1032
+ * `postMessage` boundary that drops `accept`: `PostMessageLLMAdapter` forwards it in its params
1033
+ * allowlist and `tool-dispatcher.ts`'s `case 'llm'` puts it back on the `LLMGenerateRequest` it
1034
+ * rebuilds parent-side. That is why a divergence expressible as a schema belongs here rather than
1035
+ * in a callback -- deployed org-bundle agents run on the far side of that boundary.
1036
+ */
1037
+ validationSchema?: JsonSchema;
932
1038
  }
933
1039
  /**
934
1040
  * Generic LLM generation response
935
- * Usage field is internal-only (stripped by UniversalLLMAdapter wrapper)
1041
+ * `usage`, `cost`, `strictStatus` and `strictRefusalReasons` are observability fields. They are
1042
+ * **read** by `UniversalLLMAdapter` and lifted onto the `ai_calls` row; they are **not removed**.
1043
+ * The wrapper returns the base adapter's response object as-is, so a caller can observe all four.
1044
+ * Earlier revisions of this file claimed they were stripped — they never were.
936
1045
  */
937
1046
  interface LLMGenerateResponse<T = unknown> {
938
1047
  output: T;
@@ -940,35 +1049,53 @@ interface LLMGenerateResponse<T = unknown> {
940
1049
  inputTokens: number;
941
1050
  outputTokens: number;
942
1051
  totalTokens: number;
1052
+ /**
1053
+ * Anthropic-only: input tokens served from the prompt cache (`cache_read_input_tokens`), billed
1054
+ * at 0.1x the base input rate. Optional so OpenAI/OpenRouter usage objects, which never report
1055
+ * this, stay valid -- absent means "this provider doesn't report it," not "zero were read."
1056
+ */
1057
+ cacheReadInputTokens?: number;
1058
+ /**
1059
+ * Anthropic-only: input tokens written to the prompt cache this call
1060
+ * (`cache_creation_input_tokens`), billed at 1.25x the base input rate. Same optionality
1061
+ * rationale as `cacheReadInputTokens`.
1062
+ */
1063
+ cacheCreationInputTokens?: number;
943
1064
  };
944
1065
  cost?: number;
945
1066
  /**
946
- * What actually happened to `strict` on the request that produced this response. Every server
947
- * adapter sets it on every call, so the value is a statement rather than an inference:
1067
+ * What actually happened to `strict` on the request that produced this response.
948
1068
  *
949
1069
  * - `applied` — the request carried `strict: true` and the grammar was in effect
950
- * - `refused` — `toStrictSchema` could not express the schema, so the request went out unstrict
951
- * - `compileRejected` — the schema passed `toStrictSchema` but the provider's grammar compiler
1070
+ * - `refused` — `compileSchema` could not express the schema, so the request went out unstrict
1071
+ * - `compileRejected` — the schema passed `compileSchema` but the provider's grammar compiler
952
1072
  * rejected it at request time, and the call was retried unstrict
953
- * - `notAttempted` — this adapter does not send strict at all (OpenAI, Google, OpenRouter)
1073
+ * - `notAttempted` — the adapter did not send `strict` on this call
954
1074
  *
955
1075
  * This exists because `strictRefusalReasons` alone cannot answer the question. Its absence means
956
1076
  * "strict held" OR "nothing ever tried", and a prod run that recorded zero refusals while
957
1077
  * returning an array-typed field as a string is exactly the case where the difference matters.
958
1078
  *
959
- * Internal-only, like `usage` `UniversalLLMAdapter` lifts it onto the `ai_calls` row and
960
- * strips it before the response reaches callers.
1079
+ * **Do not read this as "provider X never sends strict."** It describes one call, not an adapter.
1080
+ * A previous revision of this comment enumerated OpenAI, Google and OpenRouter as adapters that
1081
+ * never send `strict`, which was false for OpenRouter — it sends `strict: true` whenever the
1082
+ * schema compiles, and separately reports `notAttempted`. That producer bug is still live; the
1083
+ * fix is to make the value a return of schema compilation rather than a per-adapter literal.
1084
+ * `MockAdapter` sets no value at all, so absence does not imply `notAttempted` either.
1085
+ *
1086
+ * Observability only — `UniversalLLMAdapter` lifts it onto the `ai_calls` row. It is not removed
1087
+ * from the response.
961
1088
  */
962
1089
  strictStatus?: StrictStatus;
963
1090
  /**
964
1091
  * Why this call went out WITHOUT `strict`, on an adapter that tried to send it with one.
965
1092
  *
966
1093
  * The detail behind a `refused` / `compileRejected` `strictStatus` — the short, stable reason
967
- * strings `toStrictSchema` computes. Read `strictStatus` to answer "was it enforced"; read this
1094
+ * strings `compileSchema` computes. Read `strictStatus` to answer "was it enforced"; read this
968
1095
  * to answer "why not".
969
1096
  *
970
- * Internal-only, like `usage` — `UniversalLLMAdapter` lifts it onto the `ai_calls` row and
971
- * strips it before the response reaches callers.
1097
+ * Observability only — `UniversalLLMAdapter` lifts it onto the `ai_calls` row. It is not removed
1098
+ * from the response.
972
1099
  */
973
1100
  strictRefusalReasons?: string[];
974
1101
  }
@@ -1001,7 +1128,7 @@ interface LLMAdapter {
1001
1128
  * Use-case agnostic types that describe the purpose of each entry
1002
1129
  * Memory types mirror action types for clarity and filtering
1003
1130
  */
1004
- type MemoryEntryType = 'context' | 'input' | 'reasoning' | 'tool-result' | 'delegation-result' | 'error';
1131
+ type MemoryEntryType = 'context' | 'input' | 'reasoning' | 'tool-result' | 'error';
1005
1132
  /**
1006
1133
  * Who authored an entry's content.
1007
1134
  *
@@ -1030,6 +1157,14 @@ interface MemoryEntry {
1030
1157
  * starting the agent with empty memory rather than throwing.
1031
1158
  */
1032
1159
  source?: MemoryEntrySource;
1160
+ /**
1161
+ * Which tool produced this entry. Set on `tool-result` entries so the model can tell N parallel
1162
+ * results apart -- the framework instructs batching independent tool calls in one iteration, and
1163
+ * an anonymous result is unattributable the moment two land in the same iteration. `addToolError`
1164
+ * already carries this (folded into its `content` JSON); this is the same fact for the success
1165
+ * path, carried as a real field instead of prose the caller has to parse back out.
1166
+ */
1167
+ toolName?: string;
1033
1168
  }
1034
1169
  /**
1035
1170
  * Agent memory - Self-orchestrated memory with session + working storage
@@ -1056,7 +1191,6 @@ interface AgentMemory {
1056
1191
  interface MemoryStatus {
1057
1192
  sessionMemoryKeys: number;
1058
1193
  sessionMemoryLimit: number;
1059
- currentKeys: string[];
1060
1194
  sessionMemoryTokens: number;
1061
1195
  sessionMemoryTokenLimit: number;
1062
1196
  /**
@@ -1065,10 +1199,26 @@ interface MemoryStatus {
1065
1199
  * read as history pressure and triggered history compaction that could not relieve it.
1066
1200
  */
1067
1201
  historyPercent: number;
1202
+ /**
1203
+ * Tokens the history entries **in scope for the requested turn** occupy — the same set
1204
+ * `toContextParts` puts in the envelope. Equal to `storedHistoryTokens` when `getStatus` is
1205
+ * called without a turn.
1206
+ *
1207
+ * This is the number the model is shown, and it is scoped because the model is handed a scoped
1208
+ * set. Counting the whole cross-turn array here meant the framing quoted the size of a store
1209
+ * while the envelope beside it carried one turn's worth of it.
1210
+ */
1068
1211
  historyTokens: number;
1212
+ /**
1213
+ * Tokens the **entire** history array occupies, across every turn the session snapshot restored.
1214
+ *
1215
+ * This is what compaction measures, because compaction trims that array. Scoping it to a turn
1216
+ * would let the store grow without bound whenever the current turn happened to be small.
1217
+ */
1218
+ storedHistoryTokens: number;
1219
+ /** `storedHistoryTokens` as a percentage of `historyBudget`. The auto-compaction trigger. */
1220
+ storedHistoryPercent: number;
1069
1221
  historyBudget: number;
1070
- totalTokens: number;
1071
- tokenBudget: number;
1072
1222
  }
1073
1223
  /**
1074
1224
  * Memory constraints (optional limits)
@@ -1150,6 +1300,14 @@ declare class MemoryManager {
1150
1300
  * are not. Eviction is oldest-first by timestamp, matching the key-count path, and always
1151
1301
  * leaves at least one entry so a single oversized key degrades to "one key" rather than to
1152
1302
  * "memory silently emptied".
1303
+ *
1304
+ * The running total is **recomputed** from the survivors rather than decremented per entry.
1305
+ * `getStatus` estimates the pool as a ceiling of the joined sum, and a per-entry decrement is a
1306
+ * sum of ceilings — the larger of the two by up to one token per key. The running total therefore
1307
+ * fell faster than the pool did, and the loop could exit reporting a fit while the very next
1308
+ * `getStatus` still read over the limit. Recomputing makes the loop's exit condition and the
1309
+ * number it is judged by the same expression. The pool is capped at `MAX_SESSION_MEMORY_KEYS`
1310
+ * entries, so the extra passes are bounded and cheap.
1153
1311
  */
1154
1312
  private enforceSessionMemoryTokenLimit;
1155
1313
  /**
@@ -1159,9 +1317,13 @@ declare class MemoryManager {
1159
1317
  getHistoryLength(): number;
1160
1318
  /**
1161
1319
  * Get memory status for agent awareness
1320
+ *
1321
+ * @param currentTurn - Turn to scope `historyTokens` / `historyPercent` to. Omit to measure the
1322
+ * whole store, which is what the compaction paths want. Callers building something the model
1323
+ * reads should pass it, so the count describes the set the model is actually handed.
1162
1324
  * @returns Memory status with token usage and key counts
1163
1325
  */
1164
- getStatus(): MemoryStatus;
1326
+ getStatus(currentTurn?: number): MemoryStatus;
1165
1327
  /**
1166
1328
  * Create memory snapshot for persistence
1167
1329
  * Caches snapshot internally for later retrieval
@@ -1200,87 +1362,6 @@ declare class MemoryManager {
1200
1362
  toContextParts(currentIteration: number, currentTurn?: number): MemoryContextParts;
1201
1363
  }
1202
1364
 
1203
- /**
1204
- * Knowledge Map Types
1205
- *
1206
- * Enables agents to navigate organizational knowledge through a lightweight
1207
- * graph that lazy-loads capabilities on-demand.
1208
- *
1209
- * @module agent/knowledge-map
1210
- */
1211
-
1212
- /**
1213
- * Lightweight knowledge map (passed as agent property)
1214
- *
1215
- * Contains metadata about available knowledge nodes without loading
1216
- * the full content upfront. Total size: ~300-500 tokens.
1217
- *
1218
- * Multi-tenancy is enforced via:
1219
- * - File-scoped maps (organizations/{org-name}/knowledge/)
1220
- * - ExecutionContext.organizationId passed to node.load()
1221
- */
1222
- interface KnowledgeMap {
1223
- /** Available knowledge nodes indexed by ID */
1224
- nodes: Record<string, KnowledgeNode>;
1225
- }
1226
- /**
1227
- * Single knowledge source
1228
- *
1229
- * Represents a domain knowledge area (CRM, brand guidelines, Excel tools)
1230
- * that can be lazy-loaded to provide instructions and tools to agents.
1231
- */
1232
- interface KnowledgeNode {
1233
- /** Unique identifier for this node (e.g., "crm", "brand-guidelines") */
1234
- id: string;
1235
- /**
1236
- * Description of when to use this knowledge
1237
- * Used for semantic matching against user intent
1238
- */
1239
- description: string;
1240
- /**
1241
- * Load knowledge content on-demand
1242
- *
1243
- * @param context - Execution context with organizationId for multi-tenancy
1244
- * @returns Promise resolving to knowledge content (prompt + optional tools)
1245
- */
1246
- load(context: ExecutionContext): Promise<KnowledgeContent>;
1247
- /**
1248
- * Loaded state flag
1249
- * Set to true after load() is called
1250
- */
1251
- loaded?: boolean;
1252
- /**
1253
- * Cached prompt (for system prompt serialization)
1254
- * Only the prompt is cached - tools go to toolRegistry, children flattened to nodes
1255
- */
1256
- prompt?: string;
1257
- }
1258
- /**
1259
- * Content returned by knowledge node
1260
- *
1261
- * Separates instructions (prompt) from capabilities (tools).
1262
- * Tools are optional - some nodes only provide context.
1263
- *
1264
- * Supports recursive navigation - nodes can contain child nodes
1265
- * that are discovered when the parent node is loaded.
1266
- */
1267
- interface KnowledgeContent {
1268
- /** Instructions and context (markdown format) */
1269
- prompt: string;
1270
- /** Tool implementations (optional) */
1271
- tools?: Tool[];
1272
- /**
1273
- * Child knowledge nodes (optional, recursive)
1274
- *
1275
- * Enables hierarchical navigation: base → specialized → deep expertise.
1276
- * Child nodes are flattened into the main knowledge map when parent loads,
1277
- * making them available for subsequent navigate-knowledge actions.
1278
- *
1279
- * Example: CRM base node returns crm-customers and crm-deals as children
1280
- */
1281
- nodes?: Record<string, KnowledgeNode>;
1282
- }
1283
-
1284
1365
  /**
1285
1366
  * Agent-specific type definitions
1286
1367
  * Types for autonomous agents with tools, memory, and constraints
@@ -1357,11 +1438,6 @@ interface AgentDefinition {
1357
1438
  * Specifies provider, API key, and model-specific options
1358
1439
  */
1359
1440
  modelConfig: ModelConfig;
1360
- /**
1361
- * Optional knowledge map for lazy-loading capabilities
1362
- * Enables agents to navigate organizational knowledge on-demand
1363
- */
1364
- knowledgeMap?: KnowledgeMap;
1365
1441
  /**
1366
1442
  * Preload memory before execution starts
1367
1443
  * Handles BOTH context loading AND session restoration
@@ -1395,7 +1471,6 @@ interface IterationContext {
1395
1471
  logger: AgentScopedLogger;
1396
1472
  modelConfig: ModelConfig;
1397
1473
  adapterFactory: LLMAdapterFactory;
1398
- knowledgeMap?: KnowledgeMap;
1399
1474
  /**
1400
1475
  * The validated input for this execution, serialized. It travels here because the model gets
1401
1476
  * it as its own `role:'user'` message; nothing else in this context carried it, so the input
@@ -2731,6 +2806,17 @@ interface BaseAICall {
2731
2806
  costUsd: number;
2732
2807
  latencyMs: number;
2733
2808
  context?: AICallContext;
2809
+ /**
2810
+ * Anthropic-only: input tokens served from the prompt cache this call (`cache_read_input_tokens`),
2811
+ * billed at 0.1x the base input rate. Already folded into `inputTokens`/`totalInputTokens` so
2812
+ * aggregate totals reflect real usage -- present here as the raw breakdown, not additive on top.
2813
+ */
2814
+ cacheReadInputTokens?: number;
2815
+ /**
2816
+ * Anthropic-only: input tokens written to the prompt cache this call (`cache_creation_input_tokens`),
2817
+ * billed at 1.25x the base input rate. Same folding rationale as `cacheReadInputTokens`.
2818
+ */
2819
+ cacheCreationInputTokens?: number;
2734
2820
  /**
2735
2821
  * Distinct prompt-injection pattern types detected in the request's user-role messages.
2736
2822
  * Present only when the input sanitizer matched something. Non-blocking matches ride along on
@@ -2796,6 +2882,41 @@ interface BaseAICall {
2796
2882
  * Existing readers that only look at the fields above are unaffected.
2797
2883
  */
2798
2884
  strictRefusalReasons?: string[];
2885
+ /**
2886
+ * Time spent in the base adapter's `generate()` call alone, excluding `responseSchema`
2887
+ * validation. On a success or validation-failure row, `providerMs + validateMs === latencyMs`
2888
+ * (modulo rounding) -- `latencyMs` keeps its existing meaning unchanged; this and `validateMs`
2889
+ * are the same window split into its two components.
2890
+ *
2891
+ * Present on success and validation-failure rows. Absent on a blocked row (no provider call was
2892
+ * made) and on rows written before this field existed.
2893
+ */
2894
+ providerMs?: number;
2895
+ /**
2896
+ * Time spent in `validateResponseSchema` alone. Omitted when the call carried no `responseSchema`
2897
+ * (nothing to validate); `0` is a legitimate value meaning a schema was supplied and validation
2898
+ * was effectively instant. See `providerMs` for how the two relate to `latencyMs`.
2899
+ *
2900
+ * Present on success and validation-failure rows that supplied a `responseSchema`. Absent on a
2901
+ * blocked row and on rows written before this field existed.
2902
+ */
2903
+ validateMs?: number;
2904
+ /**
2905
+ * Total elapsed time for the WHOLE `generate()` call -- every retry attempt plus every backoff
2906
+ * sleep between them. Unlike `latencyMs` (which is per-attempt and never includes backoff, by
2907
+ * design -- see `runWithRetry`), this is the one number that answers "how long did the caller
2908
+ * actually wait". On a call that never retried, `wallClockMs === latencyMs`. On a retried call,
2909
+ * `wallClockMs` is strictly greater than any individual row's `latencyMs` from that same call, by
2910
+ * at least the backoff time actually slept.
2911
+ *
2912
+ * The same value is attached to every row produced by one `generate()` call (a validation-failure
2913
+ * row from an earlier attempt included), because it describes the call, not the attempt.
2914
+ *
2915
+ * Present on success and validation-failure rows. Absent on a blocked row -- a blocked call never
2916
+ * reaches the retry loop, so `wallClockMs` would just restate `latencyMs` (0). Absent on rows
2917
+ * written before this field existed.
2918
+ */
2919
+ wallClockMs?: number;
2799
2920
  }
2800
2921
  type AICallContext = AgentReasoningContext | AgentCompletionContext | WorkflowStepContext | ToolCallContext | OtherCallContext;
2801
2922
  interface AgentReasoningContext {
@@ -2841,6 +2962,16 @@ interface LLMUsageData {
2841
2962
  latencyMs: number;
2842
2963
  /** Actual cost from provider in USD (when available, e.g., OpenRouter) */
2843
2964
  cost?: number;
2965
+ /**
2966
+ * Anthropic-only: input tokens served from the prompt cache (`cache_read_input_tokens`), billed at
2967
+ * 0.1x the base input rate. Absent for providers that never report it (OpenAI, OpenRouter).
2968
+ */
2969
+ cacheReadInputTokens?: number;
2970
+ /**
2971
+ * Anthropic-only: input tokens written to the prompt cache this call
2972
+ * (`cache_creation_input_tokens`), billed at 1.25x the base input rate. Same absence rationale.
2973
+ */
2974
+ cacheCreationInputTokens?: number;
2844
2975
  /** Distinct prompt-injection pattern types detected in the request's user-role messages */
2845
2976
  inputWarnings?: string[];
2846
2977
  /** Additive per-source breakdown of `inputWarnings` — see `SourcedInputWarnings` */
@@ -2855,6 +2986,12 @@ interface LLMUsageData {
2855
2986
  strictStatus?: StrictStatus;
2856
2987
  /** Why the call went out unstrict, when a strict-capable adapter refused the schema */
2857
2988
  strictRefusalReasons?: string[];
2989
+ /** Time in the base adapter's `generate()` alone, excluding `responseSchema` validation. See `BaseAICall.providerMs`. */
2990
+ providerMs?: number;
2991
+ /** Time in `validateResponseSchema` alone. Omitted when no `responseSchema` was supplied. See `BaseAICall.validateMs`. */
2992
+ validateMs?: number;
2993
+ /** Total elapsed for the whole `generate()` call, including every retry and every backoff sleep. See `BaseAICall.wallClockMs`. */
2994
+ wallClockMs?: number;
2858
2995
  }
2859
2996
  interface AIUsageSummary {
2860
2997
  model: LLMModel;