@namzu/sdk 62.4.0 → 62.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +1 -1
  3. package/dist/agents/QueryAgent.d.ts.map +1 -1
  4. package/dist/agents/QueryAgent.js +3 -0
  5. package/dist/agents/QueryAgent.js.map +1 -1
  6. package/dist/agents/file-definitions.d.ts +1 -1
  7. package/dist/agents/file-definitions.js +1 -1
  8. package/dist/agents/runAgent.d.ts +4 -2
  9. package/dist/agents/runAgent.d.ts.map +1 -1
  10. package/dist/agents/runAgent.js +2 -1
  11. package/dist/agents/runAgent.js.map +1 -1
  12. package/dist/bridge/a2a/mapper.d.ts.map +1 -1
  13. package/dist/bridge/a2a/mapper.js +5 -3
  14. package/dist/bridge/a2a/mapper.js.map +1 -1
  15. package/dist/compaction/model-summary.d.ts.map +1 -1
  16. package/dist/compaction/model-summary.js +2 -1
  17. package/dist/compaction/model-summary.js.map +1 -1
  18. package/dist/compaction/verifier.d.ts.map +1 -1
  19. package/dist/compaction/verifier.js +2 -1
  20. package/dist/compaction/verifier.js.map +1 -1
  21. package/dist/eval/judge.d.ts.map +1 -1
  22. package/dist/eval/judge.js +2 -1
  23. package/dist/eval/judge.js.map +1 -1
  24. package/dist/pricing/catalogue.generated.d.ts.map +1 -1
  25. package/dist/pricing/catalogue.generated.js +24 -0
  26. package/dist/pricing/catalogue.generated.js.map +1 -1
  27. package/dist/provider/fallback.d.ts.map +1 -1
  28. package/dist/provider/fallback.js +23 -1
  29. package/dist/provider/fallback.js.map +1 -1
  30. package/dist/public-runtime.d.ts +1 -1
  31. package/dist/public-runtime.d.ts.map +1 -1
  32. package/dist/public-runtime.js +1 -1
  33. package/dist/public-runtime.js.map +1 -1
  34. package/dist/runtime/query/auto-review/classifier.d.ts.map +1 -1
  35. package/dist/runtime/query/auto-review/classifier.js +2 -1
  36. package/dist/runtime/query/auto-review/classifier.js.map +1 -1
  37. package/dist/runtime/query/index.d.ts +21 -0
  38. package/dist/runtime/query/index.d.ts.map +1 -1
  39. package/dist/runtime/query/index.js +4 -0
  40. package/dist/runtime/query/index.js.map +1 -1
  41. package/dist/runtime/query/iteration/index.d.ts +10 -0
  42. package/dist/runtime/query/iteration/index.d.ts.map +1 -1
  43. package/dist/runtime/query/iteration/index.js +62 -6
  44. package/dist/runtime/query/iteration/index.js.map +1 -1
  45. package/dist/runtime/query/iteration/phases/context.d.ts +4 -0
  46. package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
  47. package/dist/runtime/query/iteration/phases/context.js.map +1 -1
  48. package/dist/runtime/query/iteration/request-repair.d.ts +9 -1
  49. package/dist/runtime/query/iteration/request-repair.d.ts.map +1 -1
  50. package/dist/runtime/query/iteration/request-repair.js +29 -0
  51. package/dist/runtime/query/iteration/request-repair.js.map +1 -1
  52. package/dist/runtime/query/iteration/side-call.d.ts +16 -0
  53. package/dist/runtime/query/iteration/side-call.d.ts.map +1 -0
  54. package/dist/runtime/query/iteration/side-call.js +50 -0
  55. package/dist/runtime/query/iteration/side-call.js.map +1 -0
  56. package/dist/runtime/query/iteration/step-shaping.d.ts.map +1 -1
  57. package/dist/runtime/query/iteration/step-shaping.js +3 -0
  58. package/dist/runtime/query/iteration/step-shaping.js.map +1 -1
  59. package/dist/runtime/query/prepare-turn.d.ts.map +1 -1
  60. package/dist/runtime/query/prepare-turn.js +5 -2
  61. package/dist/runtime/query/prepare-turn.js.map +1 -1
  62. package/dist/runtime/query/request-rich-content.d.ts +7 -1
  63. package/dist/runtime/query/request-rich-content.d.ts.map +1 -1
  64. package/dist/runtime/query/request-rich-content.js +8 -2
  65. package/dist/runtime/query/request-rich-content.js.map +1 -1
  66. package/dist/turn/index.d.ts +1 -1
  67. package/dist/turn/index.d.ts.map +1 -1
  68. package/dist/turn/index.js +1 -1
  69. package/dist/turn/index.js.map +1 -1
  70. package/dist/turn/memory-recall.d.ts +13 -0
  71. package/dist/turn/memory-recall.d.ts.map +1 -1
  72. package/dist/turn/memory-recall.js +38 -1
  73. package/dist/turn/memory-recall.js.map +1 -1
  74. package/dist/types/agent/base.d.ts +2 -0
  75. package/dist/types/agent/base.d.ts.map +1 -1
  76. package/dist/types/agent/query.d.ts +4 -0
  77. package/dist/types/agent/query.d.ts.map +1 -1
  78. package/dist/types/common/index.d.ts +38 -0
  79. package/dist/types/common/index.d.ts.map +1 -1
  80. package/dist/types/common/index.js +21 -2
  81. package/dist/types/common/index.js.map +1 -1
  82. package/dist/types/provider/chat.d.ts +10 -0
  83. package/dist/types/provider/chat.d.ts.map +1 -1
  84. package/dist/types/provider/config.d.ts +8 -0
  85. package/dist/types/provider/config.d.ts.map +1 -1
  86. package/dist/types/provider/index.d.ts +1 -1
  87. package/dist/types/provider/index.d.ts.map +1 -1
  88. package/dist/types/session/config.d.ts +10 -0
  89. package/dist/types/session/config.d.ts.map +1 -1
  90. package/dist/types/session/events.d.ts +18 -1
  91. package/dist/types/session/events.d.ts.map +1 -1
  92. package/dist/types/session/events.js.map +1 -1
  93. package/dist/types/session/prepare-step.d.ts +7 -0
  94. package/dist/types/session/prepare-step.d.ts.map +1 -1
  95. package/dist/utils/cost.d.ts +13 -0
  96. package/dist/utils/cost.d.ts.map +1 -1
  97. package/dist/utils/cost.js +34 -0
  98. package/dist/utils/cost.js.map +1 -1
  99. package/package.json +2 -2
  100. package/src/agents/QueryAgent.ts +3 -0
  101. package/src/agents/file-definitions.ts +1 -1
  102. package/src/agents/runAgent.ts +10 -2
  103. package/src/bridge/a2a/mapper.ts +5 -3
  104. package/src/compaction/model-summary.ts +2 -1
  105. package/src/compaction/verifier.ts +2 -1
  106. package/src/eval/judge.ts +2 -1
  107. package/src/pricing/catalogue.generated.ts +24 -0
  108. package/src/pricing/rates.source.json +22 -5
  109. package/src/provider/fallback.ts +33 -1
  110. package/src/public-runtime.ts +1 -1
  111. package/src/runtime/query/auto-review/classifier.ts +2 -1
  112. package/src/runtime/query/index.ts +27 -0
  113. package/src/runtime/query/iteration/index.ts +73 -5
  114. package/src/runtime/query/iteration/phases/context.ts +4 -0
  115. package/src/runtime/query/iteration/request-repair.ts +42 -1
  116. package/src/runtime/query/iteration/side-call.ts +60 -0
  117. package/src/runtime/query/iteration/step-shaping.ts +3 -0
  118. package/src/runtime/query/prepare-turn.ts +6 -2
  119. package/src/runtime/query/request-rich-content.ts +11 -2
  120. package/src/turn/index.ts +1 -1
  121. package/src/turn/memory-recall.ts +40 -0
  122. package/src/types/agent/base.ts +2 -0
  123. package/src/types/agent/query.ts +4 -0
  124. package/src/types/common/index.ts +65 -2
  125. package/src/types/provider/chat.ts +12 -0
  126. package/src/types/provider/config.ts +8 -0
  127. package/src/types/provider/index.ts +1 -0
  128. package/src/types/session/config.ts +11 -0
  129. package/src/types/session/events.ts +15 -1
  130. package/src/types/session/prepare-step.ts +7 -0
  131. package/src/utils/cost.ts +49 -0
