@dexto/tui 1.7.1 → 1.8.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.
Files changed (99) hide show
  1. package/dist/agent-backend.cjs +16 -2
  2. package/dist/agent-backend.d.ts +5 -2
  3. package/dist/agent-backend.d.ts.map +1 -1
  4. package/dist/agent-backend.js +15 -2
  5. package/dist/agent-backend.test.cjs +28 -2
  6. package/dist/agent-backend.test.js +28 -2
  7. package/dist/components/ApprovalPrompt.cjs +6 -5
  8. package/dist/components/ApprovalPrompt.d.ts +1 -1
  9. package/dist/components/ApprovalPrompt.d.ts.map +1 -1
  10. package/dist/components/ApprovalPrompt.js +6 -5
  11. package/dist/components/TextBufferInput.cjs +14 -1
  12. package/dist/components/TextBufferInput.d.ts +5 -1
  13. package/dist/components/TextBufferInput.d.ts.map +1 -1
  14. package/dist/components/TextBufferInput.js +14 -1
  15. package/dist/components/chat/QueuedMessagesDisplay.cjs +17 -8
  16. package/dist/components/chat/QueuedMessagesDisplay.d.ts +7 -1
  17. package/dist/components/chat/QueuedMessagesDisplay.d.ts.map +1 -1
  18. package/dist/components/chat/QueuedMessagesDisplay.js +16 -8
  19. package/dist/components/input/InputArea.cjs +4 -0
  20. package/dist/components/input/InputArea.d.ts +5 -1
  21. package/dist/components/input/InputArea.d.ts.map +1 -1
  22. package/dist/components/input/InputArea.js +4 -0
  23. package/dist/components/modes/AlternateBufferCLI.cjs +20 -1
  24. package/dist/components/modes/AlternateBufferCLI.d.ts.map +1 -1
  25. package/dist/components/modes/AlternateBufferCLI.js +21 -2
  26. package/dist/components/modes/StaticCLI.cjs +20 -1
  27. package/dist/components/modes/StaticCLI.d.ts.map +1 -1
  28. package/dist/components/modes/StaticCLI.js +21 -2
  29. package/dist/components/overlays/LoginOverlay.cjs +2 -10
  30. package/dist/components/overlays/LoginOverlay.d.ts.map +1 -1
  31. package/dist/components/overlays/LoginOverlay.js +3 -11
  32. package/dist/containers/InputContainer.cjs +119 -18
  33. package/dist/containers/InputContainer.d.ts +6 -2
  34. package/dist/containers/InputContainer.d.ts.map +1 -1
  35. package/dist/containers/InputContainer.js +119 -18
  36. package/dist/hooks/useAgentEvents.cjs +27 -5
  37. package/dist/hooks/useAgentEvents.d.ts +3 -2
  38. package/dist/hooks/useAgentEvents.d.ts.map +1 -1
  39. package/dist/hooks/useAgentEvents.js +27 -5
  40. package/dist/hooks/useCLIState.cjs +10 -4
  41. package/dist/hooks/useCLIState.d.ts +2 -0
  42. package/dist/hooks/useCLIState.d.ts.map +1 -1
  43. package/dist/hooks/useCLIState.js +10 -4
  44. package/dist/hooks/useInputOrchestrator.cjs +15 -14
  45. package/dist/hooks/useInputOrchestrator.d.ts +6 -6
  46. package/dist/hooks/useInputOrchestrator.d.ts.map +1 -1
  47. package/dist/hooks/useInputOrchestrator.js +15 -14
  48. package/dist/host/index.cjs +6 -6
  49. package/dist/host/index.d.ts +8 -17
  50. package/dist/host/index.d.ts.map +1 -1
  51. package/dist/host/index.js +5 -5
  52. package/dist/host/index.test.cjs +47 -0
  53. package/dist/host/index.test.d.ts +2 -0
  54. package/dist/host/index.test.d.ts.map +1 -0
  55. package/dist/host/index.test.js +50 -0
  56. package/dist/index.d.cts +10 -15
  57. package/dist/interactive-commands/command-parser.cjs +1 -0
  58. package/dist/interactive-commands/command-parser.d.ts.map +1 -1
  59. package/dist/interactive-commands/command-parser.js +1 -0
  60. package/dist/interactive-commands/commands.cjs +3 -0
  61. package/dist/interactive-commands/commands.d.ts.map +1 -1
  62. package/dist/interactive-commands/commands.js +3 -0
  63. package/dist/interactive-commands/commands.test.cjs +42 -0
  64. package/dist/interactive-commands/commands.test.js +42 -0
  65. package/dist/interactive-commands/prompt-commands.cjs +4 -66
  66. package/dist/interactive-commands/prompt-commands.d.ts +1 -2
  67. package/dist/interactive-commands/prompt-commands.d.ts.map +1 -1
  68. package/dist/interactive-commands/prompt-commands.js +4 -66
  69. package/dist/interactive-commands/skill-commands.cjs +73 -0
  70. package/dist/interactive-commands/skill-commands.d.ts +9 -0
  71. package/dist/interactive-commands/skill-commands.d.ts.map +1 -0
  72. package/dist/interactive-commands/skill-commands.js +49 -0
  73. package/dist/services/processStream.cjs +23 -4
  74. package/dist/services/processStream.d.ts +3 -1
  75. package/dist/services/processStream.d.ts.map +1 -1
  76. package/dist/services/processStream.js +23 -4
  77. package/dist/services/processStream.test.cjs +52 -2
  78. package/dist/services/processStream.test.js +52 -2
  79. package/dist/state/initialState.cjs +2 -1
  80. package/dist/state/initialState.d.ts.map +1 -1
  81. package/dist/state/initialState.js +2 -1
  82. package/dist/state/reducer.cjs +10 -5
  83. package/dist/state/reducer.d.ts.map +1 -1
  84. package/dist/state/reducer.js +10 -5
  85. package/dist/state/types.d.ts +2 -0
  86. package/dist/state/types.d.ts.map +1 -1
  87. package/dist/utils/messageFormatting.cjs +0 -23
  88. package/dist/utils/messageFormatting.d.ts +0 -13
  89. package/dist/utils/messageFormatting.d.ts.map +1 -1
  90. package/dist/utils/messageFormatting.js +0 -21
  91. package/dist/utils/queuedComposerContent.cjs +148 -0
  92. package/dist/utils/queuedComposerContent.d.ts +17 -0
  93. package/dist/utils/queuedComposerContent.d.ts.map +1 -0
  94. package/dist/utils/queuedComposerContent.js +123 -0
  95. package/dist/utils/queuedComposerContent.test.cjs +176 -0
  96. package/dist/utils/queuedComposerContent.test.d.ts +2 -0
  97. package/dist/utils/queuedComposerContent.test.d.ts.map +1 -0
  98. package/dist/utils/queuedComposerContent.test.js +175 -0
  99. package/package.json +4 -4
