@miphamai/cli 0.6.1 → 0.6.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miphamai/cli",
3
- "version": "0.6.1",
3
+ "version": "0.6.3",
4
4
  "description": "Mipham Code — Multi-model open-core intelligent coding terminal by MiphamAI",
5
5
  "keywords": [
6
6
  "ai",
@@ -140,6 +140,7 @@ export class QueryEngine {
140
140
  const toolDefs = this.getToolDefinitions()
141
141
 
142
142
  let assistantContent = ''
143
+ let reasoningContent = ''
143
144
  const toolUses: Array<{ id: string; name: string; input: Record<string, unknown> }> = []
144
145
 
145
146
  // Stream model response
@@ -162,6 +163,10 @@ export class QueryEngine {
162
163
  assistantContent += chunk.content
163
164
  }
164
165
 
166
+ if (chunk.reasoning_content) {
167
+ reasoningContent += chunk.reasoning_content
168
+ }
169
+
165
170
  if (chunk.type === 'tool_use' && chunk.toolUse) {
166
171
  toolUses.push({
167
172
  id: chunk.toolUse.id,
@@ -172,16 +177,26 @@ export class QueryEngine {
172
177
 
173
178
  if (chunk.type === 'stop') {
174
179
  // Add assistant response to context
175
- if (assistantContent) {
176
- this.context.addMessage({ role: 'assistant', content: assistantContent })
180
+ if (assistantContent || reasoningContent) {
181
+ const msg: import('../shared/types').Message = {
182
+ role: 'assistant',
183
+ content: assistantContent || '',
184
+ }
185
+ if (reasoningContent) msg.reasoning_content = reasoningContent
186
+ this.context.addMessage(msg)
177
187
  }
178
188
  }
179
189
  }
180
190
  } catch (err) {
181
191
  if (isAbortError(err)) {
182
192
  // User interrupted — keep partial content, stop gracefully
183
- if (assistantContent) {
184
- this.context.addMessage({ role: 'assistant', content: assistantContent })
193
+ if (assistantContent || reasoningContent) {
194
+ const msg: import('../shared/types').Message = {
195
+ role: 'assistant',
196
+ content: assistantContent || '',
197
+ }
198
+ if (reasoningContent) msg.reasoning_content = reasoningContent
199
+ this.context.addMessage(msg)
185
200
  }
186
201
  yield { type: 'stop' }
187
202
  return
@@ -259,6 +274,7 @@ export class QueryEngine {
259
274
  const messages = this.context.getMessages()
260
275
 
261
276
  let assistantContent = ''
277
+ let reasoningContent = ''
262
278
  const toolUses: Array<{ id: string; name: string; input: Record<string, unknown> }> = []
263
279
 
264
280
  try {
@@ -274,6 +290,10 @@ export class QueryEngine {
274
290
  if (chunk.type === 'error') return
275
291
  if (chunk.type === 'text' && chunk.content) assistantContent += chunk.content
276
292
 
293
+ if (chunk.reasoning_content) {
294
+ reasoningContent += chunk.reasoning_content
295
+ }
296
+
277
297
  if (chunk.type === 'tool_use' && chunk.toolUse) {
278
298
  toolUses.push({
279
299
  id: chunk.toolUse.id,
@@ -284,8 +304,13 @@ export class QueryEngine {
284
304
  }
285
305
  } catch (err) {
286
306
  if (isAbortError(err)) {
287
- if (assistantContent) {
288
- this.context.addMessage({ role: 'assistant', content: assistantContent })
307
+ if (assistantContent || reasoningContent) {
308
+ const msg: import('../shared/types').Message = {
309
+ role: 'assistant',
310
+ content: assistantContent || '',
311
+ }
312
+ if (reasoningContent) msg.reasoning_content = reasoningContent
313
+ this.context.addMessage(msg)
289
314
  }
290
315
  yield { type: 'stop' }
291
316
  return
@@ -294,8 +319,13 @@ export class QueryEngine {
294
319
  return
295
320
  }
296
321
 
297
- if (assistantContent) {
298
- this.context.addMessage({ role: 'assistant', content: assistantContent })
322
+ if (assistantContent || reasoningContent) {
323
+ const msg: import('../shared/types').Message = {
324
+ role: 'assistant',
325
+ content: assistantContent || '',
326
+ }
327
+ if (reasoningContent) msg.reasoning_content = reasoningContent
328
+ this.context.addMessage(msg)
299
329
  }
300
330
 
301
331
  // No more tool calls — fire Stop hook and potentially continue
@@ -44,8 +44,9 @@ export class OpenAICompatProvider implements ProviderInstance {
44
44
  const decoder = new TextDecoder()
45
45
  let buffer = ''
46
46
 
47
- // Track incremental tool calls across streaming deltas
47
+ // Track incremental tool calls and reasoning content across streaming deltas
48
48
  const pendingToolCalls = new Map<number, { id: string; name: string; arguments: string }>()
49
+ let reasoningContent = ''
49
50
 
50
51
  while (true) {
51
52
  const { done, value } = await reader.read()
@@ -72,7 +73,7 @@ export class OpenAICompatProvider implements ProviderInstance {
72
73
  },
73
74
  }
74
75
  }
75
- yield { type: 'stop' }
76
+ yield { type: 'stop', reasoning_content: reasoningContent }
76
77
  return
77
78
  }
78
79
 
@@ -104,6 +105,10 @@ export class OpenAICompatProvider implements ProviderInstance {
104
105
  yield { type: 'text', content: delta.content }
105
106
  }
106
107
 
108
+ if (delta?.reasoning_content) {
109
+ reasoningContent += delta.reasoning_content
110
+ }
111
+
107
112
  if (choice.finish_reason === 'tool_calls') {
108
113
  // Emit fully accumulated tool calls
109
114
  for (const [, tc] of pendingToolCalls) {
@@ -121,7 +126,7 @@ export class OpenAICompatProvider implements ProviderInstance {
121
126
  }
122
127
 
123
128
  if (choice.finish_reason === 'stop') {
124
- yield { type: 'stop' }
129
+ yield { type: 'stop', reasoning_content: reasoningContent }
125
130
  }
126
131
  } catch {
127
132
  // skip unparseable chunks
@@ -129,7 +134,7 @@ export class OpenAICompatProvider implements ProviderInstance {
129
134
  }
130
135
  }
131
136
 
132
- yield { type: 'stop' }
137
+ yield { type: 'stop', reasoning_content: reasoningContent }
133
138
  }
134
139
 
135
140
  async listModels(): Promise<ModelInfo[]> {
@@ -174,7 +179,7 @@ export class OpenAICompatProvider implements ProviderInstance {
174
179
  next.content.some((b) => b.type === 'tool_use')
175
180
  ) {
176
181
  const toolUses = next.content.filter((b) => b.type === 'tool_use')
177
- result.push({
182
+ const combinedMsg: Record<string, unknown> = {
178
183
  role: 'assistant',
179
184
  content: msg.content,
180
185
  tool_calls: toolUses.map((tu) => ({
@@ -185,12 +190,20 @@ export class OpenAICompatProvider implements ProviderInstance {
185
190
  arguments: JSON.stringify(tu.input),
186
191
  },
187
192
  })),
188
- })
193
+ }
194
+ if (msg.reasoning_content) {
195
+ combinedMsg.reasoning_content = msg.reasoning_content
196
+ }
197
+ result.push(combinedMsg)
189
198
  i++ // skip the next message (consumed)
190
199
  continue
191
200
  }
192
201
 
193
- result.push({ role: msg.role, content: msg.content })
202
+ const standaloneMsg: Record<string, unknown> = { role: msg.role, content: msg.content }
203
+ if (msg.role === 'assistant' && msg.reasoning_content) {
204
+ standaloneMsg.reasoning_content = msg.reasoning_content
205
+ }
206
+ result.push(standaloneMsg)
194
207
  continue
195
208
  }
196
209
 
@@ -207,7 +220,7 @@ export class OpenAICompatProvider implements ProviderInstance {
207
220
  .map((b) => (b.type === 'text' ? b.text : ''))
208
221
  .join('') || null
209
222
 
210
- result.push({
223
+ const toolUseMsg: Record<string, unknown> = {
211
224
  role: 'assistant',
212
225
  content: textContent,
213
226
  tool_calls: toolUses.map((tu) => ({
@@ -218,7 +231,11 @@ export class OpenAICompatProvider implements ProviderInstance {
218
231
  arguments: JSON.stringify(tu.input),
219
232
  },
220
233
  })),
221
- })
234
+ }
235
+ if (msg.reasoning_content) {
236
+ toolUseMsg.reasoning_content = msg.reasoning_content
237
+ }
238
+ result.push(toolUseMsg)
222
239
  continue
223
240
  }
224
241
 
@@ -46,6 +46,8 @@ export type ContentBlock = TextContent | ImageContent | ToolUseContent | ToolRes
46
46
  export interface Message {
47
47
  role: 'system' | 'user' | 'assistant'
48
48
  content: string | ContentBlock[]
49
+ /** DeepSeek reasoning tokens — must be passed back to the API in multi-turn conversations. */
50
+ reasoning_content?: string
49
51
  }
50
52
 
51
53
  // ── Tool Types ──
@@ -105,6 +107,8 @@ export interface StreamChunk {
105
107
  toolUse?: ToolUseContent
106
108
  tool_use_id?: string
107
109
  error?: string
110
+ /** DeepSeek reasoning tokens accumulated during this stream. */
111
+ reasoning_content?: string
108
112
  }
109
113
 
110
114
  // ── Config Types ──
@@ -49,7 +49,7 @@ export function getCurrentVersion(): string {
49
49
  function fetchLatestVersion(): string {
50
50
  const result = execSync(`npm view ${PACKAGE} version --json`, {
51
51
  encoding: 'utf-8',
52
- timeout: 10_000,
52
+ timeout: 30_000,
53
53
  stdio: ['pipe', 'pipe', 'pipe'],
54
54
  }).trim()
55
55
  return result.replace(/"/g, '')