@@ -332,8 +332,13 @@ export async function prepareTurn(params: QueryParams): Promise<PreparedTurn> {
332
332
  const promptCache = params.promptCache
333
333
  const taskScheduler = params.taskScheduler
334
334
  const streamIdleTimeoutMs = resolveStreamIdleTimeoutMs(params.turnConfig.streamIdleTimeoutMs)
335
- const maxRequestRichContentBytes = resolveMaxRequestRichContentBytes(
335
+ // Validated here, at the door, but only the caller's own override is kept on
336
+ // the turn: the provider's declaration is read where it is used (see
337
+ // `IterationOrchestrator.richContentBudget`), so it follows the provider
338
+ // that serves the turn rather than being pinned by the first one.
339
+ resolveMaxRequestRichContentBytes(
336
340
  params.turnConfig.maxRequestRichContentBytes,
341
+ params.provider.capabilities?.maxRequestRichContentBytes,
337
342
  )
338
343
  const sandboxTeardownTimeoutMs = resolveSandboxTeardownTimeoutMs(params.sandboxTeardownTimeoutMs)
339
344
  // Persist the EFFECTIVE value, not only an override. A turn replayed after a
@@ -343,7 +348,6 @@ export async function prepareTurn(params: QueryParams): Promise<PreparedTurn> {
343
348
  const turnConfig: TurnConfig = {
344
349
  ...params.turnConfig,
345
350
  streamIdleTimeoutMs,
346
- maxRequestRichContentBytes,
347
351
  }
348
352
 
349
353
  // The turn's one correlated logger, built before anything below needs
@@ -12,8 +12,17 @@ export const DEFAULT_MAX_REQUEST_RICH_CONTENT_BYTES = 24 * 1024 * 1024
12
12
 
13
13
  const MAX_REQUEST_RICH_CONTENT_BYTES = Number.MAX_SAFE_INTEGER
14
14
 
15
- export function resolveMaxRequestRichContentBytes(value: number | undefined): number {
16
- const resolved = value ?? DEFAULT_MAX_REQUEST_RICH_CONTENT_BYTES
15
+ /**
16
+ * The budget for one turn: the caller's `turnConfig.maxRequestRichContentBytes`
17
+ * when set, else the one the provider declares for its own wire limit
18
+ * (`ProviderCapabilities.maxRequestRichContentBytes`), else the kernel default.
19
+ * The override always wins, so a host can tighten or loosen what a driver declares.
20
+ */
21
+ export function resolveMaxRequestRichContentBytes(
22
+ value: number | undefined,
23
+ providerDeclared?: number,
24
+ ): number {
25
+ const resolved = value ?? providerDeclared ?? DEFAULT_MAX_REQUEST_RICH_CONTENT_BYTES
17
26
  if (
18
27
  !Number.isSafeInteger(resolved) ||
19
28
  resolved < 0 ||
package/src/turn/index.ts CHANGED
@@ -23,7 +23,7 @@ export type { LimitCheckerState, LimitCheckResult } from './LimitChecker.js'
23
23
 
24
24
  export { SESSION_MEMORY_TAG, createMemoryPromoter } from './memory-promoter.js'
25
25
  export type { MemoryPromoterOptions, SessionMemoryCategory } from './memory-promoter.js'
26
- export { createMemoryRecallStep } from './memory-recall.js'
26
+ export { createMemoryRecallStep, recalledMemoryIds } from './memory-recall.js'
27
27
  export type {
28
28
  MemoryRecallOptions,
29
29
  MemorySelection,
@@ -80,6 +80,12 @@ export interface MemoryRecallOptions {
80
80
  readonly minCoverage?: number
81
81
  /** Upper bound on the selector, in ms; the signal it is given aborts then. Default 2,500. */
82
82
  readonly selectTimeoutMs?: number
83
+ /**
84
+ * Ids recall must not offer, read afresh on every request. A host keeps a
85
+ * set-aside list here (records a refused request carried) and lifts it when
86
+ * the person restores a record. A throw reads as an empty list.
87
+ */
88
+ readonly excluded?: () => Iterable<string> | Promise<Iterable<string>>
83
89
  }
84
90
 
85
91
  /** What a selector may know about a record: never its body. */
@@ -126,6 +132,27 @@ const OTHERS_PLURAL = (count: number): string =>
126
132
  export const RECALLED_MEMORY_ENTRY_KEY = 'memory'
127
133
 
128
134
  /** The `id@updatedAt` of every record the entries still in the history carry. */
135
+ /**
136
+ * The ids of the records the `memory` entries carry, in the order they were
137
+ * recorded and without repeats. `entries` are bodies as `turnContextEntries`
138
+ * returns them.
139
+ */
140
+ export function recalledMemoryIds(entries: readonly string[]): string[] {
141
+ const ids = new Set<string>()
142
+ for (const entry of entries) {
143
+ for (const line of entry.split('\n')) {
144
+ if (!line.startsWith('{')) continue
145
+ try {
146
+ const parsed = JSON.parse(line) as { id?: unknown }
147
+ if (typeof parsed.id === 'string') ids.add(parsed.id)
148
+ } catch {
149
+ // a line of the entry that is not a record
150
+ }
151
+ }
152
+ }
153
+ return [...ids]
154
+ }
155
+
129
156
  function recordedRecords(entries: readonly string[]): Set<string> {
130
157
  const seen = new Set<string>()
131
158
  for (const entry of entries) {
@@ -377,8 +404,12 @@ export function createMemoryRecallStep(options: MemoryRecallOptions): PrepareSte
377
404
  latestUserMessage,
378
405
  contextBudget,
379
406
  signal,
407
+ withheldKeys,
380
408
  }) => {
381
409
  signal?.throwIfAborted()
410
+ // A refused request was re-run without the memories it carried; adding
411
+ // them again would be refused again.
412
+ if (withheldKeys?.includes(RECALLED_MEMORY_ENTRY_KEY)) return undefined
382
413
  // Leave room for the current request and response. The kernel supplies
383
414
  // an estimate; using one character per remaining token is deliberately
384
415
  // conservative for this optional text, not a billing/tokenizer claim.
@@ -484,6 +515,14 @@ export function createMemoryRecallStep(options: MemoryRecallOptions): PrepareSte
484
515
  }
485
516
  const recall = async (): Promise<Recalled> => {
486
517
  const shown: RecalledMemory[] = []
518
+ let excludedIds: ReadonlySet<string> = new Set()
519
+ if (options.excluded) {
520
+ try {
521
+ excludedIds = new Set(await options.excluded())
522
+ } catch {
523
+ // An unreadable list excludes nothing.
524
+ }
525
+ }
487
526
  const page = await options.store.list({
488
527
  query: terms.join(' '),
489
528
  status: 'active',
@@ -501,6 +540,7 @@ export function createMemoryRecallStep(options: MemoryRecallOptions): PrepareSte
501
540
  let block = lead
502
541
  const fresh = page.entries
503
542
  .filter((entry) => entry.status === 'active')
543
+ .filter((entry) => !excludedIds.has(entry.id))
504
544
  .filter((entry) => !known.has(`${entry.id}@${entry.updatedAt}`))
505
545
  const candidates = fresh.slice(0, shortlist)
506
546
  const picks = await choose(candidates)
@@ -226,6 +226,8 @@ export interface BaseAgentConfig {
226
226
  */
227
227
  thinking?: import('../provider/index.js').ThinkingConfig
228
228
  effort?: import('../provider/index.js').ReasoningEffort
229
+ /** Inference speed; see {@link import('../session/config.js').TurnConfig.speed}. */
230
+ speed?: import('../provider/index.js').InferenceSpeed
229
231
  /** How the turn bounds its reasoning; see {@link import('../session/config.js').TurnConfig.reasoning}. */
230
232
  reasoning?: import('../session/config.js').TurnConfig['reasoning']
231
233
  /** Ask once for a check of edits before a turn ends; see {@link import('../session/config.js').TurnConfig.completionAudit}. */
@@ -100,6 +100,10 @@ export interface QueryAgentConfig extends BaseAgentConfig {
100
100
  maxOutputContinuations?: QueryParams['maxOutputContinuations']
101
101
  /** See {@link QueryParams.refusalFallback}. */
102
102
  refusalFallback?: QueryParams['refusalFallback']
103
+ /** See {@link QueryParams.withholdOnRefusal}. */
104
+ withholdOnRefusal?: QueryParams['withholdOnRefusal']
105
+ /** See {@link QueryParams.withheldKeys}. */
106
+ withheldKeys?: QueryParams['withheldKeys']
103
107
  maxToolOutputChars?: number
104
108
  maxToolOutputCharsPerMessage?: number
105
109
  retainedToolPreviewChars?: QueryParams['retainedToolPreviewChars']
@@ -42,6 +42,50 @@ export interface TokenUsage {
42
42
  * {@link TokenUsage.cacheTtlMs}.
43
43
  */
44
44
  cacheWriteTtlTokens?: { fiveMin?: number; oneHour?: number }
45
+
46
+ /**
47
+ * The speed the provider says served this call, when it says. `'fast'` is a
48
+ * premium-priced mode, so pricing reads it per call: a per-call fact like
49
+ * {@link TokenUsage.cacheTtlMs}, never summed. Absent means standard or
50
+ * unreported.
51
+ */
52
+ speed?: import('../provider/chat.js').InferenceSpeed
53
+
54
+ /**
55
+ * Hosted web searches the provider ran for this call and bills per request.
56
+ * Unlike the per-call facts below it IS a count of work done, so it is
57
+ * summed across calls. Absent means the provider did not report one.
58
+ */
59
+ webSearchRequests?: number
60
+
61
+ /**
62
+ * The service tier the provider says served this call (`standard`,
63
+ * `priority`, `batch`). A per-call fact, never summed. Absent means
64
+ * unreported.
65
+ */
66
+ serviceTier?: string
67
+
68
+ /** The region the provider says ran this call, when it says. Per call, never summed. */
69
+ inferenceGeo?: string
70
+
71
+ /**
72
+ * Why the provider's prompt cache did not serve a prefix it had before, when
73
+ * it explains. Per call, never summed. Absent means no miss was explained: the
74
+ * provider reported nothing, a pending answer, or a hit.
75
+ */
76
+ cacheMiss?: CacheMiss
77
+ }
78
+
79
+ /** A prompt-cache miss as the provider explains it. See {@link TokenUsage.cacheMiss}. */
80
+ export interface CacheMiss {
81
+ /**
82
+ * The provider's own reason, e.g. `model_changed`, `system_changed`,
83
+ * `tools_changed`, `messages_changed`, `previous_message_not_found`,
84
+ * `unavailable`.
85
+ */
86
+ reason: string
87
+ /** Input tokens that missed the cache because of it, when the provider counts them. */
88
+ missedTokens?: number
45
89
  }
46
90
 
47
91
  export function accumulateTokenUsage(current: TokenUsage, addition: TokenUsage): TokenUsage {
@@ -58,8 +102,12 @@ export function accumulateTokenUsage(current: TokenUsage, addition: TokenUsage):
58
102
  ...(current.reasoningTokens !== undefined || addition.reasoningTokens !== undefined
59
103
  ? { reasoningTokens: (current.reasoningTokens ?? 0) + (addition.reasoningTokens ?? 0) }
60
104
  : {}),
61
- // `cacheTtlMs` and `cacheWriteTtlTokens` are per-call facts and are
62
- // deliberately not carried into a sum.
105
+ ...(current.webSearchRequests !== undefined || addition.webSearchRequests !== undefined
106
+ ? { webSearchRequests: (current.webSearchRequests ?? 0) + (addition.webSearchRequests ?? 0) }
107
+ : {}),
108
+ // `cacheTtlMs`, `cacheWriteTtlTokens`, `speed`, `serviceTier`,
109
+ // `inferenceGeo` and `cacheMiss` are per-call facts and are deliberately
110
+ // not carried into a sum.
63
111
  }
64
112
  }
65
113
 
@@ -101,6 +149,21 @@ export function mergeTokenUsage(current: TokenUsage, next: TokenUsage): TokenUsa
101
149
  ...(next.cacheWriteTtlTokens !== undefined || current.cacheWriteTtlTokens !== undefined
102
150
  ? { cacheWriteTtlTokens: next.cacheWriteTtlTokens ?? current.cacheWriteTtlTokens }
103
151
  : {}),
152
+ ...(next.speed !== undefined || current.speed !== undefined
153
+ ? { speed: next.speed ?? current.speed }
154
+ : {}),
155
+ ...(next.webSearchRequests !== undefined || current.webSearchRequests !== undefined
156
+ ? { webSearchRequests: Math.max(current.webSearchRequests ?? 0, next.webSearchRequests ?? 0) }
157
+ : {}),
158
+ ...(next.serviceTier !== undefined || current.serviceTier !== undefined
159
+ ? { serviceTier: next.serviceTier ?? current.serviceTier }
160
+ : {}),
161
+ ...(next.inferenceGeo !== undefined || current.inferenceGeo !== undefined
162
+ ? { inferenceGeo: next.inferenceGeo ?? current.inferenceGeo }
163
+ : {}),
164
+ ...(next.cacheMiss !== undefined || current.cacheMiss !== undefined
165
+ ? { cacheMiss: next.cacheMiss ?? current.cacheMiss }
166
+ : {}),
104
167
  }
105
168
  }
106
169
 
@@ -106,6 +106,15 @@ export interface ChatCompletionParams {
106
106
  * that narrower set according to their documented provider policy.
107
107
  */
108
108
  effort?: ReasoningEffort
109
+
110
+ /**
111
+ * Inference speed. `'fast'` asks a provider for its premium low-latency
112
+ * mode, billed at a multiple of the standard rate; absent and `'standard'`
113
+ * are the same request. A driver with no such mode, or a model without it,
114
+ * must refuse `'fast'` rather than serve it at standard speed and let the
115
+ * caller believe it was honoured.
116
+ */
117
+ speed?: InferenceSpeed
109
118
  }
110
119
 
111
120
  export interface ThinkingConfig {
@@ -174,6 +183,9 @@ export interface ThinkingConfig {
174
183
  * transport or leave the vendor to refuse an unknown compatible-endpoint
175
184
  * extension explicitly.
176
185
  */
186
+ /** `'fast'` is a premium low-latency mode; `'standard'` is the ordinary request. See {@link ChatCompletionParams.speed}. */
187
+ export type InferenceSpeed = 'standard' | 'fast'
188
+
177
189
  export type ReasoningEffort =
178
190
  | 'none'
179
191
  | 'minimal'
@@ -170,6 +170,14 @@ export interface ProviderCapabilities {
170
170
  * or the lifetime is the provider's own and cannot be chosen or read).
171
171
  */
172
172
  cacheTtl?: readonly ('5m' | '1h')[]
173
+ /**
174
+ * The most base64 characters of inline images and documents this provider
175
+ * will take in one request, when its wire limit differs from the kernel's
176
+ * default (24 MiB). Counts the encoded value, like
177
+ * `turnConfig.maxRequestRichContentBytes`, which still overrides it.
178
+ * Absent means the kernel default.
179
+ */
180
+ maxRequestRichContentBytes?: number
173
181
  }
174
182
 
175
183
  export interface ProviderFactoryResult {
@@ -5,6 +5,7 @@ export type {
5
5
  ChatCompletionParams,
6
6
  ChatCompletionResponse,
7
7
  ProviderRefusal,
8
+ InferenceSpeed,
8
9
  ReasoningEffort,
9
10
  ThinkingConfig,
10
11
  } from './chat.js'
@@ -69,6 +69,17 @@ export interface TurnConfig {
69
69
  */
70
70
  effort?: import('../provider/index.js').ReasoningEffort
71
71
 
72
+ /**
73
+ * Inference speed for every model call in the turn: `'fast'` asks for the
74
+ * provider's premium low-latency mode (billed at a multiple of the standard
75
+ * rate), absent and `'standard'` are the ordinary request. Turn-level for
76
+ * the same reason as {@link TurnConfig.effort}: speeds do not share a
77
+ * prompt-cache prefix, so a value that moves between steps pays for a cache
78
+ * miss each time. A driver or model without the mode REFUSES `'fast'`
79
+ * rather than serving it slowly.
80
+ */
81
+ speed?: import('../provider/index.js').InferenceSpeed
82
+
72
83
  /**
73
84
  * How the turn bounds its reasoning. On by default.
74
85
  *
@@ -519,7 +519,14 @@ type CoreSessionEvent =
519
519
  /** The model that declined. */
520
520
  model: string
521
521
  providerId: string
522
- outcome: 'fallback' | 'retry' | 'declined'
522
+ outcome: 'fallback' | 'retry' | 'withheld' | 'declined'
523
+ /**
524
+ * Set only with `outcome: 'withheld'`: the recorded-context keys the
525
+ * re-run leaves out of the request (see `QueryParams.withholdOnRefusal`).
526
+ */
527
+ withheldKeys?: string[]
528
+ /** With `'withheld'`: the ids of the recalled memories those entries carried. */
529
+ withheldMemoryIds?: string[]
523
530
  /** The model the request moves to. Set only with `outcome: 'fallback'`. */
524
531
  fallbackModel?: string
525
532
  /** The provider's own classification, when it gave one. */
@@ -919,6 +926,13 @@ type CoreSessionEvent =
919
926
  * absent means unknown, and a host must not assume one.
920
927
  */
921
928
  cache?: { ttlMs: number; touched: boolean }
929
+ /**
930
+ * Why the provider says the latest model call did not read the cache
931
+ * prefix it had before, when it explains one. Absent means no miss was
932
+ * explained: nothing reported, a pending answer, or a hit. A host that
933
+ * shows it should do so quietly; a miss after an edit is ordinary.
934
+ */
935
+ cacheMiss?: { reason: string; missedTokens?: number }
922
936
  /**
923
937
  * How large the CONTEXT is right now, and how large it may get.
924
938
  *
@@ -98,6 +98,13 @@ export interface PrepareStepContext {
98
98
  }
99
99
  /** Every completed step, in order. */
100
100
  readonly steps: readonly StepResult[]
101
+ /**
102
+ * Recorded-context keys the request leaves out: set aside by a refused
103
+ * request (`QueryParams.withholdOnRefusal`) or by the host
104
+ * (`QueryParams.withheldKeys`). A stage that records text under one of
105
+ * these keys should add nothing now; whatever it records is also left out.
106
+ */
107
+ readonly withheldKeys?: readonly string[]
101
108
 
102
109
  /**
103
110
  * What the stages before this one decided, when several were supplied.
package/src/utils/cost.ts CHANGED
@@ -41,6 +41,19 @@ export interface ModelPricing {
41
41
  * part. The catalogue always supplies this.
42
42
  */
43
43
  cache?: CacheRates
44
+ /**
45
+ * The vendor's published multiple of every rate on this card for a request
46
+ * served in fast mode (`TokenUsage.speed === 'fast'`). Absent means there is
47
+ * no published fast price: fast usage is then counted as unpriced, never
48
+ * charged at the standard rate, which would under-report it.
49
+ */
50
+ fastMultiplier?: number
51
+ /**
52
+ * What the vendor charges per 1,000 hosted web searches
53
+ * (`TokenUsage.webSearchRequests`). Absent means no published search price:
54
+ * searches are then not part of the total, as before this field existed.
55
+ */
56
+ webSearchCostPer1000?: number
44
57
  }
45
58
 
46
59
  export { ZERO_COST }
@@ -54,6 +67,42 @@ interface Priced {
54
67
  }
55
68
 
56
69
  function priceUsage(usage: TokenUsage, pricing: ModelPricing): Priced {
70
+ const tokens = priceTokens(usage, pricing)
71
+ const searches = usage.webSearchRequests ?? 0
72
+ if (searches === 0 || pricing.webSearchCostPer1000 === undefined) return tokens
73
+ // Per request, so no speed or tier multiple applies to it.
74
+ return { ...tokens, cost: tokens.cost + (searches / 1000) * pricing.webSearchCostPer1000 }
75
+ }
76
+
77
+ /**
78
+ * Tiers with a published per-token price (anything but `priority` and `batch`; a compatible endpoint may report `default` or `auto`). The vendor lists none for `priority`
79
+ * (a capacity commitment) or `batch` (a different endpoint), so tokens served
80
+ * on one are unpriced rather than charged at the standard rate.
81
+ */
82
+ function isStandardTier(tier: string | undefined): boolean {
83
+ return tier !== 'priority' && tier !== 'batch'
84
+ }
85
+
86
+ function priceTokens(usage: TokenUsage, pricing: ModelPricing): Priced {
87
+ if (!isStandardTier(usage.serviceTier)) {
88
+ return { cost: 0, cacheDiscount: 0, unpriced: usage.totalTokens }
89
+ }
90
+ if (usage.speed === 'fast') {
91
+ const multiplier = pricing.fastMultiplier
92
+ if (multiplier === undefined) {
93
+ return { cost: 0, cacheDiscount: 0, unpriced: usage.totalTokens }
94
+ }
95
+ const standard = priceStandard({ ...usage, speed: undefined }, pricing)
96
+ return {
97
+ cost: standard.cost * multiplier,
98
+ cacheDiscount: standard.cacheDiscount * multiplier,
99
+ unpriced: standard.unpriced,
100
+ }
101
+ }
102
+ return priceStandard(usage, pricing)
103
+ }
104
+
105
+ function priceStandard(usage: TokenUsage, pricing: ModelPricing): Priced {
57
106
  const perMillion = (tokens: number, rate: number) => (tokens / 1_000_000) * rate
58
107
 
59
108
  const cache = pricing.cache