@namzu/sdk 62.4.0 → 62.5.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.
- package/CHANGELOG.md +20 -0
- package/dist/agents/QueryAgent.d.ts.map +1 -1
- package/dist/agents/QueryAgent.js +3 -0
- package/dist/agents/QueryAgent.js.map +1 -1
- package/dist/agents/runAgent.d.ts +3 -1
- package/dist/agents/runAgent.d.ts.map +1 -1
- package/dist/agents/runAgent.js +1 -0
- package/dist/agents/runAgent.js.map +1 -1
- package/dist/bridge/a2a/mapper.d.ts.map +1 -1
- package/dist/bridge/a2a/mapper.js +5 -3
- package/dist/bridge/a2a/mapper.js.map +1 -1
- package/dist/pricing/catalogue.generated.d.ts.map +1 -1
- package/dist/pricing/catalogue.generated.js +5 -0
- package/dist/pricing/catalogue.generated.js.map +1 -1
- package/dist/provider/fallback.d.ts.map +1 -1
- package/dist/provider/fallback.js +23 -1
- package/dist/provider/fallback.js.map +1 -1
- package/dist/public-runtime.d.ts +1 -1
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +1 -1
- package/dist/public-runtime.js.map +1 -1
- package/dist/runtime/query/index.d.ts +21 -0
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +4 -0
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts +10 -0
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +59 -6
- package/dist/runtime/query/iteration/index.js.map +1 -1
- package/dist/runtime/query/iteration/phases/context.d.ts +4 -0
- package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/context.js.map +1 -1
- package/dist/runtime/query/iteration/step-shaping.d.ts.map +1 -1
- package/dist/runtime/query/iteration/step-shaping.js +3 -0
- package/dist/runtime/query/iteration/step-shaping.js.map +1 -1
- package/dist/runtime/query/prepare-turn.d.ts.map +1 -1
- package/dist/runtime/query/prepare-turn.js +5 -2
- package/dist/runtime/query/prepare-turn.js.map +1 -1
- package/dist/runtime/query/request-rich-content.d.ts +7 -1
- package/dist/runtime/query/request-rich-content.d.ts.map +1 -1
- package/dist/runtime/query/request-rich-content.js +8 -2
- package/dist/runtime/query/request-rich-content.js.map +1 -1
- package/dist/turn/index.d.ts +1 -1
- package/dist/turn/index.d.ts.map +1 -1
- package/dist/turn/index.js +1 -1
- package/dist/turn/index.js.map +1 -1
- package/dist/turn/memory-recall.d.ts +13 -0
- package/dist/turn/memory-recall.d.ts.map +1 -1
- package/dist/turn/memory-recall.js +38 -1
- package/dist/turn/memory-recall.js.map +1 -1
- package/dist/types/agent/base.d.ts +2 -0
- package/dist/types/agent/base.d.ts.map +1 -1
- package/dist/types/agent/query.d.ts +4 -0
- package/dist/types/agent/query.d.ts.map +1 -1
- package/dist/types/common/index.d.ts +7 -0
- package/dist/types/common/index.d.ts.map +1 -1
- package/dist/types/common/index.js +3 -0
- package/dist/types/common/index.js.map +1 -1
- package/dist/types/provider/chat.d.ts +10 -0
- package/dist/types/provider/chat.d.ts.map +1 -1
- package/dist/types/provider/config.d.ts +8 -0
- package/dist/types/provider/config.d.ts.map +1 -1
- package/dist/types/provider/index.d.ts +1 -1
- package/dist/types/provider/index.d.ts.map +1 -1
- package/dist/types/session/config.d.ts +10 -0
- package/dist/types/session/config.d.ts.map +1 -1
- package/dist/types/session/events.d.ts +8 -1
- package/dist/types/session/events.d.ts.map +1 -1
- package/dist/types/session/events.js.map +1 -1
- package/dist/types/session/prepare-step.d.ts +7 -0
- package/dist/types/session/prepare-step.d.ts.map +1 -1
- package/dist/utils/cost.d.ts +7 -0
- package/dist/utils/cost.d.ts.map +1 -1
- package/dist/utils/cost.js +15 -0
- package/dist/utils/cost.js.map +1 -1
- package/package.json +1 -1
- package/src/agents/QueryAgent.ts +3 -0
- package/src/agents/runAgent.ts +9 -1
- package/src/bridge/a2a/mapper.ts +5 -3
- package/src/pricing/catalogue.generated.ts +5 -0
- package/src/pricing/rates.source.json +15 -5
- package/src/provider/fallback.ts +33 -1
- package/src/public-runtime.ts +1 -1
- package/src/runtime/query/index.ts +27 -0
- package/src/runtime/query/iteration/index.ts +70 -5
- package/src/runtime/query/iteration/phases/context.ts +4 -0
- package/src/runtime/query/iteration/step-shaping.ts +3 -0
- package/src/runtime/query/prepare-turn.ts +6 -2
- package/src/runtime/query/request-rich-content.ts +11 -2
- package/src/turn/index.ts +1 -1
- package/src/turn/memory-recall.ts +40 -0
- package/src/types/agent/base.ts +2 -0
- package/src/types/agent/query.ts +4 -0
- package/src/types/common/index.ts +11 -0
- package/src/types/provider/chat.ts +12 -0
- package/src/types/provider/config.ts +8 -0
- package/src/types/provider/index.ts +1 -0
- package/src/types/session/config.ts +11 -0
- package/src/types/session/events.ts +8 -1
- package/src/types/session/prepare-step.ts +7 -0
- package/src/utils/cost.ts +23 -0
package/src/agents/runAgent.ts
CHANGED
|
@@ -13,7 +13,12 @@ import type { AuthorizationGateConfig } from '../types/authorization/index.js'
|
|
|
13
13
|
import type { InputGuardrailSpec, OutputGuardrailSpec } from '../types/guardrail/index.js'
|
|
14
14
|
import type { ProjectId, SessionId, TenantId, TopicId } from '../types/ids/index.js'
|
|
15
15
|
import type { Message } from '../types/message/index.js'
|
|
16
|
-
import type {
|
|
16
|
+
import type {
|
|
17
|
+
InferenceSpeed,
|
|
18
|
+
LLMProvider,
|
|
19
|
+
ReasoningEffort,
|
|
20
|
+
ThinkingConfig,
|
|
21
|
+
} from '../types/provider/index.js'
|
|
17
22
|
import type { SandboxProvider } from '../types/sandbox/index.js'
|
|
18
23
|
import type { TurnConfig } from '../types/session/config.js'
|
|
19
24
|
import type { SessionEventListener } from '../types/session/events.js'
|
|
@@ -202,6 +207,8 @@ export interface RunAgentOptions extends AgentIdentity {
|
|
|
202
207
|
*/
|
|
203
208
|
thinking?: ThinkingConfig
|
|
204
209
|
effort?: ReasoningEffort
|
|
210
|
+
/** Inference speed for every model call; see `TurnConfig.speed`. */
|
|
211
|
+
speed?: InferenceSpeed
|
|
205
212
|
|
|
206
213
|
/** Names the agent in traces and events. Defaults to `Agent`. */
|
|
207
214
|
name?: string
|
|
@@ -295,6 +302,7 @@ const RUN_AGENT_OPTION_ROUTES = {
|
|
|
295
302
|
structuredOutput: 'query',
|
|
296
303
|
thinking: 'special',
|
|
297
304
|
effort: 'special',
|
|
305
|
+
speed: 'turn',
|
|
298
306
|
name: 'special',
|
|
299
307
|
signal: 'query',
|
|
300
308
|
listener: 'special',
|
package/src/bridge/a2a/mapper.ts
CHANGED
|
@@ -152,9 +152,11 @@ const MAPPING: {
|
|
|
152
152
|
text:
|
|
153
153
|
e.outcome === 'fallback' && e.fallbackModel
|
|
154
154
|
? `${e.model} declined to answer; continuing on ${e.fallbackModel}`
|
|
155
|
-
: e.outcome === '
|
|
156
|
-
? `${e.model}
|
|
157
|
-
:
|
|
155
|
+
: e.outcome === 'withheld'
|
|
156
|
+
? `${e.model} declined to answer; continuing once without the recorded context it carried`
|
|
157
|
+
: e.outcome === 'retry'
|
|
158
|
+
? `${e.model} stopped its reply; continuing once with that noted`
|
|
159
|
+
: `${e.model} declined to answer`,
|
|
158
160
|
},
|
|
159
161
|
],
|
|
160
162
|
}),
|
|
@@ -49,6 +49,7 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
49
49
|
inputCostPer1M: 8,
|
|
50
50
|
outputCostPer1M: 40,
|
|
51
51
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 0.2, writeCostPer1M: 10 },
|
|
52
|
+
fastMultiplier: 2,
|
|
52
53
|
},
|
|
53
54
|
],
|
|
54
55
|
[
|
|
@@ -81,6 +82,7 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
81
82
|
inputCostPer1M: 8,
|
|
82
83
|
outputCostPer1M: 40,
|
|
83
84
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 0.2, writeCostPer1M: 10 },
|
|
85
|
+
fastMultiplier: 2,
|
|
84
86
|
},
|
|
85
87
|
],
|
|
86
88
|
[
|
|
@@ -121,6 +123,7 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
121
123
|
inputCostPer1M: 5,
|
|
122
124
|
outputCostPer1M: 25,
|
|
123
125
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 0.5, writeCostPer1M: 6.25 },
|
|
126
|
+
fastMultiplier: 2,
|
|
124
127
|
},
|
|
125
128
|
],
|
|
126
129
|
[
|
|
@@ -129,6 +132,7 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
129
132
|
inputCostPer1M: 5,
|
|
130
133
|
outputCostPer1M: 25,
|
|
131
134
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 0.5, writeCostPer1M: 6.25 },
|
|
135
|
+
fastMultiplier: 2,
|
|
132
136
|
},
|
|
133
137
|
],
|
|
134
138
|
[
|
|
@@ -137,6 +141,7 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
137
141
|
inputCostPer1M: 4,
|
|
138
142
|
outputCostPer1M: 20,
|
|
139
143
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 0.2, writeCostPer1M: 5 },
|
|
144
|
+
fastMultiplier: 2,
|
|
140
145
|
},
|
|
141
146
|
],
|
|
142
147
|
[
|
|
@@ -19,6 +19,11 @@
|
|
|
19
19
|
"inference. Its turns are priced at zero, which is KNOWN-free and therefore",
|
|
20
20
|
"distinct from unknown. Such a vendor needs no model rows.",
|
|
21
21
|
"",
|
|
22
|
+
"fastMultiplier (optional) is the vendor's published multiple of every rate for",
|
|
23
|
+
"a request served in fast mode (verified 2026-11-10 against the fast-mode page:",
|
|
24
|
+
"2x on the full context window, stacking with cache pricing). A model without it",
|
|
25
|
+
"has no published fast price, so a fast request on it is reported as unpriced.",
|
|
26
|
+
"",
|
|
22
27
|
"Matching is EXACT on a normalised id (lowercased, one trailing -YYYYMMDD or",
|
|
23
28
|
"@YYYYMMDD snapshot suffix removed). Deliberately not prefix or substring:",
|
|
24
29
|
"within one vendor here, ids one character apart differ in price by 4x, so a",
|
|
@@ -66,14 +71,16 @@
|
|
|
66
71
|
"inputPer1M": 8,
|
|
67
72
|
"outputPer1M": 40,
|
|
68
73
|
"cacheReadPer1M": 0.2,
|
|
69
|
-
"cacheWritePer1M": 10
|
|
74
|
+
"cacheWritePer1M": 10,
|
|
75
|
+
"fastMultiplier": 2
|
|
70
76
|
},
|
|
71
77
|
{
|
|
72
78
|
"id": "claude-mythos-5-2",
|
|
73
79
|
"inputPer1M": 8,
|
|
74
80
|
"outputPer1M": 40,
|
|
75
81
|
"cacheReadPer1M": 0.2,
|
|
76
|
-
"cacheWritePer1M": 10
|
|
82
|
+
"cacheWritePer1M": 10,
|
|
83
|
+
"fastMultiplier": 2
|
|
77
84
|
},
|
|
78
85
|
{
|
|
79
86
|
"id": "claude-fable-5-1",
|
|
@@ -94,7 +101,8 @@
|
|
|
94
101
|
"inputPer1M": 4,
|
|
95
102
|
"outputPer1M": 20,
|
|
96
103
|
"cacheReadPer1M": 0.2,
|
|
97
|
-
"cacheWritePer1M": 5
|
|
104
|
+
"cacheWritePer1M": 5,
|
|
105
|
+
"fastMultiplier": 2
|
|
98
106
|
},
|
|
99
107
|
{
|
|
100
108
|
"id": "claude-sonnet-5-5",
|
|
@@ -122,14 +130,16 @@
|
|
|
122
130
|
"inputPer1M": 5,
|
|
123
131
|
"outputPer1M": 25,
|
|
124
132
|
"cacheReadPer1M": 0.5,
|
|
125
|
-
"cacheWritePer1M": 6.25
|
|
133
|
+
"cacheWritePer1M": 6.25,
|
|
134
|
+
"fastMultiplier": 2
|
|
126
135
|
},
|
|
127
136
|
{
|
|
128
137
|
"id": "claude-opus-4-8",
|
|
129
138
|
"inputPer1M": 5,
|
|
130
139
|
"outputPer1M": 25,
|
|
131
140
|
"cacheReadPer1M": 0.5,
|
|
132
|
-
"cacheWritePer1M": 6.25
|
|
141
|
+
"cacheWritePer1M": 6.25,
|
|
142
|
+
"fastMultiplier": 2
|
|
133
143
|
},
|
|
134
144
|
{
|
|
135
145
|
"id": "claude-opus-4-7",
|
package/src/provider/fallback.ts
CHANGED
|
@@ -22,10 +22,12 @@
|
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
import { GENAI } from '../constants/telemetry/index.js'
|
|
25
|
+
import { DEFAULT_MAX_REQUEST_RICH_CONTENT_BYTES } from '../runtime/query/request-rich-content.js'
|
|
25
26
|
import { classifyProviderError, isAbortError } from '../types/provider/errors.js'
|
|
26
27
|
import type {
|
|
27
28
|
ChatCompletionParams,
|
|
28
29
|
LLMProvider,
|
|
30
|
+
ProviderCapabilities,
|
|
29
31
|
ReasoningEffort,
|
|
30
32
|
StreamChunk,
|
|
31
33
|
ThinkingConfig,
|
|
@@ -513,7 +515,7 @@ export function withProviderFallback(
|
|
|
513
515
|
return first.provider.name
|
|
514
516
|
},
|
|
515
517
|
get capabilities() {
|
|
516
|
-
return first.provider.capabilities
|
|
518
|
+
return chainCapabilities(members, first.provider.capabilities)
|
|
517
519
|
},
|
|
518
520
|
chatStream,
|
|
519
521
|
...(first.provider.listModels
|
|
@@ -604,3 +606,33 @@ export function withProviderFallback(
|
|
|
604
606
|
: {}),
|
|
605
607
|
} as LLMProvider
|
|
606
608
|
}
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* The head's declarations, with the request rich-content budget narrowed to
|
|
612
|
+
* what EVERY member can take: a request is built once and may be served by any
|
|
613
|
+
* of them, so a head with a large budget must not send a fallback more than it
|
|
614
|
+
* accepts. A member that declares nothing counts as the kernel default. When
|
|
615
|
+
* no member declares one the head's capabilities are returned untouched.
|
|
616
|
+
*/
|
|
617
|
+
function chainCapabilities(
|
|
618
|
+
members: readonly { readonly provider: Pick<LLMProvider, 'capabilities'> }[],
|
|
619
|
+
head: ProviderCapabilities | undefined,
|
|
620
|
+
): ProviderCapabilities | undefined {
|
|
621
|
+
if (!members.some((m) => m.provider.capabilities?.maxRequestRichContentBytes !== undefined)) {
|
|
622
|
+
return head
|
|
623
|
+
}
|
|
624
|
+
const budget = Math.min(
|
|
625
|
+
...members.map(
|
|
626
|
+
(m) =>
|
|
627
|
+
m.provider.capabilities?.maxRequestRichContentBytes ??
|
|
628
|
+
DEFAULT_MAX_REQUEST_RICH_CONTENT_BYTES,
|
|
629
|
+
),
|
|
630
|
+
)
|
|
631
|
+
return {
|
|
632
|
+
supportsTools: true,
|
|
633
|
+
supportsStreaming: true,
|
|
634
|
+
supportsFunctionCalling: true,
|
|
635
|
+
...head,
|
|
636
|
+
maxRequestRichContentBytes: budget,
|
|
637
|
+
}
|
|
638
|
+
}
|
package/src/public-runtime.ts
CHANGED
|
@@ -478,7 +478,7 @@ export type {
|
|
|
478
478
|
// did nothing.
|
|
479
479
|
export { SESSION_MEMORY_TAG, createMemoryPromoter } from './turn/index.js'
|
|
480
480
|
export type { MemoryPromoterOptions, SessionMemoryCategory } from './turn/index.js'
|
|
481
|
-
export { createMemoryRecallStep } from './turn/memory-recall.js'
|
|
481
|
+
export { createMemoryRecallStep, recalledMemoryIds } from './turn/memory-recall.js'
|
|
482
482
|
export type {
|
|
483
483
|
MemoryRecallOptions,
|
|
484
484
|
MemorySelection,
|
|
@@ -393,6 +393,29 @@ export interface QueryParams {
|
|
|
393
393
|
*/
|
|
394
394
|
refusalFallback?: 'auto' | 'off'
|
|
395
395
|
|
|
396
|
+
/**
|
|
397
|
+
* Recorded-context keys (see `RecordedContextItem.key`) to leave out of the
|
|
398
|
+
* request when the provider refuses it. On a refusal, before any model
|
|
399
|
+
* fallback, the loop re-runs the step once with every entry filed under one
|
|
400
|
+
* of these keys left out of the request. The history itself is not changed,
|
|
401
|
+
* so nothing is lost for a later turn. The refused request is announced by a
|
|
402
|
+
* `model_refusal` event with `outcome: 'withheld'`, and the steps that
|
|
403
|
+
* follow, in this turn, see the keys in `PrepareStepContext.withheldKeys` so
|
|
404
|
+
* a stage can stop adding what was just set aside. When the entries are
|
|
405
|
+
* recalled memories the event carries their ids. A refusal of the retry
|
|
406
|
+
* falls through to `refusalFallback` unchanged. Nothing happens when the
|
|
407
|
+
* request carried no entry under a listed key. Absent means none.
|
|
408
|
+
*/
|
|
409
|
+
withholdOnRefusal?: readonly string[]
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Recorded-context keys to leave out of every request of this turn from the
|
|
413
|
+
* first one, for a host that remembers an earlier `outcome: 'withheld'`
|
|
414
|
+
* refusal and does not want the next turn refused again. History is not
|
|
415
|
+
* changed. Seen by stages as `PrepareStepContext.withheldKeys`.
|
|
416
|
+
*/
|
|
417
|
+
withheldKeys?: readonly string[]
|
|
418
|
+
|
|
396
419
|
/**
|
|
397
420
|
* Model-visible size cap for a single tool result. Over-budget output is
|
|
398
421
|
* spilled to the turn directory and replaced with a head+tail preview
|
|
@@ -1918,6 +1941,10 @@ export async function* query(params: QueryParams): AsyncGenerator<SessionEvent,
|
|
|
1918
1941
|
? { maxOutputContinuations: params.maxOutputContinuations }
|
|
1919
1942
|
: {}),
|
|
1920
1943
|
...(params.refusalFallback !== undefined ? { refusalFallback: params.refusalFallback } : {}),
|
|
1944
|
+
...(params.withholdOnRefusal && params.withholdOnRefusal.length > 0
|
|
1945
|
+
? { withholdOnRefusal: [...params.withholdOnRefusal] }
|
|
1946
|
+
: {}),
|
|
1947
|
+
withheldKeys: new Set(params.withheldKeys ?? []),
|
|
1921
1948
|
...(params.inboundMessages ? { inboundMessages: params.inboundMessages } : {}),
|
|
1922
1949
|
...(params.reminders ? { reminders: params.reminders } : {}),
|
|
1923
1950
|
...(params.durableInbound ? { durableInbound: params.durableInbound } : {}),
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
import { getTracer } from '../../../telemetry/runtime-accessors.js'
|
|
31
31
|
import { STRUCTURED_OUTPUT_TOOL_NAME } from '../../../tools/builtins/structuredOutput.js'
|
|
32
32
|
import type { ToolManager } from '../../../toolsets/manager.js'
|
|
33
|
+
import { RECALLED_MEMORY_ENTRY_KEY, recalledMemoryIds } from '../../../turn/memory-recall.js'
|
|
33
34
|
import type { CostInfo, TokenUsage } from '../../../types/common/index.js'
|
|
34
35
|
import { NamzuError } from '../../../types/errors/index.js'
|
|
35
36
|
import type { MessageId, SessionId, TurnId } from '../../../types/ids/index.js'
|
|
@@ -40,6 +41,8 @@ import {
|
|
|
40
41
|
createRuntimeContextMessage,
|
|
41
42
|
createSystemMessage,
|
|
42
43
|
createToolMessage,
|
|
44
|
+
turnContextEntries,
|
|
45
|
+
turnContextKey,
|
|
43
46
|
} from '../../../types/message/index.js'
|
|
44
47
|
import { classifyProviderError, readOutputOverflow } from '../../../types/provider/errors.js'
|
|
45
48
|
import type { ChatCompletionResponse, ReasoningEffort } from '../../../types/provider/index.js'
|
|
@@ -69,10 +72,10 @@ import {
|
|
|
69
72
|
snapshotRequestContext,
|
|
70
73
|
} from '../request-context.js'
|
|
71
74
|
import {
|
|
72
|
-
DEFAULT_MAX_REQUEST_RICH_CONTENT_BYTES,
|
|
73
75
|
type RequestImageIdentity,
|
|
74
76
|
markProviderRejectedImage,
|
|
75
77
|
projectRequestRichContent,
|
|
78
|
+
resolveMaxRequestRichContentBytes,
|
|
76
79
|
} from '../request-rich-content.js'
|
|
77
80
|
import { withoutVoidAssistantTurns } from '../request-void-turns.js'
|
|
78
81
|
import { formatSteeringNote, isOperatorUserMessage } from '../steering.js'
|
|
@@ -255,6 +258,20 @@ export class IterationOrchestrator {
|
|
|
255
258
|
}
|
|
256
259
|
|
|
257
260
|
/** Whether a request for `model` may carry images: the driver's catalogue and this run's own evidence agree. */
|
|
261
|
+
/**
|
|
262
|
+
* The request rich-content budget, resolved each time it is read: the
|
|
263
|
+
* caller's `turnConfig` override if one was given, else what the provider
|
|
264
|
+
* serving now declares. Never written back into `turnConfig`, which would
|
|
265
|
+
* turn the first provider's declaration into an override that a resumed
|
|
266
|
+
* turn, a nested agent or a later provider then inherits.
|
|
267
|
+
*/
|
|
268
|
+
private richContentBudget(): number {
|
|
269
|
+
return resolveMaxRequestRichContentBytes(
|
|
270
|
+
this.ctx.turnConfig.maxRequestRichContentBytes,
|
|
271
|
+
this.ctx.provider.capabilities?.maxRequestRichContentBytes,
|
|
272
|
+
)
|
|
273
|
+
}
|
|
274
|
+
|
|
258
275
|
private modelReadsImages(model: string): boolean {
|
|
259
276
|
const serving = this.servingModel(model)
|
|
260
277
|
return (
|
|
@@ -332,6 +349,8 @@ export class IterationOrchestrator {
|
|
|
332
349
|
private refusalFallbackUsed = false
|
|
333
350
|
/** The request has already been re-run on the same model once this turn. */
|
|
334
351
|
private refusalRetryUsed = false
|
|
352
|
+
/** The request has already been re-run once without its withheld recorded entries. */
|
|
353
|
+
private refusalWithholdUsed = false
|
|
335
354
|
/**
|
|
336
355
|
* `turn_end` (and, for a child, `subagent_stop`) fired when the model
|
|
337
356
|
* finished and no hook asked for more. `finalizeTurn` then does not fire
|
|
@@ -898,7 +917,16 @@ export class IterationOrchestrator {
|
|
|
898
917
|
turnId: recorder.turnId,
|
|
899
918
|
memories: recalled,
|
|
900
919
|
})
|
|
901
|
-
const
|
|
920
|
+
const withheld = this.ctx.withheldKeys
|
|
921
|
+
// A withheld key is left out of the request only: the history keeps
|
|
922
|
+
// its entries, so a later turn or a restore still has them.
|
|
923
|
+
const baseMessages =
|
|
924
|
+
withheld && withheld.size > 0
|
|
925
|
+
? recorder.messages.filter((message) => {
|
|
926
|
+
const key = turnContextKey(message)
|
|
927
|
+
return key === undefined || !withheld.has(key)
|
|
928
|
+
})
|
|
929
|
+
: recorder.messages
|
|
902
930
|
|
|
903
931
|
// Step guidance is appended to the REQUEST, never pushed onto
|
|
904
932
|
// the turn's history: it applies to this step only, and pushing
|
|
@@ -967,8 +995,7 @@ export class IterationOrchestrator {
|
|
|
967
995
|
if (policyNotice) requestHistory.push(stepContextMessage(policyNotice))
|
|
968
996
|
const projected = projectRequestRichContent(
|
|
969
997
|
withoutVoidAssistantTurns(this.projectObservations(requestHistory)),
|
|
970
|
-
this.
|
|
971
|
-
DEFAULT_MAX_REQUEST_RICH_CONTENT_BYTES,
|
|
998
|
+
this.richContentBudget(),
|
|
972
999
|
{ imagesReadable: this.modelReadsImages(stepModel) },
|
|
973
1000
|
)
|
|
974
1001
|
// Request-only data (the context contributions, notes about the
|
|
@@ -1197,6 +1224,7 @@ export class IterationOrchestrator {
|
|
|
1197
1224
|
cacheControl: { type: 'auto' },
|
|
1198
1225
|
...(turnConfig.thinking ? { thinking: turnConfig.thinking } : {}),
|
|
1199
1226
|
...(stepEffort ? { effort: stepEffort } : {}),
|
|
1227
|
+
...(turnConfig.speed ? { speed: turnConfig.speed } : {}),
|
|
1200
1228
|
...(!forceFinalize && turnConfig.webSearch
|
|
1201
1229
|
? { webSearch: turnConfig.webSearch }
|
|
1202
1230
|
: {}),
|
|
@@ -3180,6 +3208,42 @@ export class IterationOrchestrator {
|
|
|
3180
3208
|
return 'settled'
|
|
3181
3209
|
}
|
|
3182
3210
|
|
|
3211
|
+
const withholdKeys = this.ctx.withholdOnRefusal
|
|
3212
|
+
if (
|
|
3213
|
+
!input.forceFinalize &&
|
|
3214
|
+
!this.refusalWithholdUsed &&
|
|
3215
|
+
withholdKeys &&
|
|
3216
|
+
this.ctx.withheldKeys
|
|
3217
|
+
) {
|
|
3218
|
+
const carried = withholdKeys.filter(
|
|
3219
|
+
(key) =>
|
|
3220
|
+
!this.ctx.withheldKeys?.has(key) &&
|
|
3221
|
+
recorder.messages.some((message) => turnContextKey(message) === key),
|
|
3222
|
+
)
|
|
3223
|
+
if (carried.length > 0) {
|
|
3224
|
+
this.refusalWithholdUsed = true
|
|
3225
|
+
for (const key of carried) this.ctx.withheldKeys.add(key)
|
|
3226
|
+
const memoryIds = carried.includes(RECALLED_MEMORY_ENTRY_KEY)
|
|
3227
|
+
? recalledMemoryIds(turnContextEntries(recorder.messages, RECALLED_MEMORY_ENTRY_KEY))
|
|
3228
|
+
: []
|
|
3229
|
+
await this.ctx.emitEvent({
|
|
3230
|
+
type: 'model_refusal',
|
|
3231
|
+
turnId: recorder.turnId,
|
|
3232
|
+
iteration: iterationNum,
|
|
3233
|
+
model: servedBy.model,
|
|
3234
|
+
providerId: servedBy.providerId,
|
|
3235
|
+
outcome: 'withheld',
|
|
3236
|
+
withheldKeys: carried,
|
|
3237
|
+
...(memoryIds.length > 0 ? { withheldMemoryIds: memoryIds } : {}),
|
|
3238
|
+
...(refusal.category ? { category: refusal.category } : {}),
|
|
3239
|
+
...(refusal.explanation ? { explanation: refusal.explanation } : {}),
|
|
3240
|
+
})
|
|
3241
|
+
await closeIteration()
|
|
3242
|
+
yield* this.ctx.drainPending()
|
|
3243
|
+
return 'retry'
|
|
3244
|
+
}
|
|
3245
|
+
}
|
|
3246
|
+
|
|
3183
3247
|
if (!input.forceFinalize && !this.refusalFallbackUsed && this.ctx.refusalFallback !== 'off') {
|
|
3184
3248
|
const next = await this.refusalFallbackModel(input.stepModel, refusal)
|
|
3185
3249
|
if (next !== undefined) {
|
|
@@ -3369,7 +3433,7 @@ export class IterationOrchestrator {
|
|
|
3369
3433
|
]
|
|
3370
3434
|
const finalMessages = projectRequestRichContent(
|
|
3371
3435
|
withoutVoidAssistantTurns(this.projectObservations(finalHistory)),
|
|
3372
|
-
this.
|
|
3436
|
+
this.richContentBudget(),
|
|
3373
3437
|
{ imagesReadable: this.modelReadsImages(model) },
|
|
3374
3438
|
)
|
|
3375
3439
|
// The closing directive is the last thing the model reads: after
|
|
@@ -3411,6 +3475,7 @@ export class IterationOrchestrator {
|
|
|
3411
3475
|
// is exactly the shape a field goes missing from — so it is tested
|
|
3412
3476
|
// separately rather than assumed to have been kept in step.
|
|
3413
3477
|
...(this.ctx.turnConfig.effort ? { effort: this.ctx.turnConfig.effort } : {}),
|
|
3478
|
+
...(this.ctx.turnConfig.speed ? { speed: this.ctx.turnConfig.speed } : {}),
|
|
3414
3479
|
// Cancellable too: a Stop during the closing summary must not
|
|
3415
3480
|
// stream to completion.
|
|
3416
3481
|
signal: this.ctx.abortController.signal,
|
|
@@ -226,6 +226,10 @@ export interface IterationContext {
|
|
|
226
226
|
readonly maxOutputContinuations?: number
|
|
227
227
|
/** See `QueryParams.refusalFallback`. */
|
|
228
228
|
readonly refusalFallback?: 'auto' | 'off'
|
|
229
|
+
/** See `QueryParams.withholdOnRefusal`. */
|
|
230
|
+
readonly withholdOnRefusal?: readonly string[]
|
|
231
|
+
/** Recorded-context keys left out of the request; grows when a refusal is retried without them. */
|
|
232
|
+
readonly withheldKeys?: Set<string>
|
|
229
233
|
|
|
230
234
|
/**
|
|
231
235
|
* What the driver said this model's context window is, resolved once.
|
|
@@ -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
|
-
|
|
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
|
-
|
|
16
|
-
|
|
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)
|
package/src/types/agent/base.ts
CHANGED
|
@@ -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}. */
|
package/src/types/agent/query.ts
CHANGED
|
@@ -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,14 @@ 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
|
|
45
53
|
}
|
|
46
54
|
|
|
47
55
|
export function accumulateTokenUsage(current: TokenUsage, addition: TokenUsage): TokenUsage {
|
|
@@ -101,6 +109,9 @@ export function mergeTokenUsage(current: TokenUsage, next: TokenUsage): TokenUsa
|
|
|
101
109
|
...(next.cacheWriteTtlTokens !== undefined || current.cacheWriteTtlTokens !== undefined
|
|
102
110
|
? { cacheWriteTtlTokens: next.cacheWriteTtlTokens ?? current.cacheWriteTtlTokens }
|
|
103
111
|
: {}),
|
|
112
|
+
...(next.speed !== undefined || current.speed !== undefined
|
|
113
|
+
? { speed: next.speed ?? current.speed }
|
|
114
|
+
: {}),
|
|
104
115
|
}
|
|
105
116
|
}
|
|
106
117
|
|
|
@@ -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 {
|