mohdel 3.8.0 → 3.9.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/js/core/envelope.js
CHANGED
|
@@ -122,6 +122,13 @@
|
|
|
122
122
|
* @property {('text'|'reasoning'|'image')} type
|
|
123
123
|
* @property {string} [text]
|
|
124
124
|
* Required on `text` and `reasoning` parts.
|
|
125
|
+
* @property {string} [encrypted]
|
|
126
|
+
* On a `reasoning` part: the provider's opaque reasoning, replayed only
|
|
127
|
+
* to `model` and dropped for any other.
|
|
128
|
+
* @property {string} [id]
|
|
129
|
+
* On a `reasoning` part carrying `encrypted`: the provider's item id.
|
|
130
|
+
* @property {string} [model]
|
|
131
|
+
* On a `reasoning` part carrying `encrypted`: the model that produced it.
|
|
125
132
|
* @property {string} [fileUri]
|
|
126
133
|
* Required on `image` parts. Same schemes and local-read rules as
|
|
127
134
|
* an envelope `images` ref. Accepted on `user` and `tool` messages.
|
package/js/core/events.js
CHANGED
|
@@ -101,6 +101,10 @@
|
|
|
101
101
|
* `'insufficientOutputBudget' | 'aborted' | ...` additive union.
|
|
102
102
|
* @property {ToolCall[]} [toolCalls]
|
|
103
103
|
* Present when `status === 'tool_use'`.
|
|
104
|
+
* @property {import('./envelope.js').MessagePart[]} [reasoningParts]
|
|
105
|
+
* Reasoning parts carrying `encrypted`, from a provider that returns its
|
|
106
|
+
* reasoning to be replayed. A multi-turn caller puts them at the head
|
|
107
|
+
* of the assistant message it records for this result.
|
|
104
108
|
* @property {number} [maxInterFrameMs]
|
|
105
109
|
* Longest gap (ms) between adapter events during the call —
|
|
106
110
|
* from `startedAt` to the first frame, between consecutive
|
|
@@ -262,6 +262,11 @@ async function * runStreaming (envelope, client, args, config, start, deps) {
|
|
|
262
262
|
return
|
|
263
263
|
}
|
|
264
264
|
|
|
265
|
+
if (finishReason === null) {
|
|
266
|
+
yield { type: 'error', error: classifyProviderError(new Error(`${config.provider} stream ended before completion`), envelope.auth?.key, { provider: config.provider }) }
|
|
267
|
+
return
|
|
268
|
+
}
|
|
269
|
+
|
|
265
270
|
const collectedToolCalls = Object.values(toolCallAccum).map(tc => ({
|
|
266
271
|
id: tc.id,
|
|
267
272
|
function: { name: tc.name, arguments: tc.arguments }
|
|
@@ -557,7 +562,7 @@ function flattenText (content) {
|
|
|
557
562
|
/** @param {string | import('#core/envelope.js').MessagePart[]} content */
|
|
558
563
|
function extractReasoning (content) {
|
|
559
564
|
if (typeof content === 'string' || !Array.isArray(content)) return null
|
|
560
|
-
const parts = content.filter(p => p.type === 'reasoning' && p.text).map(p => p.text)
|
|
565
|
+
const parts = content.filter(p => p.type === 'reasoning' && p.text && !p.encrypted).map(p => p.text)
|
|
561
566
|
return parts.length ? parts.join('\n') : null
|
|
562
567
|
}
|
|
563
568
|
|
|
@@ -70,7 +70,8 @@ export async function * openai (envelope, deps = {}) {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
const { instructions, input } = splitPrompt(envelope.prompt, imageParts, {
|
|
73
|
-
toolResultImages: ['openai', 'chatgpt'].includes(providerOf(envelope.model))
|
|
73
|
+
toolResultImages: ['openai', 'chatgpt'].includes(providerOf(envelope.model)),
|
|
74
|
+
model: envelope.model
|
|
74
75
|
})
|
|
75
76
|
if (imageInputs.length) injectImageParts(input, imageInputs)
|
|
76
77
|
|
|
@@ -94,6 +95,8 @@ export async function * openai (envelope, deps = {}) {
|
|
|
94
95
|
// Tool-call accumulation: itemId → {call_id, name, arguments}
|
|
95
96
|
/** @type {Map<string, {call_id: string, name: string, arguments: string}>} */
|
|
96
97
|
const toolItems = new Map()
|
|
98
|
+
/** @type {import('#core/envelope.js').MessagePart[]} */
|
|
99
|
+
const reasoningParts = []
|
|
97
100
|
|
|
98
101
|
try {
|
|
99
102
|
const stream = await client.responses.stream(request, { signal })
|
|
@@ -122,6 +125,18 @@ export async function * openai (envelope, deps = {}) {
|
|
|
122
125
|
}
|
|
123
126
|
break
|
|
124
127
|
|
|
128
|
+
case 'response.output_item.done':
|
|
129
|
+
if (event.item?.type === 'reasoning' && event.item.encrypted_content) {
|
|
130
|
+
reasoningParts.push({
|
|
131
|
+
type: 'reasoning',
|
|
132
|
+
text: (event.item.summary ?? []).map(s => s.text).join('\n'),
|
|
133
|
+
id: event.item.id,
|
|
134
|
+
encrypted: event.item.encrypted_content,
|
|
135
|
+
model: envelope.model
|
|
136
|
+
})
|
|
137
|
+
}
|
|
138
|
+
break
|
|
139
|
+
|
|
125
140
|
case 'response.function_call_arguments.delta':
|
|
126
141
|
if (event.item_id && event.delta) {
|
|
127
142
|
const t = toolItems.get(event.item_id)
|
|
@@ -167,12 +182,12 @@ export async function * openai (envelope, deps = {}) {
|
|
|
167
182
|
}
|
|
168
183
|
break
|
|
169
184
|
|
|
170
|
-
case 'response.failed':
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
185
|
+
case 'response.failed': {
|
|
186
|
+
const provider = providerOf(envelope.model)
|
|
187
|
+
const failure = Object.assign(new Error(`${provider} response failed`), { error: event.response?.error })
|
|
188
|
+
yield { type: 'error', error: classifyProviderError(failure, envelope.auth?.key, { provider }) }
|
|
189
|
+
return
|
|
190
|
+
}
|
|
176
191
|
|
|
177
192
|
default:
|
|
178
193
|
break
|
|
@@ -194,8 +209,9 @@ export async function * openai (envelope, deps = {}) {
|
|
|
194
209
|
}
|
|
195
210
|
|
|
196
211
|
const end = String(process.hrtime.bigint())
|
|
197
|
-
if (
|
|
198
|
-
|
|
212
|
+
if (!terminalResponse) {
|
|
213
|
+
const provider = providerOf(envelope.model)
|
|
214
|
+
yield { type: 'error', error: classifyProviderError(new Error(`${provider} stream ended before completion`), envelope.auth?.key, { provider }) }
|
|
199
215
|
return
|
|
200
216
|
}
|
|
201
217
|
// OpenAI Responses reports `output_tokens` INCLUDING reasoning
|
|
@@ -239,6 +255,7 @@ export async function * openai (envelope, deps = {}) {
|
|
|
239
255
|
}
|
|
240
256
|
}
|
|
241
257
|
if (warning) done.result.warning = warning
|
|
258
|
+
if (reasoningParts.length) done.result.reasoningParts = reasoningParts
|
|
242
259
|
if (toolItems.size > 0) {
|
|
243
260
|
done.result.toolCalls = fromOpenAIToolCalls(Array.from(toolItems.values()))
|
|
244
261
|
}
|
|
@@ -345,6 +362,7 @@ function buildRequest (envelope, input, instructions) {
|
|
|
345
362
|
request.max_output_tokens += headroom
|
|
346
363
|
}
|
|
347
364
|
request.reasoning = { effort }
|
|
365
|
+
if (effort !== 'none') request.include = ['reasoning.encrypted_content']
|
|
348
366
|
}
|
|
349
367
|
}
|
|
350
368
|
|
|
@@ -391,7 +409,7 @@ function buildRequest (envelope, input, instructions) {
|
|
|
391
409
|
*
|
|
392
410
|
* @param {string | import('#core/envelope.js').Message[]} prompt
|
|
393
411
|
* @param {Map<object, import('./_images.js').LoadedImage>} imageParts
|
|
394
|
-
* @param {{toolResultImages: boolean}} opts
|
|
412
|
+
* @param {{toolResultImages: boolean, model: string}} opts
|
|
395
413
|
*/
|
|
396
414
|
function splitPrompt (prompt, imageParts, opts) {
|
|
397
415
|
if (typeof prompt === 'string') {
|
|
@@ -409,6 +427,18 @@ function splitPrompt (prompt, imageParts, opts) {
|
|
|
409
427
|
}
|
|
410
428
|
for (const m of prompt) {
|
|
411
429
|
if (m.role !== 'tool') flushHoisted()
|
|
430
|
+
if (m.role === 'assistant' && Array.isArray(m.content)) {
|
|
431
|
+
for (const p of m.content) {
|
|
432
|
+
if (p.type === 'reasoning' && p.encrypted && p.model === opts.model) {
|
|
433
|
+
input.push({
|
|
434
|
+
type: 'reasoning',
|
|
435
|
+
id: p.id,
|
|
436
|
+
summary: p.text ? [{ type: 'summary_text', text: p.text }] : [],
|
|
437
|
+
encrypted_content: p.encrypted
|
|
438
|
+
})
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
412
442
|
if (m.role === 'system') {
|
|
413
443
|
systemParts.push(flattenText(m.content))
|
|
414
444
|
} else if (m.role === 'tool') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mohdel",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.9.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Christophe Le Bars",
|
|
@@ -144,7 +144,7 @@
|
|
|
144
144
|
"@opentelemetry/exporter-trace-otlp-grpc": "^0.222.0",
|
|
145
145
|
"@opentelemetry/sdk-node": "^0.222.0",
|
|
146
146
|
"chalk": "^6.0.1",
|
|
147
|
-
"mohdel-thin-gate-linux-x64-gnu": "3.
|
|
147
|
+
"mohdel-thin-gate-linux-x64-gnu": "3.9.0"
|
|
148
148
|
},
|
|
149
149
|
"dependencies": {
|
|
150
150
|
"@anthropic-ai/sdk": "^0.129.0",
|