@@ -32,13 +32,14 @@ __export(InputContainer_exports, {
32
32
  });
33
33
  module.exports = __toCommonJS(InputContainer_exports);
34
34
  var import_jsx_runtime = require("react/jsx-runtime");
35
- var import_react = require("react");
35
+ var import_react = __toESM(require("react"), 1);
36
36
  var import_core = require("@dexto/core");
37
37
  var import_InputArea = require("../components/input/InputArea.js");
38
38
  var import_services = require("../services/index.js");
39
39
  var import_contexts = require("../contexts/index.js");
40
40
  var import_messageFormatting = require("../utils/messageFormatting.js");
41
41
  var import_idGenerator = require("../utils/idGenerator.js");
42
+ var import_queuedComposerContent = require("../utils/queuedComposerContent.js");
42
43
  var import_host = require("../host/index.js");
43
44
  var import_overlayPresentation = require("../utils/overlayPresentation.js");
44
45
  var import_agent_backend = require("../agent-backend.js");
@@ -50,6 +51,7 @@ const InputContainer = (0, import_react.forwardRef)(
50
51
  session,
51
52
  initialPrompt,
52
53
  approval,
54
+ steerMessages,
53
55
  queuedMessages,
54
56
  setInput,
55
57
  setUi,
@@ -57,6 +59,7 @@ const InputContainer = (0, import_react.forwardRef)(
57
59
  setMessages,
58
60
  setPendingMessages,
59
61
  setDequeuedBuffer,
62
+ setSteerMessages,
60
63
  setQueuedMessages,
61
64
  setApproval,
62
65
  setApprovalQueue,
@@ -68,6 +71,8 @@ const InputContainer = (0, import_react.forwardRef)(
68
71
  useStreaming = true
69
72
  }, ref) {
70
73
  const sessionCreationPromiseRef = (0, import_react.useRef)(null);
74
+ const queuedEditPendingRef = (0, import_react.useRef)(false);
75
+ const [isQueuedEditPending, setIsQueuedEditPending] = import_react.default.useState(false);
71
76
  const didAutoSubmitInitialPromptRef = (0, import_react.useRef)(false);
72
77
  const soundService = (0, import_contexts.useSoundService)();
73
78
  const autoApproveEditsRef = (0, import_react.useRef)(ui.autoApproveEdits);
@@ -83,21 +88,81 @@ const InputContainer = (0, import_react.forwardRef)(
83
88
  sessionCreationPromiseRef.current = null;
84
89
  }
85
90
  }, [session.id]);
