mohdel 0.98.0 → 0.98.1
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.
|
@@ -107,6 +107,7 @@ export async function * runChatCompletions (envelope, client, config, deps = {})
|
|
|
107
107
|
|
|
108
108
|
let content = message.content || ''
|
|
109
109
|
let toolCalls = message.tool_calls
|
|
110
|
+
const reasoning = message.reasoning_content || null
|
|
110
111
|
|
|
111
112
|
if (config.parseDsml && content && (!toolCalls || !toolCalls.length)) {
|
|
112
113
|
const dsml = parseDsmlToolCalls(content)
|
|
@@ -121,7 +122,7 @@ export async function * runChatCompletions (envelope, client, config, deps = {})
|
|
|
121
122
|
}
|
|
122
123
|
|
|
123
124
|
yield finalize({
|
|
124
|
-
envelope, content, toolCalls, usage, finishReason, start, first
|
|
125
|
+
envelope, content, toolCalls, usage, finishReason, start, first, reasoning
|
|
125
126
|
})
|
|
126
127
|
}
|
|
127
128
|
|
|
@@ -140,6 +141,7 @@ async function * runStreaming (envelope, client, args, config, start, deps) {
|
|
|
140
141
|
// F53: accumulate via array + join to avoid per-delta V8 cons-string
|
|
141
142
|
// churn on long streams.
|
|
142
143
|
const contentParts = []
|
|
144
|
+
const reasoningParts = []
|
|
143
145
|
let first = null
|
|
144
146
|
let finishReason = null
|
|
145
147
|
let usage = {}
|
|
@@ -164,12 +166,13 @@ async function * runStreaming (envelope, client, args, config, start, deps) {
|
|
|
164
166
|
for await (const chunk of stream) {
|
|
165
167
|
const choice = chunk.choices?.[0]
|
|
166
168
|
// DeepSeek V4 / deepseek-reasoner / Cerebras reasoning models emit
|
|
167
|
-
// `delta.reasoning_content` chunks before visible content.
|
|
168
|
-
//
|
|
169
|
-
//
|
|
170
|
-
//
|
|
171
|
-
if (choice?.delta?.reasoning_content
|
|
172
|
-
first = String(process.hrtime.bigint())
|
|
169
|
+
// `delta.reasoning_content` chunks before visible content. Capture
|
|
170
|
+
// them so multi-turn callers can roundtrip reasoning back to the
|
|
171
|
+
// API (DeepSeek V4 hard-rejects assistant messages without it).
|
|
172
|
+
// Token count comes from `usage.completion_tokens_details.reasoning_tokens`.
|
|
173
|
+
if (choice?.delta?.reasoning_content) {
|
|
174
|
+
if (first === null) first = String(process.hrtime.bigint())
|
|
175
|
+
reasoningParts.push(choice.delta.reasoning_content)
|
|
173
176
|
}
|
|
174
177
|
if (choice?.delta?.content) {
|
|
175
178
|
if (first === null) first = String(process.hrtime.bigint())
|
|
@@ -235,7 +238,8 @@ async function * runStreaming (envelope, client, args, config, start, deps) {
|
|
|
235
238
|
usage,
|
|
236
239
|
finishReason,
|
|
237
240
|
start,
|
|
238
|
-
first
|
|
241
|
+
first,
|
|
242
|
+
reasoning: reasoningParts.length ? reasoningParts.join('') : null
|
|
239
243
|
})
|
|
240
244
|
}
|
|
241
245
|
|
|
@@ -247,11 +251,12 @@ async function * runStreaming (envelope, client, args, config, start, deps) {
|
|
|
247
251
|
* usage: any,
|
|
248
252
|
* finishReason: string | null,
|
|
249
253
|
* start: string,
|
|
250
|
-
* first: string | null
|
|
254
|
+
* first: string | null,
|
|
255
|
+
* reasoning?: string | null
|
|
251
256
|
* }} p
|
|
252
257
|
* @returns {import('#core/events.js').DoneEvent}
|
|
253
258
|
*/
|
|
254
|
-
function finalize ({ envelope, content, toolCalls, usage, finishReason, start, first }) {
|
|
259
|
+
function finalize ({ envelope, content, toolCalls, usage, finishReason, start, first, reasoning = null }) {
|
|
255
260
|
const end = String(process.hrtime.bigint())
|
|
256
261
|
const inputTokens = usage.prompt_tokens || 0
|
|
257
262
|
const totalOutputTokens = usage.completion_tokens || 0
|
|
@@ -282,6 +287,7 @@ function finalize ({ envelope, content, toolCalls, usage, finishReason, start, f
|
|
|
282
287
|
if (toolCalls && toolCalls.length > 0) {
|
|
283
288
|
done.result.toolCalls = fromCerebrasToolCalls(toolCalls)
|
|
284
289
|
}
|
|
290
|
+
if (reasoning) done.result.reasoning = reasoning
|
|
285
291
|
return done
|
|
286
292
|
}
|
|
287
293
|
|
|
@@ -357,11 +363,12 @@ function toChatMessages (prompt) {
|
|
|
357
363
|
content: flattenText(m.content)
|
|
358
364
|
}
|
|
359
365
|
}
|
|
366
|
+
const reasoning = m.role === 'assistant' ? extractReasoning(m.content) : null
|
|
360
367
|
if (m.role === 'assistant' && m.toolCalls?.length) {
|
|
361
368
|
// Chat Completions assistant turn: optional `content` + the
|
|
362
369
|
// `tool_calls` array. `arguments` must be a JSON string on
|
|
363
370
|
// the wire.
|
|
364
|
-
|
|
371
|
+
const msg = {
|
|
365
372
|
role: 'assistant',
|
|
366
373
|
content: flattenText(m.content) || '',
|
|
367
374
|
tool_calls: m.toolCalls.map(tc => ({
|
|
@@ -373,8 +380,12 @@ function toChatMessages (prompt) {
|
|
|
373
380
|
}
|
|
374
381
|
}))
|
|
375
382
|
}
|
|
383
|
+
if (reasoning) msg.reasoning_content = reasoning
|
|
384
|
+
return msg
|
|
376
385
|
}
|
|
377
|
-
|
|
386
|
+
const msg = { role: m.role, content: flattenText(m.content) }
|
|
387
|
+
if (reasoning) msg.reasoning_content = reasoning
|
|
388
|
+
return msg
|
|
378
389
|
})
|
|
379
390
|
}
|
|
380
391
|
|
|
@@ -391,6 +402,13 @@ function flattenText (content) {
|
|
|
391
402
|
return content.filter(p => p.type === 'text' && p.text).map(p => p.text).join('\n')
|
|
392
403
|
}
|
|
393
404
|
|
|
405
|
+
/** @param {string | import('#core/envelope.js').MessagePart[]} content */
|
|
406
|
+
function extractReasoning (content) {
|
|
407
|
+
if (typeof content === 'string' || !Array.isArray(content)) return null
|
|
408
|
+
const parts = content.filter(p => p.type === 'reasoning' && p.text).map(p => p.text)
|
|
409
|
+
return parts.length ? parts.join('\n') : null
|
|
410
|
+
}
|
|
411
|
+
|
|
394
412
|
/**
|
|
395
413
|
* @param {any} args
|
|
396
414
|
* @param {import('#core/envelope.js').MediaRef[]} images
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mohdel",
|
|
3
|
-
"version": "0.98.
|
|
3
|
+
"version": "0.98.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Christophe Le Bars",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"@opentelemetry/exporter-trace-otlp-grpc": "^0.215.0",
|
|
88
88
|
"@opentelemetry/sdk-node": "^0.215.0",
|
|
89
89
|
"chalk": "^5.4.0",
|
|
90
|
-
"mohdel-thin-gate-linux-x64-gnu": "0.98.
|
|
90
|
+
"mohdel-thin-gate-linux-x64-gnu": "0.98.1"
|
|
91
91
|
},
|
|
92
92
|
"dependencies": {
|
|
93
93
|
"@anthropic-ai/sdk": "^0.91.1",
|