@yeshwanthyk/coding-agent 0.3.13 → 0.3.14
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/dist/adapters/tui/app.js +29 -17
- package/dist/adapters/tui/{app.js.map → app.jsx.map} +1 -1
- package/dist/components/Footer.js +60 -24
- package/dist/components/{Footer.js.map → Footer.jsx.map} +1 -1
- package/dist/components/Header.js +312 -96
- package/dist/components/{Header.js.map → Header.jsx.map} +1 -1
- package/dist/components/MessageList.js +393 -146
- package/dist/components/MessageList.jsx.map +1 -0
- package/dist/runtime/context.js +15 -9
- package/dist/runtime/context.jsx.map +1 -0
- package/dist/session-picker.js +123 -69
- package/dist/session-picker.jsx.map +1 -0
- package/dist/tui-open-rendering.js +716 -343
- package/dist/tui-open-rendering.jsx.map +1 -0
- package/dist/ui/app-shell/TuiApp.js +590 -441
- package/dist/ui/app-shell/{TuiApp.js.map → TuiApp.jsx.map} +1 -1
- package/dist/ui/components/modals/ConfirmModal.js +80 -23
- package/dist/ui/components/modals/ConfirmModal.jsx.map +1 -0
- package/dist/ui/components/modals/EditorModal.js +55 -15
- package/dist/ui/components/modals/EditorModal.jsx.map +1 -0
- package/dist/ui/components/modals/InputModal.js +36 -9
- package/dist/ui/components/modals/InputModal.jsx.map +1 -0
- package/dist/ui/components/modals/ModalContainer.js +72 -16
- package/dist/ui/components/modals/ModalContainer.jsx.map +1 -0
- package/dist/ui/components/modals/SelectModal.js +53 -24
- package/dist/ui/components/modals/SelectModal.jsx.map +1 -0
- package/dist/ui/features/composer/Composer.js +145 -26
- package/dist/ui/features/composer/Composer.jsx.map +1 -0
- package/dist/ui/features/main-view/MainView.js +341 -248
- package/dist/ui/features/main-view/{MainView.js.map → MainView.jsx.map} +1 -1
- package/dist/ui/features/message-pane/MessagePane.js +46 -4
- package/dist/ui/features/message-pane/MessagePane.jsx.map +1 -0
- package/package.json +2 -2
- package/dist/components/MessageList.js.map +0 -1
- package/dist/runtime/context.js.map +0 -1
- package/dist/session-picker.js.map +0 -1
- package/dist/tui-open-rendering.js.map +0 -1
- package/dist/ui/components/modals/ConfirmModal.js.map +0 -1
- package/dist/ui/components/modals/EditorModal.js.map +0 -1
- package/dist/ui/components/modals/InputModal.js.map +0 -1
- package/dist/ui/components/modals/ModalContainer.js.map +0 -1
- package/dist/ui/components/modals/SelectModal.js.map +0 -1
- package/dist/ui/features/composer/Composer.js.map +0 -1
- package/dist/ui/features/message-pane/MessagePane.js.map +0 -1
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createComponent as _$createComponent } from "@opentui/solid";
|
|
2
2
|
import { ThemeProvider } from "@yeshwanthyk/open-tui";
|
|
3
3
|
import { batch, onMount } from "solid-js";
|
|
4
4
|
import { Effect } from "effect";
|
|
5
5
|
/** Detect system dark/light mode (macOS only, defaults to dark) */
|
|
6
6
|
function detectThemeMode() {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
7
|
+
try {
|
|
8
|
+
const result = Bun.spawnSync(["defaults", "read", "-g", "AppleInterfaceStyle"]);
|
|
9
|
+
return result.stdout.toString().trim().toLowerCase() === "dark" ? "dark" : "light";
|
|
10
|
+
} catch {
|
|
11
|
+
return "dark";
|
|
12
|
+
}
|
|
14
13
|
}
|
|
15
14
|
import { useRuntime } from "../../runtime/context.js";
|
|
16
15
|
import { createSessionController } from "../../runtime/session/session-controller.js";
|
|
@@ -29,450 +28,600 @@ import { completeSimple } from "@yeshwanthyk/ai";
|
|
|
29
28
|
import { useModals } from "../hooks/useModals.js";
|
|
30
29
|
import { ModalContainer } from "../components/modals/ModalContainer.js";
|
|
31
30
|
const SHELL_INJECTION_PREFIX = "[Shell output]";
|
|
32
|
-
export const TuiApp = ({
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
31
|
+
export const TuiApp = ({
|
|
32
|
+
initialSession
|
|
33
|
+
}) => {
|
|
34
|
+
const runtime = useRuntime();
|
|
35
|
+
const {
|
|
36
|
+
agent,
|
|
37
|
+
sessionManager,
|
|
38
|
+
hookRunner,
|
|
39
|
+
toolByName,
|
|
40
|
+
customCommands,
|
|
41
|
+
lsp,
|
|
42
|
+
config,
|
|
43
|
+
codexTransport,
|
|
44
|
+
getApiKey,
|
|
45
|
+
sendRef,
|
|
46
|
+
lspActiveRef,
|
|
47
|
+
cycleModels,
|
|
48
|
+
validationIssues
|
|
49
|
+
} = runtime;
|
|
50
|
+
const toolMetaByName = new Map();
|
|
51
|
+
for (const [name, entry] of toolByName.entries()) {
|
|
52
|
+
toolMetaByName.set(name, {
|
|
53
|
+
label: entry.label,
|
|
54
|
+
source: entry.source,
|
|
55
|
+
sourcePath: entry.sourcePath,
|
|
56
|
+
renderCall: entry.renderCall,
|
|
57
|
+
renderResult: entry.renderResult
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
const store = createAppStore({
|
|
61
|
+
initialTheme: config.theme,
|
|
62
|
+
initialModelId: config.modelId,
|
|
63
|
+
initialThinking: config.thinking,
|
|
64
|
+
initialContextWindow: config.model.contextWindow,
|
|
65
|
+
initialProvider: config.provider
|
|
66
|
+
});
|
|
67
|
+
const promptQueue = createPromptQueue(counts => store.queueCounts.set(counts));
|
|
68
|
+
const modals = useModals();
|
|
69
|
+
const sessionController = createSessionController({
|
|
70
|
+
initialProvider: config.provider,
|
|
71
|
+
initialModel: config.model,
|
|
72
|
+
initialModelId: config.modelId,
|
|
73
|
+
initialThinking: config.thinking,
|
|
74
|
+
agent,
|
|
75
|
+
sessionManager,
|
|
76
|
+
hookRunner,
|
|
77
|
+
toolByName: toolMetaByName,
|
|
78
|
+
setMessages: store.messages.set,
|
|
79
|
+
setContextTokens: store.contextTokens.set,
|
|
80
|
+
setDisplayProvider: store.currentProvider.set,
|
|
81
|
+
setDisplayModelId: store.displayModelId.set,
|
|
82
|
+
setDisplayThinking: store.displayThinking.set,
|
|
83
|
+
setDisplayContextWindow: store.displayContextWindow.set,
|
|
84
|
+
shellInjectionPrefix: SHELL_INJECTION_PREFIX,
|
|
85
|
+
promptQueue
|
|
86
|
+
});
|
|
87
|
+
onMount(() => {
|
|
88
|
+
if (initialSession) {
|
|
89
|
+
sessionController.restoreSession(initialSession);
|
|
44
90
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
91
|
+
});
|
|
92
|
+
const ensureSession = () => sessionController.ensureSession();
|
|
93
|
+
let cycleIndex = cycleModels.findIndex(entry => entry.model.id === config.modelId && entry.provider === config.provider);
|
|
94
|
+
if (cycleIndex < 0) cycleIndex = 0;
|
|
95
|
+
const streamingMessageIdRef = {
|
|
96
|
+
current: null
|
|
97
|
+
};
|
|
98
|
+
const retryConfig = {
|
|
99
|
+
enabled: true,
|
|
100
|
+
maxRetries: 3,
|
|
101
|
+
baseDelayMs: 2000
|
|
102
|
+
};
|
|
103
|
+
const retryablePattern = /overloaded|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server error|internal error/i;
|
|
104
|
+
const retryState = {
|
|
105
|
+
attempt: 0,
|
|
106
|
+
abortController: null
|
|
107
|
+
};
|
|
108
|
+
lspActiveRef.setActive = store.lspActive.set;
|
|
109
|
+
const eventCtx = {
|
|
110
|
+
setMessages: store.messages.set,
|
|
111
|
+
setToolBlocks: store.toolBlocks.set,
|
|
112
|
+
setActivityState: store.activityState.set,
|
|
113
|
+
setIsResponding: store.isResponding.set,
|
|
114
|
+
setContextTokens: store.contextTokens.set,
|
|
115
|
+
setCacheStats: store.cacheStats.set,
|
|
116
|
+
setRetryStatus: store.retryStatus.set,
|
|
117
|
+
setTurnCount: store.turnCount.set,
|
|
118
|
+
promptQueue,
|
|
119
|
+
sessionManager,
|
|
120
|
+
streamingMessageId: streamingMessageIdRef,
|
|
121
|
+
retryConfig,
|
|
122
|
+
retryablePattern,
|
|
123
|
+
retryState,
|
|
124
|
+
agent: agent,
|
|
125
|
+
hookRunner,
|
|
126
|
+
toolByName: toolMetaByName,
|
|
127
|
+
getContextWindow: () => store.displayContextWindow.value()
|
|
128
|
+
};
|
|
129
|
+
useAgentEvents({
|
|
130
|
+
agent,
|
|
131
|
+
context: eventCtx
|
|
132
|
+
});
|
|
133
|
+
const handleThemeChange = name => {
|
|
134
|
+
store.theme.set(name);
|
|
135
|
+
void updateAppConfig({
|
|
136
|
+
configDir: config.configDir,
|
|
137
|
+
configPath: config.configPath
|
|
138
|
+
}, {
|
|
139
|
+
theme: name
|
|
51
140
|
});
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
141
|
+
};
|
|
142
|
+
const exitHandlerRef = {
|
|
143
|
+
current: () => process.exit(0)
|
|
144
|
+
};
|
|
145
|
+
const editorOpenRef = {
|
|
146
|
+
current: async () => {}
|
|
147
|
+
};
|
|
148
|
+
const setEditorTextRef = {
|
|
149
|
+
current: _text => {}
|
|
150
|
+
};
|
|
151
|
+
const getEditorTextRef = {
|
|
152
|
+
current: () => ""
|
|
153
|
+
};
|
|
154
|
+
const showToastRef = {
|
|
155
|
+
current: (_title, _message, _variant) => {}
|
|
156
|
+
};
|
|
157
|
+
// Flag to skip editor clear when hooks populate the editor via setEditorText
|
|
158
|
+
const skipNextEditorClearRef = {
|
|
159
|
+
current: false
|
|
160
|
+
};
|
|
161
|
+
const handleBeforeExit = async () => {
|
|
162
|
+
// Emit shutdown hook before exiting
|
|
163
|
+
await hookRunner.emit({
|
|
164
|
+
type: "session.shutdown",
|
|
165
|
+
sessionId: sessionManager.sessionId
|
|
71
166
|
});
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
167
|
+
};
|
|
168
|
+
const submitPrompt = async (text, mode = "followUp") => {
|
|
169
|
+
const trimmed = text.trim();
|
|
170
|
+
if (!trimmed) return;
|
|
171
|
+
ensureSession();
|
|
172
|
+
let beforeStartResult;
|
|
173
|
+
try {
|
|
174
|
+
beforeStartResult = await hookRunner.emitBeforeAgentStart(trimmed);
|
|
175
|
+
const hookMsg = beforeStartResult?.message ? createHookMessage(beforeStartResult.message) : null;
|
|
176
|
+
if (hookMsg?.display) {
|
|
177
|
+
const uiMsg = {
|
|
178
|
+
id: crypto.randomUUID(),
|
|
179
|
+
role: "assistant",
|
|
180
|
+
content: typeof hookMsg.content === "string" ? hookMsg.content : hookMsg.content.map(p => p.type === "text" ? p.text : "[image]").join(""),
|
|
181
|
+
timestamp: hookMsg.timestamp
|
|
182
|
+
};
|
|
183
|
+
store.messages.set(prev => appendWithCap(prev, uiMsg));
|
|
184
|
+
}
|
|
185
|
+
} catch (err) {
|
|
186
|
+
store.messages.set(prev => appendWithCap(prev, {
|
|
187
|
+
id: crypto.randomUUID(),
|
|
188
|
+
role: "assistant",
|
|
189
|
+
content: `Hook error: ${err instanceof Error ? err.message : String(err)}`,
|
|
190
|
+
timestamp: Date.now()
|
|
191
|
+
}));
|
|
192
|
+
}
|
|
193
|
+
promptQueue.push({
|
|
194
|
+
text: trimmed,
|
|
195
|
+
mode
|
|
76
196
|
});
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
197
|
+
batch(() => {
|
|
198
|
+
store.toolBlocks.set([]);
|
|
199
|
+
store.isResponding.set(true);
|
|
200
|
+
store.activityState.set("thinking");
|
|
201
|
+
});
|
|
202
|
+
try {
|
|
203
|
+
await Effect.runPromise(runtime.sessionOrchestrator.submitPrompt(trimmed, {
|
|
204
|
+
mode,
|
|
205
|
+
beforeStartResult
|
|
206
|
+
}));
|
|
207
|
+
} catch (err) {
|
|
208
|
+
batch(() => {
|
|
209
|
+
store.messages.set(prev => appendWithCap(prev, {
|
|
210
|
+
id: crypto.randomUUID(),
|
|
211
|
+
role: "assistant",
|
|
212
|
+
content: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
213
|
+
}));
|
|
214
|
+
store.isResponding.set(false);
|
|
215
|
+
store.activityState.set("idle");
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
const steerHelper = async text => {
|
|
220
|
+
const trimmed = text.trim();
|
|
221
|
+
if (!trimmed) return;
|
|
222
|
+
if (store.isResponding.value()) {
|
|
223
|
+
await sessionController.steer(trimmed);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
await submitPrompt(trimmed, "steer");
|
|
227
|
+
};
|
|
228
|
+
const followUpHelper = async text => {
|
|
229
|
+
const trimmed = text.trim();
|
|
230
|
+
if (!trimmed) return;
|
|
231
|
+
if (store.isResponding.value()) {
|
|
232
|
+
await sessionController.followUp(trimmed);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
await submitPrompt(trimmed, "followUp");
|
|
236
|
+
};
|
|
237
|
+
const sendUserMessageHelper = async (text, options) => {
|
|
238
|
+
const mode = options?.deliverAs ?? "followUp";
|
|
239
|
+
if (mode === "steer") {
|
|
240
|
+
await steerHelper(text);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
await followUpHelper(text);
|
|
244
|
+
};
|
|
245
|
+
const cmdCtx = {
|
|
246
|
+
agent,
|
|
247
|
+
sessionManager,
|
|
248
|
+
configDir: config.configDir,
|
|
249
|
+
configPath: config.configPath,
|
|
250
|
+
cwd: process.cwd(),
|
|
251
|
+
editor: config.editor,
|
|
252
|
+
codexTransport,
|
|
253
|
+
getApiKey,
|
|
254
|
+
get currentProvider() {
|
|
255
|
+
return sessionController.currentProvider();
|
|
256
|
+
},
|
|
257
|
+
get currentModelId() {
|
|
258
|
+
return sessionController.currentModelId();
|
|
259
|
+
},
|
|
260
|
+
get currentThinking() {
|
|
261
|
+
return sessionController.currentThinking();
|
|
262
|
+
},
|
|
263
|
+
setCurrentProvider: p => sessionController.setCurrentProvider(p),
|
|
264
|
+
setCurrentModelId: id => sessionController.setCurrentModelId(id),
|
|
265
|
+
setCurrentThinking: t => sessionController.setCurrentThinking(t),
|
|
266
|
+
isResponding: store.isResponding.value,
|
|
267
|
+
setIsResponding: store.isResponding.set,
|
|
268
|
+
setActivityState: store.activityState.set,
|
|
269
|
+
setMessages: store.messages.set,
|
|
270
|
+
setToolBlocks: store.toolBlocks.set,
|
|
271
|
+
setContextTokens: store.contextTokens.set,
|
|
272
|
+
setCacheStats: store.cacheStats.set,
|
|
273
|
+
setDisplayModelId: store.displayModelId.set,
|
|
274
|
+
setDisplayThinking: store.displayThinking.set,
|
|
275
|
+
setDisplayContextWindow: store.displayContextWindow.set,
|
|
276
|
+
setDiffWrapMode: store.diffWrapMode.set,
|
|
277
|
+
setConcealMarkdown: store.concealMarkdown.set,
|
|
278
|
+
setTheme: handleThemeChange,
|
|
279
|
+
openEditor: () => editorOpenRef.current(),
|
|
280
|
+
onExit: () => exitHandlerRef.current(),
|
|
281
|
+
hookRunner,
|
|
282
|
+
submitPrompt: (text, options) => submitPrompt(text, options?.mode ?? "followUp"),
|
|
283
|
+
steer: text => steerHelper(text),
|
|
284
|
+
followUp: text => followUpHelper(text),
|
|
285
|
+
sendUserMessage: (text, options) => sendUserMessageHelper(text, options)
|
|
286
|
+
};
|
|
287
|
+
const builtInCommandNames = new Set(slashCommands.map(c => c.name));
|
|
288
|
+
const enqueueWhileResponding = (text, mode) => {
|
|
289
|
+
void sendUserMessageHelper(text, {
|
|
290
|
+
deliverAs: mode
|
|
291
|
+
}).catch(err => {
|
|
292
|
+
store.messages.set(prev => appendWithCap(prev, {
|
|
293
|
+
id: crypto.randomUUID(),
|
|
294
|
+
role: "assistant",
|
|
295
|
+
content: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
296
|
+
}));
|
|
297
|
+
});
|
|
298
|
+
};
|
|
299
|
+
const handleSubmit = async (text, editorClearFn) => {
|
|
300
|
+
if (!text.trim()) return;
|
|
301
|
+
if (text.startsWith("!")) {
|
|
302
|
+
const shouldInject = text.startsWith("!!");
|
|
303
|
+
const command = text.slice(shouldInject ? 2 : 1).trim();
|
|
304
|
+
if (!command) return;
|
|
305
|
+
editorClearFn?.();
|
|
306
|
+
ensureSession();
|
|
307
|
+
const shellMsgId = crypto.randomUUID();
|
|
308
|
+
const pendingMsg = {
|
|
309
|
+
id: shellMsgId,
|
|
310
|
+
role: "shell",
|
|
311
|
+
command,
|
|
312
|
+
output: "",
|
|
313
|
+
exitCode: null,
|
|
314
|
+
truncated: false,
|
|
315
|
+
timestamp: Date.now()
|
|
316
|
+
};
|
|
317
|
+
store.messages.set(prev => appendWithCap(prev, pendingMsg));
|
|
318
|
+
const result = await runShellCommand(command, {
|
|
319
|
+
timeout: 30000
|
|
320
|
+
});
|
|
321
|
+
const finalMsg = {
|
|
322
|
+
id: shellMsgId,
|
|
323
|
+
role: "shell",
|
|
324
|
+
command,
|
|
325
|
+
output: result.output,
|
|
326
|
+
exitCode: result.exitCode,
|
|
327
|
+
truncated: result.truncated,
|
|
328
|
+
tempFilePath: result.tempFilePath,
|
|
329
|
+
timestamp: Date.now()
|
|
330
|
+
};
|
|
331
|
+
store.messages.set(prev => prev.map(m => m.id === shellMsgId ? finalMsg : m));
|
|
332
|
+
sessionManager.appendMessage({
|
|
333
|
+
role: "shell",
|
|
334
|
+
command,
|
|
335
|
+
output: result.output,
|
|
336
|
+
exitCode: result.exitCode,
|
|
337
|
+
truncated: result.truncated,
|
|
338
|
+
tempFilePath: result.tempFilePath,
|
|
339
|
+
timestamp: Date.now()
|
|
340
|
+
});
|
|
341
|
+
if (shouldInject) {
|
|
342
|
+
const injectionLines = [`${SHELL_INJECTION_PREFIX}`, `$ ${command}`, result.output];
|
|
343
|
+
if (result.exitCode !== null && result.exitCode !== 0) injectionLines.push(`[exit ${result.exitCode}]`);
|
|
344
|
+
if (result.truncated && result.tempFilePath) injectionLines.push(`[truncated, full output: ${result.tempFilePath}]`);
|
|
345
|
+
const injectedText = injectionLines.filter(line => line.length > 0).join("\n");
|
|
346
|
+
const injectionMessage = {
|
|
347
|
+
role: "user",
|
|
348
|
+
content: [{
|
|
349
|
+
type: "text",
|
|
350
|
+
text: injectedText
|
|
351
|
+
}],
|
|
352
|
+
timestamp: Date.now()
|
|
353
|
+
};
|
|
354
|
+
agent.appendMessage(injectionMessage);
|
|
355
|
+
sessionManager.appendMessage(injectionMessage);
|
|
356
|
+
}
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
if (text.startsWith("/")) {
|
|
360
|
+
const trimmed = text.trim();
|
|
361
|
+
const handled = await handleSlashInput(trimmed, {
|
|
362
|
+
commandContext: cmdCtx,
|
|
363
|
+
customCommands,
|
|
364
|
+
builtInCommandNames,
|
|
365
|
+
onExpand: async expanded => handleSubmit(expanded)
|
|
366
|
+
});
|
|
367
|
+
if (handled) {
|
|
368
|
+
// Skip clear if hook populated editor via setEditorText
|
|
369
|
+
if (!skipNextEditorClearRef.current) {
|
|
370
|
+
editorClearFn?.();
|
|
150
371
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
372
|
+
skipNextEditorClearRef.current = false;
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
if (store.isResponding.value()) {
|
|
377
|
+
enqueueWhileResponding(text, "followUp");
|
|
378
|
+
editorClearFn?.();
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
editorClearFn?.();
|
|
382
|
+
await submitPrompt(text, "followUp");
|
|
383
|
+
};
|
|
384
|
+
// Initialize hook runner with full context
|
|
385
|
+
const hookUIContext = createHookUIContext({
|
|
386
|
+
setEditorText: text => {
|
|
387
|
+
skipNextEditorClearRef.current = true;
|
|
388
|
+
setEditorTextRef.current(text);
|
|
389
|
+
},
|
|
390
|
+
getEditorText: () => getEditorTextRef.current(),
|
|
391
|
+
showSelect: modals.showSelect,
|
|
392
|
+
showInput: modals.showInput,
|
|
393
|
+
showConfirm: modals.showConfirm,
|
|
394
|
+
showEditor: modals.showEditor,
|
|
395
|
+
showNotify: (message, type = "info") => showToastRef.current(type, message, type)
|
|
396
|
+
});
|
|
397
|
+
const hookSessionContext = {
|
|
398
|
+
summarize: async () => {
|
|
399
|
+
// Trigger compaction through the /compact command flow
|
|
400
|
+
await handleSlashInput("/compact", {
|
|
401
|
+
commandContext: cmdCtx,
|
|
402
|
+
customCommands,
|
|
403
|
+
builtInCommandNames,
|
|
404
|
+
onExpand: async expanded => handleSubmit(expanded)
|
|
405
|
+
});
|
|
406
|
+
},
|
|
407
|
+
toast: (title, message, variant = "info") => showToastRef.current(title, message, variant),
|
|
408
|
+
getTokenUsage: () => hookRunner["tokenUsage"],
|
|
409
|
+
getContextLimit: () => hookRunner["contextLimit"],
|
|
410
|
+
newSession: async _opts => {
|
|
411
|
+
// Clear current session and start fresh
|
|
412
|
+
store.messages.set([]);
|
|
413
|
+
store.toolBlocks.set([]);
|
|
414
|
+
store.contextTokens.set(0);
|
|
415
|
+
agent.reset();
|
|
416
|
+
void hookRunner.emit({
|
|
417
|
+
type: "session.clear",
|
|
418
|
+
sessionId: null
|
|
419
|
+
});
|
|
420
|
+
// Start a new session
|
|
421
|
+
sessionManager.startSession(sessionController.currentProvider(), sessionController.currentModelId(), sessionController.currentThinking());
|
|
422
|
+
return {
|
|
423
|
+
cancelled: false,
|
|
424
|
+
sessionId: sessionManager.sessionId ?? undefined
|
|
425
|
+
};
|
|
426
|
+
},
|
|
427
|
+
getApiKey: async model => getApiKey(model.provider),
|
|
428
|
+
complete: async (systemPrompt, userText) => {
|
|
429
|
+
const model = agent.state.model;
|
|
430
|
+
const apiKey = getApiKey(model.provider);
|
|
431
|
+
if (!apiKey) {
|
|
432
|
+
return {
|
|
433
|
+
text: "",
|
|
434
|
+
stopReason: "error"
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
try {
|
|
438
|
+
const userMessage = {
|
|
439
|
+
role: "user",
|
|
440
|
+
content: [{
|
|
441
|
+
type: "text",
|
|
442
|
+
text: userText
|
|
443
|
+
}],
|
|
444
|
+
timestamp: Date.now()
|
|
445
|
+
};
|
|
446
|
+
const result = await completeSimple(model, {
|
|
447
|
+
systemPrompt,
|
|
448
|
+
messages: [userMessage]
|
|
449
|
+
}, {
|
|
450
|
+
apiKey
|
|
156
451
|
});
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
452
|
+
const text = result.content.filter(c => c.type === "text").map(c => c.text).join("\n");
|
|
453
|
+
// Map stopReason: stop -> end, length -> max_tokens, toolUse -> tool_use
|
|
454
|
+
const stopMap = {
|
|
455
|
+
stop: "end",
|
|
456
|
+
length: "max_tokens",
|
|
457
|
+
toolUse: "tool_use",
|
|
458
|
+
error: "error",
|
|
459
|
+
aborted: "aborted"
|
|
460
|
+
};
|
|
461
|
+
return {
|
|
462
|
+
text,
|
|
463
|
+
stopReason: stopMap[result.stopReason] ?? "end"
|
|
464
|
+
};
|
|
465
|
+
} catch (err) {
|
|
466
|
+
return {
|
|
467
|
+
text: err instanceof Error ? err.message : String(err),
|
|
468
|
+
stopReason: "error"
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
const sendMessageHandler = (message, triggerTurn) => {
|
|
474
|
+
const hookMessage = createHookMessage(message);
|
|
475
|
+
// Add to UI messages if display is true
|
|
476
|
+
if (hookMessage.display) {
|
|
477
|
+
const uiMsg = {
|
|
478
|
+
id: crypto.randomUUID(),
|
|
479
|
+
role: "assistant",
|
|
480
|
+
// Render hook messages as assistant for now
|
|
481
|
+
content: typeof hookMessage.content === "string" ? hookMessage.content : hookMessage.content.map(p => p.type === "text" ? p.text : "[image]").join(""),
|
|
482
|
+
timestamp: hookMessage.timestamp
|
|
483
|
+
};
|
|
484
|
+
store.messages.set(prev => appendWithCap(prev, uiMsg));
|
|
485
|
+
}
|
|
486
|
+
// Persist hook message to session
|
|
487
|
+
sessionManager.appendMessage(hookMessage);
|
|
488
|
+
// Optionally trigger a new turn
|
|
489
|
+
if (triggerTurn) {
|
|
490
|
+
void handleSubmit(typeof hookMessage.content === "string" ? hookMessage.content : "");
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
hookRunner.initialize({
|
|
494
|
+
sendHandler: text => void handleSubmit(text),
|
|
495
|
+
sendMessageHandler,
|
|
496
|
+
sendUserMessageHandler: (text, options) => sendUserMessageHelper(text, options),
|
|
497
|
+
steerHandler: text => steerHelper(text),
|
|
498
|
+
followUpHandler: text => followUpHelper(text),
|
|
499
|
+
isIdleHandler: () => !store.isResponding.value(),
|
|
500
|
+
appendEntryHandler: (customType, data) => sessionManager.appendEntry(customType, data),
|
|
501
|
+
getSessionId: () => sessionManager.sessionId,
|
|
502
|
+
getModel: () => agent.state.model,
|
|
503
|
+
uiContext: hookUIContext,
|
|
504
|
+
sessionContext: hookSessionContext,
|
|
505
|
+
hasUI: true
|
|
506
|
+
});
|
|
507
|
+
sendRef.current = text => void handleSubmit(text);
|
|
508
|
+
const handleAbort = () => {
|
|
509
|
+
if (retryState.abortController) {
|
|
510
|
+
retryState.abortController.abort();
|
|
511
|
+
retryState.abortController = null;
|
|
512
|
+
retryState.attempt = 0;
|
|
513
|
+
store.retryStatus.set(null);
|
|
514
|
+
}
|
|
515
|
+
agent.abort();
|
|
516
|
+
agent.clearMessageQueue();
|
|
517
|
+
const restore = promptQueue.drainToScript();
|
|
518
|
+
Effect.runFork(Effect.catchAll(runtime.sessionOrchestrator.drainToScript, () => Effect.succeed(null)));
|
|
519
|
+
batch(() => {
|
|
520
|
+
store.isResponding.set(false);
|
|
521
|
+
store.activityState.set("idle");
|
|
522
|
+
});
|
|
523
|
+
return restore;
|
|
524
|
+
};
|
|
525
|
+
const cycleModel = () => {
|
|
526
|
+
if (cycleModels.length <= 1) return;
|
|
527
|
+
if (store.isResponding.value()) return;
|
|
528
|
+
cycleIndex = (cycleIndex + 1) % cycleModels.length;
|
|
529
|
+
const entry = cycleModels[cycleIndex];
|
|
530
|
+
sessionController.setCurrentProvider(entry.provider);
|
|
531
|
+
sessionController.setCurrentModelId(entry.model.id);
|
|
532
|
+
agent.setModel(entry.model);
|
|
533
|
+
store.displayModelId.set(entry.model.id);
|
|
534
|
+
store.displayContextWindow.set(entry.model.contextWindow);
|
|
535
|
+
};
|
|
536
|
+
const cycleThinking = () => {
|
|
537
|
+
const current = sessionController.currentThinking();
|
|
538
|
+
const next = THINKING_LEVELS[(THINKING_LEVELS.indexOf(current) + 1) % THINKING_LEVELS.length];
|
|
539
|
+
sessionController.setCurrentThinking(next);
|
|
540
|
+
agent.setThinkingLevel(next);
|
|
541
|
+
store.displayThinking.set(next);
|
|
542
|
+
};
|
|
543
|
+
const themeMode = detectThemeMode();
|
|
544
|
+
return _$createComponent(ThemeProvider, {
|
|
545
|
+
mode: themeMode,
|
|
546
|
+
get themeName() {
|
|
547
|
+
return store.theme.value();
|
|
548
|
+
},
|
|
549
|
+
onThemeChange: handleThemeChange,
|
|
550
|
+
get children() {
|
|
551
|
+
return [_$createComponent(MainView, {
|
|
552
|
+
validationIssues: validationIssues,
|
|
553
|
+
get messages() {
|
|
554
|
+
return store.messages.value();
|
|
211
555
|
},
|
|
212
|
-
get
|
|
213
|
-
|
|
556
|
+
get toolBlocks() {
|
|
557
|
+
return store.toolBlocks.value();
|
|
214
558
|
},
|
|
215
|
-
get
|
|
216
|
-
|
|
559
|
+
get isResponding() {
|
|
560
|
+
return store.isResponding.value();
|
|
217
561
|
},
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
setCurrentThinking: (t) => sessionController.setCurrentThinking(t),
|
|
221
|
-
isResponding: store.isResponding.value,
|
|
222
|
-
setIsResponding: store.isResponding.set,
|
|
223
|
-
setActivityState: store.activityState.set,
|
|
224
|
-
setMessages: store.messages.set,
|
|
225
|
-
setToolBlocks: store.toolBlocks.set,
|
|
226
|
-
setContextTokens: store.contextTokens.set,
|
|
227
|
-
setCacheStats: store.cacheStats.set,
|
|
228
|
-
setDisplayModelId: store.displayModelId.set,
|
|
229
|
-
setDisplayThinking: store.displayThinking.set,
|
|
230
|
-
setDisplayContextWindow: store.displayContextWindow.set,
|
|
231
|
-
setDiffWrapMode: store.diffWrapMode.set,
|
|
232
|
-
setConcealMarkdown: store.concealMarkdown.set,
|
|
233
|
-
setTheme: handleThemeChange,
|
|
234
|
-
openEditor: () => editorOpenRef.current(),
|
|
235
|
-
onExit: () => exitHandlerRef.current(),
|
|
236
|
-
hookRunner,
|
|
237
|
-
submitPrompt: (text, options) => submitPrompt(text, options?.mode ?? "followUp"),
|
|
238
|
-
steer: (text) => steerHelper(text),
|
|
239
|
-
followUp: (text) => followUpHelper(text),
|
|
240
|
-
sendUserMessage: (text, options) => sendUserMessageHelper(text, options),
|
|
241
|
-
};
|
|
242
|
-
const builtInCommandNames = new Set(slashCommands.map((c) => c.name));
|
|
243
|
-
const enqueueWhileResponding = (text, mode) => {
|
|
244
|
-
void sendUserMessageHelper(text, { deliverAs: mode }).catch((err) => {
|
|
245
|
-
store.messages.set((prev) => appendWithCap(prev, {
|
|
246
|
-
id: crypto.randomUUID(),
|
|
247
|
-
role: "assistant",
|
|
248
|
-
content: `Error: ${err instanceof Error ? err.message : String(err)}`,
|
|
249
|
-
}));
|
|
250
|
-
});
|
|
251
|
-
};
|
|
252
|
-
const handleSubmit = async (text, editorClearFn) => {
|
|
253
|
-
if (!text.trim())
|
|
254
|
-
return;
|
|
255
|
-
if (text.startsWith("!")) {
|
|
256
|
-
const shouldInject = text.startsWith("!!");
|
|
257
|
-
const command = text.slice(shouldInject ? 2 : 1).trim();
|
|
258
|
-
if (!command)
|
|
259
|
-
return;
|
|
260
|
-
editorClearFn?.();
|
|
261
|
-
ensureSession();
|
|
262
|
-
const shellMsgId = crypto.randomUUID();
|
|
263
|
-
const pendingMsg = {
|
|
264
|
-
id: shellMsgId,
|
|
265
|
-
role: "shell",
|
|
266
|
-
command,
|
|
267
|
-
output: "",
|
|
268
|
-
exitCode: null,
|
|
269
|
-
truncated: false,
|
|
270
|
-
timestamp: Date.now(),
|
|
271
|
-
};
|
|
272
|
-
store.messages.set((prev) => appendWithCap(prev, pendingMsg));
|
|
273
|
-
const result = await runShellCommand(command, { timeout: 30000 });
|
|
274
|
-
const finalMsg = {
|
|
275
|
-
id: shellMsgId,
|
|
276
|
-
role: "shell",
|
|
277
|
-
command,
|
|
278
|
-
output: result.output,
|
|
279
|
-
exitCode: result.exitCode,
|
|
280
|
-
truncated: result.truncated,
|
|
281
|
-
tempFilePath: result.tempFilePath,
|
|
282
|
-
timestamp: Date.now(),
|
|
283
|
-
};
|
|
284
|
-
store.messages.set((prev) => prev.map((m) => (m.id === shellMsgId ? finalMsg : m)));
|
|
285
|
-
sessionManager.appendMessage({
|
|
286
|
-
role: "shell",
|
|
287
|
-
command,
|
|
288
|
-
output: result.output,
|
|
289
|
-
exitCode: result.exitCode,
|
|
290
|
-
truncated: result.truncated,
|
|
291
|
-
tempFilePath: result.tempFilePath,
|
|
292
|
-
timestamp: Date.now(),
|
|
293
|
-
});
|
|
294
|
-
if (shouldInject) {
|
|
295
|
-
const injectionLines = [`${SHELL_INJECTION_PREFIX}`, `$ ${command}`, result.output];
|
|
296
|
-
if (result.exitCode !== null && result.exitCode !== 0)
|
|
297
|
-
injectionLines.push(`[exit ${result.exitCode}]`);
|
|
298
|
-
if (result.truncated && result.tempFilePath)
|
|
299
|
-
injectionLines.push(`[truncated, full output: ${result.tempFilePath}]`);
|
|
300
|
-
const injectedText = injectionLines.filter((line) => line.length > 0).join("\n");
|
|
301
|
-
const injectionMessage = {
|
|
302
|
-
role: "user",
|
|
303
|
-
content: [{ type: "text", text: injectedText }],
|
|
304
|
-
timestamp: Date.now(),
|
|
305
|
-
};
|
|
306
|
-
agent.appendMessage(injectionMessage);
|
|
307
|
-
sessionManager.appendMessage(injectionMessage);
|
|
308
|
-
}
|
|
309
|
-
return;
|
|
310
|
-
}
|
|
311
|
-
if (text.startsWith("/")) {
|
|
312
|
-
const trimmed = text.trim();
|
|
313
|
-
const handled = await handleSlashInput(trimmed, {
|
|
314
|
-
commandContext: cmdCtx,
|
|
315
|
-
customCommands,
|
|
316
|
-
builtInCommandNames,
|
|
317
|
-
onExpand: async (expanded) => handleSubmit(expanded),
|
|
318
|
-
});
|
|
319
|
-
if (handled) {
|
|
320
|
-
// Skip clear if hook populated editor via setEditorText
|
|
321
|
-
if (!skipNextEditorClearRef.current) {
|
|
322
|
-
editorClearFn?.();
|
|
323
|
-
}
|
|
324
|
-
skipNextEditorClearRef.current = false;
|
|
325
|
-
return;
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
if (store.isResponding.value()) {
|
|
329
|
-
enqueueWhileResponding(text, "followUp");
|
|
330
|
-
editorClearFn?.();
|
|
331
|
-
return;
|
|
332
|
-
}
|
|
333
|
-
editorClearFn?.();
|
|
334
|
-
await submitPrompt(text, "followUp");
|
|
335
|
-
};
|
|
336
|
-
// Initialize hook runner with full context
|
|
337
|
-
const hookUIContext = createHookUIContext({
|
|
338
|
-
setEditorText: (text) => {
|
|
339
|
-
skipNextEditorClearRef.current = true;
|
|
340
|
-
setEditorTextRef.current(text);
|
|
562
|
+
get activityState() {
|
|
563
|
+
return store.activityState.value();
|
|
341
564
|
},
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
showInput: modals.showInput,
|
|
345
|
-
showConfirm: modals.showConfirm,
|
|
346
|
-
showEditor: modals.showEditor,
|
|
347
|
-
showNotify: (message, type = "info") => showToastRef.current(type, message, type)
|
|
348
|
-
});
|
|
349
|
-
const hookSessionContext = {
|
|
350
|
-
summarize: async () => {
|
|
351
|
-
// Trigger compaction through the /compact command flow
|
|
352
|
-
await handleSlashInput("/compact", {
|
|
353
|
-
commandContext: cmdCtx,
|
|
354
|
-
customCommands,
|
|
355
|
-
builtInCommandNames,
|
|
356
|
-
onExpand: async (expanded) => handleSubmit(expanded),
|
|
357
|
-
});
|
|
565
|
+
get thinkingVisible() {
|
|
566
|
+
return store.thinkingVisible.value();
|
|
358
567
|
},
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
getContextLimit: () => hookRunner["contextLimit"],
|
|
362
|
-
newSession: async (_opts) => {
|
|
363
|
-
// Clear current session and start fresh
|
|
364
|
-
store.messages.set([]);
|
|
365
|
-
store.toolBlocks.set([]);
|
|
366
|
-
store.contextTokens.set(0);
|
|
367
|
-
agent.reset();
|
|
368
|
-
void hookRunner.emit({ type: "session.clear", sessionId: null });
|
|
369
|
-
// Start a new session
|
|
370
|
-
sessionManager.startSession(sessionController.currentProvider(), sessionController.currentModelId(), sessionController.currentThinking());
|
|
371
|
-
return { cancelled: false, sessionId: sessionManager.sessionId ?? undefined };
|
|
568
|
+
get modelId() {
|
|
569
|
+
return store.displayModelId.value();
|
|
372
570
|
},
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
const model = agent.state.model;
|
|
376
|
-
const apiKey = getApiKey(model.provider);
|
|
377
|
-
if (!apiKey) {
|
|
378
|
-
return { text: "", stopReason: "error" };
|
|
379
|
-
}
|
|
380
|
-
try {
|
|
381
|
-
const userMessage = {
|
|
382
|
-
role: "user",
|
|
383
|
-
content: [{ type: "text", text: userText }],
|
|
384
|
-
timestamp: Date.now(),
|
|
385
|
-
};
|
|
386
|
-
const result = await completeSimple(model, { systemPrompt, messages: [userMessage] }, { apiKey });
|
|
387
|
-
const text = result.content
|
|
388
|
-
.filter((c) => c.type === "text")
|
|
389
|
-
.map((c) => c.text)
|
|
390
|
-
.join("\n");
|
|
391
|
-
// Map stopReason: stop -> end, length -> max_tokens, toolUse -> tool_use
|
|
392
|
-
const stopMap = {
|
|
393
|
-
stop: "end", length: "max_tokens", toolUse: "tool_use", error: "error", aborted: "aborted"
|
|
394
|
-
};
|
|
395
|
-
return { text, stopReason: stopMap[result.stopReason] ?? "end" };
|
|
396
|
-
}
|
|
397
|
-
catch (err) {
|
|
398
|
-
return { text: err instanceof Error ? err.message : String(err), stopReason: "error" };
|
|
399
|
-
}
|
|
571
|
+
get thinking() {
|
|
572
|
+
return store.displayThinking.value();
|
|
400
573
|
},
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
574
|
+
get provider() {
|
|
575
|
+
return store.currentProvider.value();
|
|
576
|
+
},
|
|
577
|
+
get contextTokens() {
|
|
578
|
+
return store.contextTokens.value();
|
|
579
|
+
},
|
|
580
|
+
get contextWindow() {
|
|
581
|
+
return store.displayContextWindow.value();
|
|
582
|
+
},
|
|
583
|
+
get queueCounts() {
|
|
584
|
+
return store.queueCounts.value();
|
|
585
|
+
},
|
|
586
|
+
get retryStatus() {
|
|
587
|
+
return store.retryStatus.value();
|
|
588
|
+
},
|
|
589
|
+
get turnCount() {
|
|
590
|
+
return store.turnCount.value();
|
|
591
|
+
},
|
|
592
|
+
get lspActive() {
|
|
593
|
+
return store.lspActive.value();
|
|
594
|
+
},
|
|
595
|
+
get diffWrapMode() {
|
|
596
|
+
return store.diffWrapMode.value();
|
|
597
|
+
},
|
|
598
|
+
get concealMarkdown() {
|
|
599
|
+
return store.concealMarkdown.value();
|
|
600
|
+
},
|
|
601
|
+
customCommands: customCommands,
|
|
602
|
+
onSubmit: handleSubmit,
|
|
603
|
+
onAbort: handleAbort,
|
|
604
|
+
onToggleThinking: () => store.thinkingVisible.set(v => !v),
|
|
605
|
+
onCycleModel: cycleModel,
|
|
606
|
+
onCycleThinking: cycleThinking,
|
|
607
|
+
exitHandlerRef: exitHandlerRef,
|
|
608
|
+
editorOpenRef: editorOpenRef,
|
|
609
|
+
setEditorTextRef: setEditorTextRef,
|
|
610
|
+
getEditorTextRef: getEditorTextRef,
|
|
611
|
+
showToastRef: showToastRef,
|
|
612
|
+
onBeforeExit: handleBeforeExit,
|
|
613
|
+
get editor() {
|
|
614
|
+
return config.editor;
|
|
615
|
+
},
|
|
616
|
+
lsp: lsp
|
|
617
|
+
}), _$createComponent(ModalContainer, {
|
|
618
|
+
get modalState() {
|
|
619
|
+
return modals.modalState();
|
|
620
|
+
},
|
|
621
|
+
get onClose() {
|
|
622
|
+
return modals.closeModal;
|
|
444
623
|
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
batch(() => {
|
|
450
|
-
store.isResponding.set(false);
|
|
451
|
-
store.activityState.set("idle");
|
|
452
|
-
});
|
|
453
|
-
return restore;
|
|
454
|
-
};
|
|
455
|
-
const cycleModel = () => {
|
|
456
|
-
if (cycleModels.length <= 1)
|
|
457
|
-
return;
|
|
458
|
-
if (store.isResponding.value())
|
|
459
|
-
return;
|
|
460
|
-
cycleIndex = (cycleIndex + 1) % cycleModels.length;
|
|
461
|
-
const entry = cycleModels[cycleIndex];
|
|
462
|
-
sessionController.setCurrentProvider(entry.provider);
|
|
463
|
-
sessionController.setCurrentModelId(entry.model.id);
|
|
464
|
-
agent.setModel(entry.model);
|
|
465
|
-
store.displayModelId.set(entry.model.id);
|
|
466
|
-
store.displayContextWindow.set(entry.model.contextWindow);
|
|
467
|
-
};
|
|
468
|
-
const cycleThinking = () => {
|
|
469
|
-
const current = sessionController.currentThinking();
|
|
470
|
-
const next = THINKING_LEVELS[(THINKING_LEVELS.indexOf(current) + 1) % THINKING_LEVELS.length];
|
|
471
|
-
sessionController.setCurrentThinking(next);
|
|
472
|
-
agent.setThinkingLevel(next);
|
|
473
|
-
store.displayThinking.set(next);
|
|
474
|
-
};
|
|
475
|
-
const themeMode = detectThemeMode();
|
|
476
|
-
return (_jsxs(ThemeProvider, { mode: themeMode, themeName: store.theme.value(), onThemeChange: handleThemeChange, children: [_jsx(MainView, { validationIssues: validationIssues, messages: store.messages.value(), toolBlocks: store.toolBlocks.value(), isResponding: store.isResponding.value(), activityState: store.activityState.value(), thinkingVisible: store.thinkingVisible.value(), modelId: store.displayModelId.value(), thinking: store.displayThinking.value(), provider: store.currentProvider.value(), contextTokens: store.contextTokens.value(), contextWindow: store.displayContextWindow.value(), queueCounts: store.queueCounts.value(), retryStatus: store.retryStatus.value(), turnCount: store.turnCount.value(), lspActive: store.lspActive.value(), diffWrapMode: store.diffWrapMode.value(), concealMarkdown: store.concealMarkdown.value(), customCommands: customCommands, onSubmit: handleSubmit, onAbort: handleAbort, onToggleThinking: () => store.thinkingVisible.set((v) => !v), onCycleModel: cycleModel, onCycleThinking: cycleThinking, exitHandlerRef: exitHandlerRef, editorOpenRef: editorOpenRef, setEditorTextRef: setEditorTextRef, getEditorTextRef: getEditorTextRef, showToastRef: showToastRef, onBeforeExit: handleBeforeExit, editor: config.editor, lsp: lsp }), _jsx(ModalContainer, { modalState: modals.modalState(), onClose: modals.closeModal })] }));
|
|
477
|
-
};
|
|
478
|
-
//# sourceMappingURL=TuiApp.js.map
|
|
624
|
+
})];
|
|
625
|
+
}
|
|
626
|
+
});
|
|
627
|
+
};
|