86
- const extractTextFromContent = (0, import_react.useCallback)((content) => {
87
- return content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
88
- }, []);
91
+ const popQueuedMessageForEdit = (0, import_react.useCallback)(
92
+ async (message, editingQueuedFollowUp, removeMessage) => {
93
+ if (queuedEditPendingRef.current) {
94
+ return;
95
+ }
96
+ const result = (0, import_queuedComposerContent.restoreQueuedContentForComposer)(message);
97
+ if (!result.ok) {
98
+ setMessages((prev) => [
99
+ ...prev,
100
+ {
101
+ id: (0, import_idGenerator.generateMessageId)("system"),
102
+ role: "system",
103
+ content: result.reason,
104
+ timestamp: /* @__PURE__ */ new Date()
105
+ }
106
+ ]);
107
+ return;
108
+ }
109
+ queuedEditPendingRef.current = true;
110
+ setIsQueuedEditPending(true);
111
+ let removed = false;
112
+ try {
113
+ removed = await removeMessage();
114
+ if (!removed) {
115
+ setMessages((prev) => [
116
+ ...prev,
117
+ {
118
+ id: (0, import_idGenerator.generateMessageId)("system"),
119
+ role: "system",
120
+ content: "Queued input could not be edited because it is no longer pending.",
121
+ timestamp: /* @__PURE__ */ new Date()
122
+ }
123
+ ]);
124
+ return;
125
+ }
126
+ buffer.setText(result.composer.text);
127
+ setInput((prev) => ({
128
+ ...prev,
129
+ value: result.composer.text,
130
+ images: result.composer.images,
131
+ pastedBlocks: [],
132
+ historyIndex: -1,
133
+ draftBeforeHistory: "",
134
+ editingQueuedFollowUp
135
+ }));
136
+ } catch {
137
+ setMessages((prev) => [
138
+ ...prev,
139
+ {
140
+ id: (0, import_idGenerator.generateMessageId)("system"),
141
+ role: "system",
142
+ content: "Queued input could not be edited. Try again.",
143
+ timestamp: /* @__PURE__ */ new Date()
144
+ }
145
+ ]);
146
+ } finally {
147
+ queuedEditPendingRef.current = false;
148
+ setIsQueuedEditPending(false);
149
+ }
150
+ },
151
+ [buffer, setInput, setMessages]
152
+ );
89
153
  const handleHistoryNavigate = (0, import_react.useCallback)(
90
154
  (direction) => {
91
155
  const { history, historyIndex, draftBeforeHistory } = input;
92
156
  if (direction === "up") {
93
157
  if (queuedMessages.length > 0 && session.id) {
158
+ const sessionId = session.id;
94
159
  const lastQueued = queuedMessages[queuedMessages.length - 1];
95
160
  if (lastQueued) {
96
- const text = extractTextFromContent(lastQueued.content);
97
- buffer.setText(text);
98
- setInput((prev) => ({ ...prev, value: text }));
99
- agent.removeQueuedMessage(session.id, lastQueued.id).catch(() => {
100
- });
161
+ void popQueuedMessageForEdit(
162
+ lastQueued,
163
+ true,
164
+ () => agent.removeFollowUpMessage(sessionId, lastQueued.id)
165
+ );
101
166
  return;
102
167
  }
103
168
  }
@@ -110,7 +175,8 @@ const InputContainer = (0, import_react.forwardRef)(
110
175
  ...prev,
111
176
  draftBeforeHistory: currentText,
112
177
  historyIndex: history.length - 1,
113
- value: history[history.length - 1] || ""
178
+ value: history[history.length - 1] || "",
179
+ editingQueuedFollowUp: false
114
180
  }));
115
181
  buffer.setText(history[history.length - 1] || "");
116
182
  return;
@@ -121,7 +187,12 @@ const InputContainer = (0, import_react.forwardRef)(
121
187
  }
122
188
  const historyItem = history[newIndex] || "";
123
189
  buffer.setText(historyItem);
124
- setInput((prev) => ({ ...prev, value: historyItem, historyIndex: newIndex }));
190
+ setInput((prev) => ({
191
+ ...prev,
192
+ value: historyItem,
193
+ historyIndex: newIndex,
194
+ editingQueuedFollowUp: false
195
+ }));
125
196
  } else {
126
197
  if (ui.isProcessing) return;
127
198
  if (historyIndex < 0) return;
@@ -132,7 +203,8 @@ const InputContainer = (0, import_react.forwardRef)(
132
203
  setInput((prev) => ({
133
204
  ...prev,
134
205
  value: historyItem,
135
- historyIndex: newIndex
206
+ historyIndex: newIndex,
207
+ editingQueuedFollowUp: false
136
208
  }));
137
209
  } else {
138
210
  buffer.setText(draftBeforeHistory);
@@ -140,7 +212,8 @@ const InputContainer = (0, import_react.forwardRef)(
140
212
  ...prev,
141
213
  value: draftBeforeHistory,
142
214
  historyIndex: -1,
143
- draftBeforeHistory: ""
215
+ draftBeforeHistory: "",
216
+ editingQueuedFollowUp: false
144
217
  }));
