@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.
- package/CHANGELOG.md +36 -0
- package/README.md +1 -1
- 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/file-definitions.d.ts +1 -1
- package/dist/agents/file-definitions.js +1 -1
- package/dist/agents/runAgent.d.ts +4 -2
- package/dist/agents/runAgent.d.ts.map +1 -1
- package/dist/agents/runAgent.js +2 -1
- 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/compaction/model-summary.d.ts.map +1 -1
- package/dist/compaction/model-summary.js +2 -1
- package/dist/compaction/model-summary.js.map +1 -1
- package/dist/compaction/verifier.d.ts.map +1 -1
- package/dist/compaction/verifier.js +2 -1
- package/dist/compaction/verifier.js.map +1 -1
- package/dist/eval/judge.d.ts.map +1 -1
- package/dist/eval/judge.js +2 -1
- package/dist/eval/judge.js.map +1 -1
- package/dist/pricing/catalogue.generated.d.ts.map +1 -1
- package/dist/pricing/catalogue.generated.js +24 -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/auto-review/classifier.d.ts.map +1 -1
- package/dist/runtime/query/auto-review/classifier.js +2 -1
- package/dist/runtime/query/auto-review/classifier.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 +62 -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/request-repair.d.ts +9 -1
- package/dist/runtime/query/iteration/request-repair.d.ts.map +1 -1
- package/dist/runtime/query/iteration/request-repair.js +29 -0
- package/dist/runtime/query/iteration/request-repair.js.map +1 -1
- package/dist/runtime/query/iteration/side-call.d.ts +16 -0
- package/dist/runtime/query/iteration/side-call.d.ts.map +1 -0
- package/dist/runtime/query/iteration/side-call.js +50 -0
- package/dist/runtime/query/iteration/side-call.js.map +1 -0
- 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 +38 -0
- package/dist/types/common/index.d.ts.map +1 -1
- package/dist/types/common/index.js +21 -2
- 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 +18 -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 +13 -0
- package/dist/utils/cost.d.ts.map +1 -1
- package/dist/utils/cost.js +34 -0
- package/dist/utils/cost.js.map +1 -1
- package/package.json +2 -2
- package/src/agents/QueryAgent.ts +3 -0
- package/src/agents/file-definitions.ts +1 -1
- package/src/agents/runAgent.ts +10 -2
- package/src/bridge/a2a/mapper.ts +5 -3
- package/src/compaction/model-summary.ts +2 -1
- package/src/compaction/verifier.ts +2 -1
- package/src/eval/judge.ts +2 -1
- package/src/pricing/catalogue.generated.ts +24 -0
- package/src/pricing/rates.source.json +22 -5
- package/src/provider/fallback.ts +33 -1
- package/src/public-runtime.ts +1 -1
- package/src/runtime/query/auto-review/classifier.ts +2 -1
- package/src/runtime/query/index.ts +27 -0
- package/src/runtime/query/iteration/index.ts +73 -5
- package/src/runtime/query/iteration/phases/context.ts +4 -0
- package/src/runtime/query/iteration/request-repair.ts +42 -1
- package/src/runtime/query/iteration/side-call.ts +60 -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 +65 -2
- 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 +15 -1
- package/src/types/session/prepare-step.ts +7 -0
- package/src/utils/cost.ts +49 -0
|
@@ -33,6 +33,7 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
33
33
|
inputCostPer1M: 10,
|
|
34
34
|
outputCostPer1M: 50,
|
|
35
35
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 1, writeCostPer1M: 12.5 },
|
|
36
|
+
webSearchCostPer1000: 10,
|
|
36
37
|
},
|
|
37
38
|
],
|
|
38
39
|
[
|
|
@@ -41,6 +42,7 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
41
42
|
inputCostPer1M: 10,
|
|
42
43
|
outputCostPer1M: 50,
|
|
43
44
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 0.25, writeCostPer1M: 12.5 },
|
|
45
|
+
webSearchCostPer1000: 10,
|
|
44
46
|
},
|
|
45
47
|
],
|
|
46
48
|
[
|
|
@@ -49,6 +51,8 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
49
51
|
inputCostPer1M: 8,
|
|
50
52
|
outputCostPer1M: 40,
|
|
51
53
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 0.2, writeCostPer1M: 10 },
|
|
54
|
+
fastMultiplier: 2,
|
|
55
|
+
webSearchCostPer1000: 10,
|
|
52
56
|
},
|
|
53
57
|
],
|
|
54
58
|
[
|
|
@@ -57,6 +61,7 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
57
61
|
inputCostPer1M: 1,
|
|
58
62
|
outputCostPer1M: 5,
|
|
59
63
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 0.1, writeCostPer1M: 1.25 },
|
|
64
|
+
webSearchCostPer1000: 10,
|
|
60
65
|
},
|
|
61
66
|
],
|
|
62
67
|
[
|
|
@@ -65,6 +70,7 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
65
70
|
inputCostPer1M: 10,
|
|
66
71
|
outputCostPer1M: 50,
|
|
67
72
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 1, writeCostPer1M: 12.5 },
|
|
73
|
+
webSearchCostPer1000: 10,
|
|
68
74
|
},
|
|
69
75
|
],
|
|
70
76
|
[
|
|
@@ -73,6 +79,7 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
73
79
|
inputCostPer1M: 10,
|
|
74
80
|
outputCostPer1M: 50,
|
|
75
81
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 0.25, writeCostPer1M: 12.5 },
|
|
82
|
+
webSearchCostPer1000: 10,
|
|
76
83
|
},
|
|
77
84
|
],
|
|
78
85
|
[
|
|
@@ -81,6 +88,8 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
81
88
|
inputCostPer1M: 8,
|
|
82
89
|
outputCostPer1M: 40,
|
|
83
90
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 0.2, writeCostPer1M: 10 },
|
|
91
|
+
fastMultiplier: 2,
|
|
92
|
+
webSearchCostPer1000: 10,
|
|
84
93
|
},
|
|
85
94
|
],
|
|
86
95
|
[
|
|
@@ -89,6 +98,7 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
89
98
|
inputCostPer1M: 15,
|
|
90
99
|
outputCostPer1M: 75,
|
|
91
100
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 1.5, writeCostPer1M: 18.75 },
|
|
101
|
+
webSearchCostPer1000: 10,
|
|
92
102
|
},
|
|
93
103
|
],
|
|
94
104
|
[
|
|
@@ -97,6 +107,7 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
97
107
|
inputCostPer1M: 15,
|
|
98
108
|
outputCostPer1M: 75,
|
|
99
109
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 1.5, writeCostPer1M: 18.75 },
|
|
110
|
+
webSearchCostPer1000: 10,
|
|
100
111
|
},
|
|
101
112
|
],
|
|
102
113
|
[
|
|
@@ -105,6 +116,7 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
105
116
|
inputCostPer1M: 5,
|
|
106
117
|
outputCostPer1M: 25,
|
|
107
118
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 0.5, writeCostPer1M: 6.25 },
|
|
119
|
+
webSearchCostPer1000: 10,
|
|
108
120
|
},
|
|
109
121
|
],
|
|
110
122
|
[
|
|
@@ -113,6 +125,7 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
113
125
|
inputCostPer1M: 5,
|
|
114
126
|
outputCostPer1M: 25,
|
|
115
127
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 0.5, writeCostPer1M: 6.25 },
|
|
128
|
+
webSearchCostPer1000: 10,
|
|
116
129
|
},
|
|
117
130
|
],
|
|
118
131
|
[
|
|
@@ -121,6 +134,8 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
121
134
|
inputCostPer1M: 5,
|
|
122
135
|
outputCostPer1M: 25,
|
|
123
136
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 0.5, writeCostPer1M: 6.25 },
|
|
137
|
+
fastMultiplier: 2,
|
|
138
|
+
webSearchCostPer1000: 10,
|
|
124
139
|
},
|
|
125
140
|
],
|
|
126
141
|
[
|
|
@@ -129,6 +144,8 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
129
144
|
inputCostPer1M: 5,
|
|
130
145
|
outputCostPer1M: 25,
|
|
131
146
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 0.5, writeCostPer1M: 6.25 },
|
|
147
|
+
fastMultiplier: 2,
|
|
148
|
+
webSearchCostPer1000: 10,
|
|
132
149
|
},
|
|
133
150
|
],
|
|
134
151
|
[
|
|
@@ -137,6 +154,8 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
137
154
|
inputCostPer1M: 4,
|
|
138
155
|
outputCostPer1M: 20,
|
|
139
156
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 0.2, writeCostPer1M: 5 },
|
|
157
|
+
fastMultiplier: 2,
|
|
158
|
+
webSearchCostPer1000: 10,
|
|
140
159
|
},
|
|
141
160
|
],
|
|
142
161
|
[
|
|
@@ -145,6 +164,7 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
145
164
|
inputCostPer1M: 3,
|
|
146
165
|
outputCostPer1M: 15,
|
|
147
166
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 0.3, writeCostPer1M: 3.75 },
|
|
167
|
+
webSearchCostPer1000: 10,
|
|
148
168
|
},
|
|
149
169
|
],
|
|
150
170
|
[
|
|
@@ -153,6 +173,7 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
153
173
|
inputCostPer1M: 3,
|
|
154
174
|
outputCostPer1M: 15,
|
|
155
175
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 0.3, writeCostPer1M: 3.75 },
|
|
176
|
+
webSearchCostPer1000: 10,
|
|
156
177
|
},
|
|
157
178
|
],
|
|
158
179
|
[
|
|
@@ -161,6 +182,7 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
161
182
|
inputCostPer1M: 3,
|
|
162
183
|
outputCostPer1M: 15,
|
|
163
184
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 0.3, writeCostPer1M: 3.75 },
|
|
185
|
+
webSearchCostPer1000: 10,
|
|
164
186
|
},
|
|
165
187
|
],
|
|
166
188
|
[
|
|
@@ -169,6 +191,7 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
169
191
|
inputCostPer1M: 2,
|
|
170
192
|
outputCostPer1M: 10,
|
|
171
193
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 0.2, writeCostPer1M: 2.5 },
|
|
194
|
+
webSearchCostPer1000: 10,
|
|
172
195
|
},
|
|
173
196
|
],
|
|
174
197
|
[
|
|
@@ -177,6 +200,7 @@ export const VENDOR_RATES: readonly VendorRates[] = [
|
|
|
177
200
|
inputCostPer1M: 2,
|
|
178
201
|
outputCostPer1M: 10,
|
|
179
202
|
cache: { promptIncludesCacheReads: false, readCostPer1M: 0.1, writeCostPer1M: 2.5 },
|
|
203
|
+
webSearchCostPer1000: 10,
|
|
180
204
|
},
|
|
181
205
|
],
|
|
182
206
|
]),
|
|
@@ -19,6 +19,17 @@
|
|
|
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
|
+
"",
|
|
27
|
+
"webSearchPer1000 (optional, per vendor) is the price in USD of 1,000 hosted web",
|
|
28
|
+
"searches, billed per request on top of tokens (verified 2026-11-10 against the",
|
|
29
|
+
"pricing page's web search section: $10 per 1,000, a failed search is not billed).",
|
|
30
|
+
"It is copied onto every model row of that vendor. Absent means searches are not",
|
|
31
|
+
"part of the total.",
|
|
32
|
+
"",
|
|
22
33
|
"Matching is EXACT on a normalised id (lowercased, one trailing -YYYYMMDD or",
|
|
23
34
|
"@YYYYMMDD snapshot suffix removed). Deliberately not prefix or substring:",
|
|
24
35
|
"within one vendor here, ids one character apart differ in price by 4x, so a",
|
|
@@ -59,6 +70,7 @@
|
|
|
59
70
|
"verified": "2026-11-10",
|
|
60
71
|
"promptIncludesCacheReads": false,
|
|
61
72
|
"reportsCacheWrites": true,
|
|
73
|
+
"webSearchPer1000": 10,
|
|
62
74
|
"note": "The last two rows exist because the driver's own offline catalogue offers those models and this table did not price them — a lookup-key gap that reads as `cost unknown` and is invisible to the generator's own check, which only proves the module matches this file. `providers/anthropic` asserts the two lists agree. Vendor list prices, every row checked against its pricing page on the `verified` date. Cache read is the vendor's published 0.1x of the input rate, except on the six models it prices differently: 0.05x on claude-opus-5-5 and claude-sonnet-5-5 and 0.025x on claude-fable-5-1, claude-mythos-5-1, claude-fable-5-2 and claude-mythos-5-2, entered at the published rate rather than derived. claude-haiku-5-5 has no row on purpose: the vendor prices it by prompt length ($0.10 in / $0.50 out up to 100,000 prompt tokens, $0.50 / $2.50 above, cache counted in the length), this table holds one rate per model, and either single rate would be wrong for the other half of requests, so its cost reports unknown. Cache write is its published 1.25x for the five-minute entry, which is the default TTL and the one the driver's `cacheControl: { type: 'auto' }` asks for. claude-sonnet-5 launched at an introductory $2/$10 with $3/$15 scheduled from 2026-09-01, and this table recorded the scheduled rate; the vendor has since made $2/$10 the standard price and cancelled the increase. The table has no time dimension, so a future promotional window is still recorded at the list rate and over-reported rather than mis-modelled.",
|
|
63
75
|
"models": [
|
|
64
76
|
{
|
|
@@ -66,14 +78,16 @@
|
|
|
66
78
|
"inputPer1M": 8,
|
|
67
79
|
"outputPer1M": 40,
|
|
68
80
|
"cacheReadPer1M": 0.2,
|
|
69
|
-
"cacheWritePer1M": 10
|
|
81
|
+
"cacheWritePer1M": 10,
|
|
82
|
+
"fastMultiplier": 2
|
|
70
83
|
},
|
|
71
84
|
{
|
|
72
85
|
"id": "claude-mythos-5-2",
|
|
73
86
|
"inputPer1M": 8,
|
|
74
87
|
"outputPer1M": 40,
|
|
75
88
|
"cacheReadPer1M": 0.2,
|
|
76
|
-
"cacheWritePer1M": 10
|
|
89
|
+
"cacheWritePer1M": 10,
|
|
90
|
+
"fastMultiplier": 2
|
|
77
91
|
},
|
|
78
92
|
{
|
|
79
93
|
"id": "claude-fable-5-1",
|
|
@@ -94,7 +108,8 @@
|
|
|
94
108
|
"inputPer1M": 4,
|
|
95
109
|
"outputPer1M": 20,
|
|
96
110
|
"cacheReadPer1M": 0.2,
|
|
97
|
-
"cacheWritePer1M": 5
|
|
111
|
+
"cacheWritePer1M": 5,
|
|
112
|
+
"fastMultiplier": 2
|
|
98
113
|
},
|
|
99
114
|
{
|
|
100
115
|
"id": "claude-sonnet-5-5",
|
|
@@ -122,14 +137,16 @@
|
|
|
122
137
|
"inputPer1M": 5,
|
|
123
138
|
"outputPer1M": 25,
|
|
124
139
|
"cacheReadPer1M": 0.5,
|
|
125
|
-
"cacheWritePer1M": 6.25
|
|
140
|
+
"cacheWritePer1M": 6.25,
|
|
141
|
+
"fastMultiplier": 2
|
|
126
142
|
},
|
|
127
143
|
{
|
|
128
144
|
"id": "claude-opus-4-8",
|
|
129
145
|
"inputPer1M": 5,
|
|
130
146
|
"outputPer1M": 25,
|
|
131
147
|
"cacheReadPer1M": 0.5,
|
|
132
|
-
"cacheWritePer1M": 6.25
|
|
148
|
+
"cacheWritePer1M": 6.25,
|
|
149
|
+
"fastMultiplier": 2
|
|
133
150
|
},
|
|
134
151
|
{
|
|
135
152
|
"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,
|
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
} from '../../../utils/backoff.js'
|
|
39
39
|
import { SCOPE_ATTRIBUTE } from '../../../utils/log/types.js'
|
|
40
40
|
import { type Logger, resolveLogger } from '../../../utils/logger.js'
|
|
41
|
+
import { chatStreamWithSamplingRepair } from '../iteration/side-call.js'
|
|
41
42
|
import {
|
|
42
43
|
STAGE_ONE_INSTRUCTION,
|
|
43
44
|
STAGE_TWO_INSTRUCTION,
|
|
@@ -209,7 +210,7 @@ export function createAutoReviewClassifier(
|
|
|
209
210
|
// ignores it would otherwise hold the call open past its deadline, and
|
|
210
211
|
// a turn cancelled while it waits would wait with it.
|
|
211
212
|
const collected = collectChatCompletion(
|
|
212
|
-
options.provider
|
|
213
|
+
chatStreamWithSamplingRepair(options.provider, {
|
|
213
214
|
model: options.model,
|
|
214
215
|
messages,
|
|
215
216
|
maxTokens: stage === 1 ? 64 : 8_192,
|
|
@@ -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
|
: {}),
|
|
@@ -1355,6 +1383,9 @@ export class IterationOrchestrator {
|
|
|
1355
1383
|
},
|
|
1356
1384
|
}
|
|
1357
1385
|
: {}),
|
|
1386
|
+
...(response.usage.cacheMiss !== undefined
|
|
1387
|
+
? { cacheMiss: response.usage.cacheMiss }
|
|
1388
|
+
: {}),
|
|
1358
1389
|
...contextFigures,
|
|
1359
1390
|
})
|
|
1360
1391
|
|
|
@@ -3180,6 +3211,42 @@ export class IterationOrchestrator {
|
|
|
3180
3211
|
return 'settled'
|
|
3181
3212
|
}
|
|
3182
3213
|
|
|
3214
|
+
const withholdKeys = this.ctx.withholdOnRefusal
|
|
3215
|
+
if (
|
|
3216
|
+
!input.forceFinalize &&
|
|
3217
|
+
!this.refusalWithholdUsed &&
|
|
3218
|
+
withholdKeys &&
|
|
3219
|
+
this.ctx.withheldKeys
|
|
3220
|
+
) {
|
|
3221
|
+
const carried = withholdKeys.filter(
|
|
3222
|
+
(key) =>
|
|
3223
|
+
!this.ctx.withheldKeys?.has(key) &&
|
|
3224
|
+
recorder.messages.some((message) => turnContextKey(message) === key),
|
|
3225
|
+
)
|
|
3226
|
+
if (carried.length > 0) {
|
|
3227
|
+
this.refusalWithholdUsed = true
|
|
3228
|
+
for (const key of carried) this.ctx.withheldKeys.add(key)
|
|
3229
|
+
const memoryIds = carried.includes(RECALLED_MEMORY_ENTRY_KEY)
|
|
3230
|
+
? recalledMemoryIds(turnContextEntries(recorder.messages, RECALLED_MEMORY_ENTRY_KEY))
|
|
3231
|
+
: []
|
|
3232
|
+
await this.ctx.emitEvent({
|
|
3233
|
+
type: 'model_refusal',
|
|
3234
|
+
turnId: recorder.turnId,
|
|
3235
|
+
iteration: iterationNum,
|
|
3236
|
+
model: servedBy.model,
|
|
3237
|
+
providerId: servedBy.providerId,
|
|
3238
|
+
outcome: 'withheld',
|
|
3239
|
+
withheldKeys: carried,
|
|
3240
|
+
...(memoryIds.length > 0 ? { withheldMemoryIds: memoryIds } : {}),
|
|
3241
|
+
...(refusal.category ? { category: refusal.category } : {}),
|
|
3242
|
+
...(refusal.explanation ? { explanation: refusal.explanation } : {}),
|
|
3243
|
+
})
|
|
3244
|
+
await closeIteration()
|
|
3245
|
+
yield* this.ctx.drainPending()
|
|
3246
|
+
return 'retry'
|
|
3247
|
+
}
|
|
3248
|
+
}
|
|
3249
|
+
|
|
3183
3250
|
if (!input.forceFinalize && !this.refusalFallbackUsed && this.ctx.refusalFallback !== 'off') {
|
|
3184
3251
|
const next = await this.refusalFallbackModel(input.stepModel, refusal)
|
|
3185
3252
|
if (next !== undefined) {
|
|
@@ -3369,7 +3436,7 @@ export class IterationOrchestrator {
|
|
|
3369
3436
|
]
|
|
3370
3437
|
const finalMessages = projectRequestRichContent(
|
|
3371
3438
|
withoutVoidAssistantTurns(this.projectObservations(finalHistory)),
|
|
3372
|
-
this.
|
|
3439
|
+
this.richContentBudget(),
|
|
3373
3440
|
{ imagesReadable: this.modelReadsImages(model) },
|
|
3374
3441
|
)
|
|
3375
3442
|
// The closing directive is the last thing the model reads: after
|
|
@@ -3411,6 +3478,7 @@ export class IterationOrchestrator {
|
|
|
3411
3478
|
// is exactly the shape a field goes missing from — so it is tested
|
|
3412
3479
|
// separately rather than assumed to have been kept in step.
|
|
3413
3480
|
...(this.ctx.turnConfig.effort ? { effort: this.ctx.turnConfig.effort } : {}),
|
|
3481
|
+
...(this.ctx.turnConfig.speed ? { speed: this.ctx.turnConfig.speed } : {}),
|
|
3414
3482
|
// Cancellable too: a Stop during the closing summary must not
|
|
3415
3483
|
// stream to completion.
|
|
3416
3484
|
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.
|
|
@@ -39,7 +39,13 @@ import { isProviderRejectedImageError } from './provider-rejected-image.js'
|
|
|
39
39
|
* compaction summaries, do not pass through it.
|
|
40
40
|
*/
|
|
41
41
|
|
|
42
|
-
export type RejectedParameter =
|
|
42
|
+
export type RejectedParameter =
|
|
43
|
+
| 'effort'
|
|
44
|
+
| 'thinking'
|
|
45
|
+
| 'temperature'
|
|
46
|
+
| 'topP'
|
|
47
|
+
| 'topK'
|
|
48
|
+
| 'responseFormat'
|
|
43
49
|
|
|
44
50
|
export interface MediaRemoval {
|
|
45
51
|
readonly count: number
|
|
@@ -110,6 +116,7 @@ const PARAMETER_NAMES: Record<RejectedParameter, string> = {
|
|
|
110
116
|
thinking: 'thinking',
|
|
111
117
|
temperature: 'temperature',
|
|
112
118
|
topP: 'top[_ ]?p',
|
|
119
|
+
topK: 'top[_ ]?k',
|
|
113
120
|
responseFormat:
|
|
114
121
|
'(?:response_format|output_config(?:\\.format)?|json_schema|json_object|structured\\s+output)',
|
|
115
122
|
}
|
|
@@ -124,6 +131,10 @@ const PARAMETER_PATTERNS = Object.fromEntries(
|
|
|
124
131
|
]),
|
|
125
132
|
) as Record<RejectedParameter, { named: RegExp; refused: RegExp }>
|
|
126
133
|
|
|
134
|
+
const SAMPLING = ['temperature', 'topP', 'topK'] as const satisfies readonly RejectedParameter[]
|
|
135
|
+
const SAMPLING_GROUP =
|
|
136
|
+
/\btemperature\b.{0,80}\btop[_ ]?[pk]\b|\btop[_ ]?[pk]\b.{0,80}\btemperature\b/i
|
|
137
|
+
|
|
127
138
|
const BOTH_SAMPLING =
|
|
128
139
|
/temperature.{0,60}top[_ ]?p.{0,80}(?:cannot|can['’]t|may\s+not|should\s+not).{0,20}(?:both|together)/i
|
|
129
140
|
|
|
@@ -156,6 +167,7 @@ function rejectedParameters(
|
|
|
156
167
|
thinking: params.thinking !== undefined,
|
|
157
168
|
temperature: params.temperature !== undefined,
|
|
158
169
|
topP: params.topP !== undefined,
|
|
170
|
+
topK: params.topK !== undefined,
|
|
159
171
|
responseFormat: params.responseFormat !== undefined,
|
|
160
172
|
} satisfies Record<RejectedParameter, boolean>
|
|
161
173
|
const found: RejectedParameter[] = []
|
|
@@ -165,6 +177,12 @@ function rejectedParameters(
|
|
|
165
177
|
if (structured ? pattern.named.test(text) : pattern.refused.test(text)) found.push(name)
|
|
166
178
|
}
|
|
167
179
|
if (found.length === 0 && set.topP && BOTH_SAMPLING.test(text)) found.push('topP')
|
|
180
|
+
// The vendor words a refusal of sampling controls as a group ("Omit
|
|
181
|
+
// temperature, top_p, and top_k"), so naming one of them in a refusal that
|
|
182
|
+
// names the others is enough for whichever of them was sent.
|
|
183
|
+
if (found.length === 0 && SAMPLING_GROUP.test(text)) {
|
|
184
|
+
for (const name of SAMPLING) if (set[name]) found.push(name)
|
|
185
|
+
}
|
|
168
186
|
return found
|
|
169
187
|
}
|
|
170
188
|
|
|
@@ -726,6 +744,7 @@ function withoutParameters(
|
|
|
726
744
|
if (names.has('thinking')) next.thinking = undefined
|
|
727
745
|
if (names.has('temperature')) next.temperature = undefined
|
|
728
746
|
if (names.has('topP')) next.topP = undefined
|
|
747
|
+
if (names.has('topK')) next.topK = undefined
|
|
729
748
|
if (names.has('responseFormat')) next.responseFormat = undefined
|
|
730
749
|
return next
|
|
731
750
|
}
|
|
@@ -741,3 +760,25 @@ function isHandledElsewhere(error: unknown, params: ChatCompletionParams): boole
|
|
|
741
760
|
}
|
|
742
761
|
return isImageInputRefusal(error)
|
|
743
762
|
}
|
|
763
|
+
|
|
764
|
+
/**
|
|
765
|
+
* Which of `temperature`, `top_p` and `top_k` a provider refused on this
|
|
766
|
+
* request, from the same reading of its rejection the main turn uses. Empty
|
|
767
|
+
* for any other failure, so a caller can strip exactly these and nothing else.
|
|
768
|
+
*/
|
|
769
|
+
export function rejectedSamplingParameters(
|
|
770
|
+
error: unknown,
|
|
771
|
+
params: ChatCompletionParams,
|
|
772
|
+
): RejectedParameter[] {
|
|
773
|
+
const rejection = classifyRequestRejection(error, params)
|
|
774
|
+
if (rejection?.kind !== 'parameter') return []
|
|
775
|
+
return rejection.parameters.filter((name) => (SAMPLING as readonly string[]).includes(name))
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
/** The request without the named sampling parameters. */
|
|
779
|
+
export function withoutSamplingParameters(
|
|
780
|
+
params: ChatCompletionParams,
|
|
781
|
+
names: ReadonlySet<RejectedParameter>,
|
|
782
|
+
): ChatCompletionParams {
|
|
783
|
+
return withoutParameters(params, names)
|
|
784
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ChatCompletionParams,
|
|
3
|
+
LLMProvider,
|
|
4
|
+
StreamChunk,
|
|
5
|
+
} from '../../../types/provider/index.js'
|
|
6
|
+
import {
|
|
7
|
+
type RejectedParameter,
|
|
8
|
+
rejectedSamplingParameters,
|
|
9
|
+
withoutSamplingParameters,
|
|
10
|
+
} from './request-repair.js'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* What each model was found to refuse, for the life of the provider object.
|
|
14
|
+
* Weakly keyed so a dropped provider takes its entry with it.
|
|
15
|
+
*/
|
|
16
|
+
const refused = new WeakMap<object, Map<string, Set<RejectedParameter>>>()
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A model call made outside the turn loop (a compaction summary, its verifier,
|
|
20
|
+
* the auto-review classifier) that asks for a deterministic answer with
|
|
21
|
+
* `temperature: 0`. Current models refuse sampling parameters outright, and
|
|
22
|
+
* the turn loop already recovers from that; this gives side calls the same
|
|
23
|
+
* recovery instead of letting the call fail and the feature with it.
|
|
24
|
+
*
|
|
25
|
+
* The request goes out as asked. If the provider refuses a sampling parameter
|
|
26
|
+
* BEFORE any output arrived, it is resent without exactly those parameters,
|
|
27
|
+
* and the finding is kept for the model so later calls omit them up front.
|
|
28
|
+
* Nothing is kept unless the resend was accepted, and any other failure is
|
|
29
|
+
* thrown unchanged.
|
|
30
|
+
*/
|
|
31
|
+
export async function* chatStreamWithSamplingRepair(
|
|
32
|
+
provider: LLMProvider,
|
|
33
|
+
params: ChatCompletionParams,
|
|
34
|
+
): AsyncGenerator<StreamChunk> {
|
|
35
|
+
const perModel = refused.get(provider) ?? new Map<string, Set<RejectedParameter>>()
|
|
36
|
+
refused.set(provider, perModel)
|
|
37
|
+
const known = perModel.get(params.model)
|
|
38
|
+
let request = known ? withoutSamplingParameters(params, known) : params
|
|
39
|
+
let stripped: Set<RejectedParameter> | undefined
|
|
40
|
+
for (;;) {
|
|
41
|
+
let yielded = false
|
|
42
|
+
try {
|
|
43
|
+
for await (const chunk of provider.chatStream(request)) {
|
|
44
|
+
yielded = true
|
|
45
|
+
yield chunk
|
|
46
|
+
}
|
|
47
|
+
if (stripped) {
|
|
48
|
+
const merged = new Set([...(perModel.get(params.model) ?? []), ...stripped])
|
|
49
|
+
perModel.set(params.model, merged)
|
|
50
|
+
}
|
|
51
|
+
return
|
|
52
|
+
} catch (error) {
|
|
53
|
+
if (yielded || stripped) throw error
|
|
54
|
+
const names = rejectedSamplingParameters(error, request)
|
|
55
|
+
if (names.length === 0) throw error
|
|
56
|
+
stripped = new Set(names)
|
|
57
|
+
request = withoutSamplingParameters(request, stripped)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|