@dexto/tui 1.14.0 → 1.14.2

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.
@@ -371,6 +371,16 @@ async function processStream(iterator, setters, options) {
371
371
  }
372
372
  break;
373
373
  }
374
+ case "llm:retrying": {
375
+ if (event.reason !== "empty_response") break;
376
+ state.nonStreamingAccumulatedReasoning = "";
377
+ if (state.messageId && !state.content && !state.reasoningFinalized) {
378
+ removeFromPending(state.messageId);
379
+ state.messageId = null;
380
+ }
381
+ if (!state.messageId) state.reasoning = "";
382
+ break;
383
+ }
374
384
  case "llm:response": {
375
385
  if (!useStreaming) {
376
386
  setUi((prev) => ({ ...prev, isThinking: false }));
@@ -1 +1 @@
1
- {"version":3,"file":"processStream.d.ts","sourceRoot":"","sources":["../../src/services/processStream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,cAAc,EAAuB,MAAM,aAAa,CAAC;AAGvE,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAc,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAoEvE;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACjC,2DAA2D;IAC3D,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAC7D,oFAAoF;IACpF,kBAAkB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACpE,iFAAiF;IACjF,iBAAiB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACnE,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IACrD,kEAAkE;IAClE,UAAU,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,mBAAmB,EAAE,YAAY,CAAC,CAAC,CAAC;IAC3F,4CAA4C;IAC5C,gBAAgB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,aAAa,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC;IAC9F,2CAA2C;IAC3C,iBAAiB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,aAAa,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC;IAC/F,4DAA4D;IAC5D,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC,CAAC;IAC1E,uDAAuD;IACvD,gBAAgB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC;CAC7E;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACjC,2FAA2F;IAC3F,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,2FAA2F;IAC3F,mBAAmB,EAAE;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAC1C,wFAAwF;IACxF,oBAAoB,EAAE;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAC3C,yDAAyD;IACzD,QAAQ,EAAE,IAAI,CAAC,OAAO,aAAa,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;IAC5D,8DAA8D;IAC9D,YAAY,CAAC,EAAE,OAAO,+BAA+B,EAAE,wBAAwB,CAAC;IAChF,kEAAkE;IAClE,QAAQ,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,mBAAmB,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;CAC3F;AAgDD;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CAC/B,QAAQ,EAAE,qBAAqB,CAAC,cAAc,CAAC,EAC/C,OAAO,EAAE,oBAAoB,EAC7B,OAAO,EAAE,oBAAoB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA0uCf"}
1
+ {"version":3,"file":"processStream.d.ts","sourceRoot":"","sources":["../../src/services/processStream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,cAAc,EAAuB,MAAM,aAAa,CAAC;AAGvE,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAc,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAoEvE;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACjC,2DAA2D;IAC3D,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAC7D,oFAAoF;IACpF,kBAAkB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACpE,iFAAiF;IACjF,iBAAiB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACnE,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IACrD,kEAAkE;IAClE,UAAU,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,mBAAmB,EAAE,YAAY,CAAC,CAAC,CAAC;IAC3F,4CAA4C;IAC5C,gBAAgB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,aAAa,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC;IAC9F,2CAA2C;IAC3C,iBAAiB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,aAAa,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC;IAC/F,4DAA4D;IAC5D,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC,CAAC;IAC1E,uDAAuD;IACvD,gBAAgB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC;CAC7E;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACjC,2FAA2F;IAC3F,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,2FAA2F;IAC3F,mBAAmB,EAAE;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAC1C,wFAAwF;IACxF,oBAAoB,EAAE;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAC3C,yDAAyD;IACzD,QAAQ,EAAE,IAAI,CAAC,OAAO,aAAa,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;IAC5D,8DAA8D;IAC9D,YAAY,CAAC,EAAE,OAAO,+BAA+B,EAAE,wBAAwB,CAAC;IAChF,kEAAkE;IAClE,QAAQ,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,mBAAmB,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;CAC3F;AAgDD;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CAC/B,QAAQ,EAAE,qBAAqB,CAAC,cAAc,CAAC,EAC/C,OAAO,EAAE,oBAAoB,EAC7B,OAAO,EAAE,oBAAoB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAuvCf"}
@@ -338,6 +338,16 @@ async function processStream(iterator, setters, options) {
338
338
  }
339
339
  break;
340
340
  }
341
+ case "llm:retrying": {
342
+ if (event.reason !== "empty_response") break;
343
+ state.nonStreamingAccumulatedReasoning = "";
344
+ if (state.messageId && !state.content && !state.reasoningFinalized) {
345
+ removeFromPending(state.messageId);
346
+ state.messageId = null;
347
+ }
348
+ if (!state.messageId) state.reasoning = "";
349
+ break;
350
+ }
341
351
  case "llm:response": {
342
352
  if (!useStreaming) {
343
353
  setUi((prev) => ({ ...prev, isThinking: false }));
@@ -335,6 +335,66 @@ function createSetters({
335
335
  (0, import_vitest.expect)(messagesWithReasoning).toHaveLength(1);
336
336
  (0, import_vitest.expect)(messagesWithReasoning[0]?.reasoning).toBe("R");
337
337
  });
338
+ import_vitest.it.each([true, false])(
339
+ "drops reasoning from an empty reply that is retried (streaming: %s)",
340
+ async (useStreaming) => {
341
+ const { getMessages, getPendingMessages, setters } = createSetters();
342
+ const events = [
343
+ { name: "llm:thinking", sessionId: "test-session" },
344
+ {
345
+ name: "llm:chunk",
346
+ sessionId: "test-session",
347
+ chunkType: "reasoning",
348
+ content: "FIRST"
349
+ },
350
+ {
351
+ name: "llm:retrying",
352
+ sessionId: "test-session",
353
+ error: new Error("The model ended its reply without answering. Try again."),
354
+ context: "TurnExecutor.runModelStep",
355
+ attempt: 1,
356
+ maxRetries: 1,
357
+ provider: "openai",
358
+ model: "gpt-4",
359
+ reason: "empty_response"
360
+ },
361
+ {
362
+ name: "llm:chunk",
363
+ sessionId: "test-session",
364
+ chunkType: "reasoning",
365
+ content: "SECOND"
366
+ },
367
+ {
368
+ name: "llm:chunk",
369
+ sessionId: "test-session",
370
+ chunkType: "text",
371
+ content: "Hello"
372
+ },
373
+ llmResponse({
374
+ content: "Hello",
375
+ reasoning: "SECOND"
376
+ }),
377
+ {
378
+ name: "run:complete",
379
+ sessionId: "test-session",
380
+ finishReason: "stop",
381
+ stepCount: 1,
382
+ durationMs: 1
383
+ }
384
+ ];
385
+ await (0, import_processStream.processStream)(eventStream(events), setters, {
386
+ useStreaming,
387
+ autoApproveEditsRef: { current: false },
388
+ bypassPermissionsRef: { current: false },
389
+ eventBus: { emit: import_vitest.vi.fn() }
390
+ });
391
+ (0, import_vitest.expect)(getPendingMessages()).toEqual([]);
392
+ const assistantMessages = getMessages().filter((m) => m.role === "assistant");
393
+ (0, import_vitest.expect)(assistantMessages).toHaveLength(1);
394
+ (0, import_vitest.expect)(assistantMessages[0]?.content).toBe("Hello");
395
+ (0, import_vitest.expect)(assistantMessages[0]?.reasoning).toBe("SECOND");
396
+ }
397
+ );
338
398
  (0, import_vitest.it)("includes reasoning in non-streaming mode (accumulated from chunks)", async () => {
339
399
  const { getMessages, setters } = createSetters();
340
400
  const events = [
@@ -334,6 +334,66 @@ describe("processStream (reasoning)", () => {
334
334
  expect(messagesWithReasoning).toHaveLength(1);
335
335
  expect(messagesWithReasoning[0]?.reasoning).toBe("R");
336
336
  });
337
+ it.each([true, false])(
338
+ "drops reasoning from an empty reply that is retried (streaming: %s)",
339
+ async (useStreaming) => {
340
+ const { getMessages, getPendingMessages, setters } = createSetters();
341
+ const events = [
342
+ { name: "llm:thinking", sessionId: "test-session" },
343
+ {
344
+ name: "llm:chunk",
345
+ sessionId: "test-session",
346
+ chunkType: "reasoning",
347
+ content: "FIRST"
348
+ },
349
+ {
350
+ name: "llm:retrying",
351
+ sessionId: "test-session",
352
+ error: new Error("The model ended its reply without answering. Try again."),
353
+ context: "TurnExecutor.runModelStep",
354
+ attempt: 1,
355
+ maxRetries: 1,
356
+ provider: "openai",
357
+ model: "gpt-4",
358
+ reason: "empty_response"
359
+ },
360
+ {
361
+ name: "llm:chunk",
362
+ sessionId: "test-session",
363
+ chunkType: "reasoning",
364
+ content: "SECOND"
365
+ },
366
+ {
367
+ name: "llm:chunk",
368
+ sessionId: "test-session",
369
+ chunkType: "text",
370
+ content: "Hello"
371
+ },
372
+ llmResponse({
373
+ content: "Hello",
374
+ reasoning: "SECOND"
375
+ }),
376
+ {
377
+ name: "run:complete",
378
+ sessionId: "test-session",
379
+ finishReason: "stop",
380
+ stepCount: 1,
381
+ durationMs: 1
382
+ }
383
+ ];
384
+ await processStream(eventStream(events), setters, {
385
+ useStreaming,
386
+ autoApproveEditsRef: { current: false },
387
+ bypassPermissionsRef: { current: false },
388
+ eventBus: { emit: vi.fn() }
389
+ });
390
+ expect(getPendingMessages()).toEqual([]);
391
+ const assistantMessages = getMessages().filter((m) => m.role === "assistant");
392
+ expect(assistantMessages).toHaveLength(1);
393
+ expect(assistantMessages[0]?.content).toBe("Hello");
394
+ expect(assistantMessages[0]?.reasoning).toBe("SECOND");
395
+ }
396
+ );
337
397
  it("includes reasoning in non-streaming mode (accumulated from chunks)", async () => {
338
398
  const { getMessages, setters } = createSetters();
339
399
  const events = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dexto/tui",
3
- "version": "1.14.0",
3
+ "version": "1.14.2",
4
4
  "description": "Interactive terminal UI for Dexto CLI",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -28,10 +28,10 @@
28
28
  "string-width": "^8.1.0",
29
29
  "strip-ansi": "^7.1.2",
30
30
  "wrap-ansi": "^9.0.2",
31
- "@dexto/agent-management": "1.14.0",
32
- "@dexto/core": "1.14.0",
33
- "@dexto/llm": "1.14.0",
34
- "@dexto/registry": "1.14.0"
31
+ "@dexto/agent-management": "1.14.2",
32
+ "@dexto/core": "1.14.2",
33
+ "@dexto/registry": "1.14.2",
34
+ "@dexto/llm": "1.14.2"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@types/react": "^19.0.0",