145
218
  }
146
219
  }
@@ -152,10 +225,26 @@ const InputContainer = (0, import_react.forwardRef)(
152
225
  queuedMessages,
153
226
  session.id,
154
227
  agent,
155
- extractTextFromContent,
228
+ popQueuedMessageForEdit,
156
229
  ui.isProcessing
157
230
  ]
158
231
  );
232
+ const handleCurrentTurnEdit = (0, import_react.useCallback)(() => {
233
+ if (steerMessages.length === 0 || !session.id) {
234
+ return false;
235
+ }
236
+ const lastSteer = steerMessages[steerMessages.length - 1];
237
+ if (!lastSteer) {
238
+ return false;
239
+ }
240
+ const sessionId = session.id;
241
+ void popQueuedMessageForEdit(
242
+ lastSteer,
243
+ false,
244
+ () => agent.removeSteerMessage(sessionId, lastSteer.id)
245
+ );
246
+ return true;
247
+ }, [agent, popQueuedMessageForEdit, session.id, steerMessages]);
159
248
  const handleTriggerOverlay = (0, import_react.useCallback)(
160
249
  (trigger) => {
161
250
  if (approval) return;
@@ -308,7 +397,7 @@ const InputContainer = (0, import_react.forwardRef)(
308
397
  return result;
309
398
  }, []);
310
399
  const handleSubmit = (0, import_react.useCallback)(
311
- async (value, bypassOverlayCheck = false) => {
400
+ async (value, bypassOverlayCheck = false, queueAsFollowUp = false) => {
312
401
  const expandedValue = expandPasteBlocks(value, input.pastedBlocks);
313
402
  const trimmed = expandedValue.trim();
314
403
  if (!trimmed) return;
@@ -321,8 +410,13 @@ const InputContainer = (0, import_react.forwardRef)(
321
410
  mimeType: img.mimeType
322
411
  });
323
412
  }
413
+ const submitAsFollowUp = queueAsFollowUp || input.editingQueuedFollowUp;
324
414
  try {
325
- await agent.queueMessage(session.id, { content });
415
+ if (submitAsFollowUp) {
416
+ await agent.followUp(session.id, { content });
417
+ } else {
418
+ await agent.steer(session.id, { content });
419
+ }
326
420
  buffer.setText("");
327
421
  setInput((prev) => {
328
422
  const newHistory = prev.history.length > 0 && prev.history[prev.history.length - 1] === trimmed ? prev.history : [...prev.history, trimmed].slice(-100);
@@ -332,6 +426,7 @@ const InputContainer = (0, import_react.forwardRef)(
332
426
  history: newHistory,
333
427
  historyIndex: -1,
334
428
  draftBeforeHistory: "",
429
+ editingQueuedFollowUp: false,
335
430
  images: [],
336
431
  pastedBlocks: []
337
432
  };
@@ -342,7 +437,7 @@ const InputContainer = (0, import_react.forwardRef)(
342
437
  {
343
438
  id: (0, import_idGenerator.generateMessageId)("error"),
344
439
  role: "system",
345
- content: `Failed to queue message: ${error instanceof Error ? error.message : String(error)}`,
440
+ content: `Failed to submit ${submitAsFollowUp ? "follow-up" : "steer"} message: ${error instanceof Error ? error.message : String(error)}`,
346
441
  timestamp: /* @__PURE__ */ new Date()
347
442
  }
348
443
  ]);
@@ -363,6 +458,7 @@ const InputContainer = (0, import_react.forwardRef)(
363
458
  history: newHistory,
364
459
  historyIndex: -1,
365
460
  draftBeforeHistory: "",
461
+ editingQueuedFollowUp: false,
366
462
  images: [],
367
463
  // Clear images on submit
368
464
  pastedBlocks: [],
@@ -464,6 +560,7 @@ const InputContainer = (0, import_react.forwardRef)(
464
560
  setDequeuedBuffer,
465
561
  setUi,
466
562
  setSession,
563
+ setSteerMessages,
467
564
  setQueuedMessages,
468
565
  setApproval,
469
566
  setApprovalQueue
@@ -583,6 +680,7 @@ ${trimmed}`;
583
680
  setDequeuedBuffer,
584
681
  setUi,
585
682
  setSession,
683
+ setSteerMessages,
586
684
  setQueuedMessages,
587
685
  setApproval,
588
686
  setApprovalQueue
@@ -629,6 +727,7 @@ ${trimmed}`;
629
727
  setMessages,
630
728
  setPendingMessages,
631
729
  setDequeuedBuffer,
730
+ setSteerMessages,
632
731
  setQueuedMessages,
633
732
  setSession,
634
733
  agent,
@@ -667,7 +766,7 @@ ${trimmed}`;
667
766
  const mainInputAllowed = mainInputAllowedOverlays.includes(ui.activeOverlay);
668
767
  const isHistorySearchActive = ui.historySearch.isActive;
669
768
  const isInputActive = !approval && mainInputAllowed && !isHistorySearchActive;
670
- const isInputDisabled = approval !== null || !mainInputAllowed || isHistorySearchActive;
769
+ const isInputDisabled = approval !== null || !mainInputAllowed || isHistorySearchActive || isQueuedEditPending;
671
770
  const shouldHandleSubmit = ui.activeOverlay === "none" || ui.activeOverlay === "approval";
672
771
  const canNavigateHistory = !approval && ui.activeOverlay === "none";
673
772
  const shouldHideInputArea = (0, import_overlayPresentation.getOverlayPresentation)(ui.activeOverlay, approval) === "focus";
@@ -684,10 +783,12 @@ ${trimmed}`;
684
783
  buffer,
685
784
  onSubmit: shouldHandleSubmit ? handleSubmit : () => {
686
785
  },
786
+ onQueueSubmit: shouldHandleSubmit ? (value) => void handleSubmit(value, false, true) : void 0,
687
787
  isDisabled: isInputDisabled,
688
788
  isActive: isInputActive,
689
789
  placeholder,
690
790
  onHistoryNavigate: canNavigateHistory ? handleHistoryNavigate : void 0,
791
+ onCurrentTurnEdit: handleCurrentTurnEdit,
691
792
  onTriggerOverlay: handleTriggerOverlay,
692
793
  onKeyboardScroll,
693
794
  imageCount: input.images.length,
@@ -26,7 +26,9 @@ interface InputContainerProps {
26
26
  /** If provided, auto-submits once when the UI is ready */
27
27
  initialPrompt?: string | undefined;
28
28
  approval: ApprovalRequest | null;
29
- /** Queued messages waiting to be processed */
29
+ /** Active-turn input waiting for the next executor boundary */
30
+ steerMessages: QueuedMessage[];
31
+ /** Follow-up messages waiting to run after the current turn */
30
32
  queuedMessages: QueuedMessage[];
31
33
  setInput: React.Dispatch<React.SetStateAction<InputState>>;
32
34
  setUi: React.Dispatch<React.SetStateAction<UIState>>;
@@ -37,7 +39,9 @@ interface InputContainerProps {
37
39
  setPendingMessages: React.Dispatch<React.SetStateAction<Message[]>>;
38
40
  /** Setter for dequeued buffer (user messages waiting to render after pending) */
39
41
  setDequeuedBuffer: React.Dispatch<React.SetStateAction<Message[]>>;
40
- /** Setter for queued messages */
42
+ /** Setter for active-turn steer messages */
43
+ setSteerMessages: React.Dispatch<React.SetStateAction<QueuedMessage[]>>;
44
+ /** Setter for queued follow-up messages */
41
45
  setQueuedMessages: React.Dispatch<React.SetStateAction<QueuedMessage[]>>;
42
46
  /** Setter for current approval request (for approval UI via processStream) */
43
47
  setApproval: React.Dispatch<React.SetStateAction<ApprovalRequest | null>>;
@@ -1 +1 @@
1
- {"version":3,"file":"InputContainer.d.ts","sourceRoot":"","sources":["../../src/containers/InputContainer.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAA0E,MAAM,OAAO,CAAC;AAC/F,OAAO,KAAK,EAAoC,aAAa,EAAE,MAAM,aAAa,CAAC;AAGnF,OAAO,EAAE,YAAY,EAAiB,MAAM,sBAAsB,CAAC;AAEnE,OAAO,KAAK,EACR,OAAO,EACP,OAAO,EACP,UAAU,EACV,YAAY,EAGZ,QAAQ,EACX,MAAM,mBAAmB,CAAC;AAG3B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AAGtE,OAAO,EAIH,KAAK,eAAe,EACvB,MAAM,qBAAqB,CAAC;AAK7B,qDAAqD;AACrD,MAAM,WAAW,oBAAoB;IACjC,yEAAyE;IACzE,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3C;AAED,UAAU,mBAAmB;IACzB,yCAAyC;IACzC,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,UAAU,CAAC;IAClB,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,YAAY,CAAC;IACtB,0DAA0D;IAC1D,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;IACjC,8CAA8C;IAC9C,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC;IAC3D,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IACrD,UAAU,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC;IAC/D,2DAA2D;IAC3D,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAC7D,mEAAmE;IACnE,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,iCAAiC;IACjC,iBAAiB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;IACzE,8EAA8E;IAC9E,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC,CAAC;IAC1E,yEAAyE;IACzE,gBAAgB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC;IAC1E,sEAAsE;IACtE,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC3D,KAAK,EAAE,eAAe,CAAC;IACvB,YAAY,EAAE,YAAY,CAAC;IAC3B,mDAAmD;IACnD,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,mEAAmE;IACnE,gBAAgB,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,GAAG,MAAM,KAAK,IAAI,CAAC;IACtD,6EAA6E;IAC7E,YAAY,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,kGA20B1B,CAAC"}
1
+ {"version":3,"file":"InputContainer.d.ts","sourceRoot":"","sources":["../../src/containers/InputContainer.tsx"],"names":[],"mappings":"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"}
@@ -1,11 +1,12 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import { useCallback, useRef, useEffect, useImperativeHandle, forwardRef } from "react";
2
+ import React, { useCallback, useRef, useEffect, useImperativeHandle, forwardRef } from "react";
3
3
  import { getReasoningProfile } from "@dexto/core";
4
4
  import { InputArea } from "../components/input/InputArea.js";
5
5
  import { processStream } from "../services/index.js";
6
6
  import { useSoundService } from "../contexts/index.js";
7
7
  import { createUserMessage } from "../utils/messageFormatting.js";
8
8
  import { generateMessageId } from "../utils/idGenerator.js";
9
+ import { restoreQueuedContentForComposer } from "../utils/queuedComposerContent.js";
9
10
  import { captureAnalytics } from "../host/index.js";
10
11
  import { getOverlayPresentation } from "../utils/overlayPresentation.js";
11
12
  import {
@@ -21,6 +22,7 @@ const InputContainer = forwardRef(
21
22
  session,
22
23
  initialPrompt,
23
24
  approval,
25
+ steerMessages,
24
26
  queuedMessages,
25
27
  setInput,
26
28
  setUi,
@@ -28,6 +30,7 @@ const InputContainer = forwardRef(
28
30
  setMessages,
29
31
  setPendingMessages,
30
32
  setDequeuedBuffer,
33
+ setSteerMessages,
31
34
  setQueuedMessages,
32
35
  setApproval,
33
36
  setApprovalQueue,
@@ -39,6 +42,8 @@ const InputContainer = forwardRef(
39
42
  useStreaming = true
40
43
  }, ref) {
41
44
  const sessionCreationPromiseRef = useRef(null);
45
+ const queuedEditPendingRef = useRef(false);
46
+ const [isQueuedEditPending, setIsQueuedEditPending] = React.useState(false);
42
47
  const didAutoSubmitInitialPromptRef = useRef(false);
43
48
  const soundService = useSoundService();
44
49
  const autoApproveEditsRef = useRef(ui.autoApproveEdits);
@@ -54,21 +59,81 @@ const InputContainer = forwardRef(
54
59
  sessionCreationPromiseRef.current = null;
55
60
  }
56
61
  }, [session.id]);
57
- const extractTextFromContent = useCallback((content) => {
58
- return content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
59
- }, []);
62
+ const popQueuedMessageForEdit = useCallback(
63
+ async (message, editingQueuedFollowUp, removeMessage) => {
64
+ if (queuedEditPendingRef.current) {
65
+ return;
66
+ }
67
+ const result = restoreQueuedContentForComposer(message);
68
+ if (!result.ok) {
69
+ setMessages((prev) => [
70
+ ...prev,
71
+ {
72
+ id: generateMessageId("system"),
73
+ role: "system",
74
+ content: result.reason,
75
+ timestamp: /* @__PURE__ */ new Date()
76
+ }
77
+ ]);
78
+ return;
79
+ }
80
+ queuedEditPendingRef.current = true;
81
+ setIsQueuedEditPending(true);
82
+ let removed = false;
83
+ try {
84
+ removed = await removeMessage();
85
+ if (!removed) {
86
+ setMessages((prev) => [
87
+ ...prev,
88
+ {
89
+ id: generateMessageId("system"),
90
+ role: "system",
91
+ content: "Queued input could not be edited because it is no longer pending.",
92
+ timestamp: /* @__PURE__ */ new Date()
93
+ }
94
+ ]);
95
+ return;
96
+ }
97
+ buffer.setText(result.composer.text);
98
+ setInput((prev) => ({
99
+ ...prev,
100
+ value: result.composer.text,
101
+ images: result.composer.images,
102
+ pastedBlocks: [],
103
+ historyIndex: -1,
104
+ draftBeforeHistory: "",
105
+ editingQueuedFollowUp
106
+ }));
107
+ } catch {
108
+ setMessages((prev) => [
109
+ ...prev,
110
+ {
111
+ id: generateMessageId("system"),
112
+ role: "system",
113
+ content: "Queued input could not be edited. Try again.",
114
+ timestamp: /* @__PURE__ */ new Date()
115
+ }
116
+ ]);
117
+ } finally {
118
+ queuedEditPendingRef.current = false;
119
+ setIsQueuedEditPending(false);
120
+ }
121
+ },
122
+ [buffer, setInput, setMessages]
123
+ );
60
124
  const handleHistoryNavigate = useCallback(
61
125
  (direction) => {
62
126
  const { history, historyIndex, draftBeforeHistory } = input;
63
127
  if (direction === "up") {
64
128
  if (queuedMessages.length > 0 && session.id) {
129
+ const sessionId = session.id;
65
130
  const lastQueued = queuedMessages[queuedMessages.length - 1];
66
131
  if (lastQueued) {
67
- const text = extractTextFromContent(lastQueued.content);
68
- buffer.setText(text);
69
- setInput((prev) => ({ ...prev, value: text }));
70
- agent.removeQueuedMessage(session.id, lastQueued.id).catch(() => {
71
- });
132
+ void popQueuedMessageForEdit(
133
+ lastQueued,
134
+ true,
135
+ () => agent.removeFollowUpMessage(sessionId, lastQueued.id)
136
+ );
72
137
  return;
73
138
  }
74
139
  }
@@ -81,7 +146,8 @@ const InputContainer = forwardRef(
81
146
  ...prev,
82
147
  draftBeforeHistory: currentText,
83
148
  historyIndex: history.length - 1,
84
- value: history[history.length - 1] || ""
149
+ value: history[history.length - 1] || "",
150
+ editingQueuedFollowUp: false
85
151
  }));
86
152
  buffer.setText(history[history.length - 1] || "");
87
153
  return;
@@ -92,7 +158,12 @@ const InputContainer = forwardRef(
92
158
  }
93
159
  const historyItem = history[newIndex] || "";
94
160
  buffer.setText(historyItem);
95
- setInput((prev) => ({ ...prev, value: historyItem, historyIndex: newIndex }));
161
+ setInput((prev) => ({
162
+ ...prev,
163
+ value: historyItem,
164
+ historyIndex: newIndex,
165
+ editingQueuedFollowUp: false
166
+ }));
96
167
  } else {
97
168
  if (ui.isProcessing) return;
98
169
  if (historyIndex < 0) return;
@@ -103,7 +174,8 @@ const InputContainer = forwardRef(
103
174
  setInput((prev) => ({
104
175
  ...prev,
105
176
  value: historyItem,
106
- historyIndex: newIndex
177
+ historyIndex: newIndex,
178
+ editingQueuedFollowUp: false
107
179
  }));
108
180
  } else {
109
181
  buffer.setText(draftBeforeHistory);
@@ -111,7 +183,8 @@ const InputContainer = forwardRef(
111
183
  ...prev,
112
184
  value: draftBeforeHistory,
113
185
  historyIndex: -1,
114
- draftBeforeHistory: ""
186
+ draftBeforeHistory: "",
187
+ editingQueuedFollowUp: false
115
188
  }));
116
189
  }
117
190
  }
@@ -123,10 +196,26 @@ const InputContainer = forwardRef(
123
196
  queuedMessages,
124
197
  session.id,
125
198
  agent,
126
- extractTextFromContent,
199
+ popQueuedMessageForEdit,
127
200
  ui.isProcessing
128
201
  ]
129
202
  );
203
+ const handleCurrentTurnEdit = useCallback(() => {
204
+ if (steerMessages.length === 0 || !session.id) {
205
+ return false;
206
+ }
207
+ const lastSteer = steerMessages[steerMessages.length - 1];
208
+ if (!lastSteer) {
209
+ return false;
210
+ }
211
+ const sessionId = session.id;
212
+ void popQueuedMessageForEdit(
213
+ lastSteer,
214
+ false,
215
+ () => agent.removeSteerMessage(sessionId, lastSteer.id)
216
+ );
217
+ return true;
218
+ }, [agent, popQueuedMessageForEdit, session.id, steerMessages]);
130
219
  const handleTriggerOverlay = useCallback(
131
220
  (trigger) => {
132
221
  if (approval) return;
@@ -279,7 +368,7 @@ const InputContainer = forwardRef(
279
368
  return result;
280
369
  }, []);
281
370
  const handleSubmit = useCallback(
282
- async (value, bypassOverlayCheck = false) => {
371
+ async (value, bypassOverlayCheck = false, queueAsFollowUp = false) => {
283
372
  const expandedValue = expandPasteBlocks(value, input.pastedBlocks);
284
373
  const trimmed = expandedValue.trim();
285
374
  if (!trimmed) return;
@@ -292,8 +381,13 @@ const InputContainer = forwardRef(
292
381
  mimeType: img.mimeType
293
382
  });
294
383
  }
384
+ const submitAsFollowUp = queueAsFollowUp || input.editingQueuedFollowUp;
295
385
  try {
296
- await agent.queueMessage(session.id, { content });
386
+ if (submitAsFollowUp) {
387
+ await agent.followUp(session.id, { content });
388
+ } else {
389
+ await agent.steer(session.id, { content });
390
+ }
297
391
  buffer.setText("");
298
392
  setInput((prev) => {
299
393
  const newHistory = prev.history.length > 0 && prev.history[prev.history.length - 1] === trimmed ? prev.history : [...prev.history, trimmed].slice(-100);
@@ -303,6 +397,7 @@ const InputContainer = forwardRef(
303
397
  history: newHistory,
304
398
  historyIndex: -1,
305
399
  draftBeforeHistory: "",
400
+ editingQueuedFollowUp: false,
306
401
  images: [],
307
402
  pastedBlocks: []
308
403
  };
@@ -313,7 +408,7 @@ const InputContainer = forwardRef(
313
408
  {
314
409
  id: generateMessageId("error"),
315
410
  role: "system",
316
- content: `Failed to queue message: ${error instanceof Error ? error.message : String(error)}`,
411
+ content: `Failed to submit ${submitAsFollowUp ? "follow-up" : "steer"} message: ${error instanceof Error ? error.message : String(error)}`,
317
412
  timestamp: /* @__PURE__ */ new Date()
318
413
  }
319
414
  ]);
@@ -334,6 +429,7 @@ const InputContainer = forwardRef(
334
429
  history: newHistory,
335
430
  historyIndex: -1,
336
431
  draftBeforeHistory: "",
432
+ editingQueuedFollowUp: false,
337
433
  images: [],
338
434
  // Clear images on submit
339
435
  pastedBlocks: [],
@@ -435,6 +531,7 @@ const InputContainer = forwardRef(
435
531
  setDequeuedBuffer,
436
532
  setUi,
437
533
  setSession,
534
+ setSteerMessages,
438
535
  setQueuedMessages,
439
536
  setApproval,
440
537
  setApprovalQueue
@@ -554,6 +651,7 @@ ${trimmed}`;
554
651
  setDequeuedBuffer,
555
652
  setUi,
556
653
  setSession,
654
+ setSteerMessages,
557
655
  setQueuedMessages,
558
656
  setApproval,
559
657
  setApprovalQueue
@@ -600,6 +698,7 @@ ${trimmed}`;
600
698
  setMessages,
601
699
  setPendingMessages,
602
700
  setDequeuedBuffer,
701
+ setSteerMessages,
603
702
  setQueuedMessages,
604
703
  setSession,
605
704
  agent,
@@ -638,7 +737,7 @@ ${trimmed}`;
638
737
  const mainInputAllowed = mainInputAllowedOverlays.includes(ui.activeOverlay);
639
738
  const isHistorySearchActive = ui.historySearch.isActive;
640
739
  const isInputActive = !approval && mainInputAllowed && !isHistorySearchActive;
641
- const isInputDisabled = approval !== null || !mainInputAllowed || isHistorySearchActive;
740
+ const isInputDisabled = approval !== null || !mainInputAllowed || isHistorySearchActive || isQueuedEditPending;
642
741
  const shouldHandleSubmit = ui.activeOverlay === "none" || ui.activeOverlay === "approval";
643
742
  const canNavigateHistory = !approval && ui.activeOverlay === "none";
644
743
  const shouldHideInputArea = getOverlayPresentation(ui.activeOverlay, approval) === "focus";
@@ -655,10 +754,12 @@ ${trimmed}`;
655
754
  buffer,
656
755
  onSubmit: shouldHandleSubmit ? handleSubmit : () => {
657
756
  },
757
+ onQueueSubmit: shouldHandleSubmit ? (value) => void handleSubmit(value, false, true) : void 0,
658
758
  isDisabled: isInputDisabled,
659
759
  isActive: isInputActive,
660
760
  placeholder,
661
761
  onHistoryNavigate: canNavigateHistory ? handleHistoryNavigate : void 0,
762
+ onCurrentTurnEdit: handleCurrentTurnEdit,
662
763
  onTriggerOverlay: handleTriggerOverlay,
663
764
  onKeyboardScroll,
664
765
  imageCount: input.images.length,