protoagent 0.1.9 → 0.1.11
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/README.md +0 -1
- package/dist/App.js +114 -81
- package/dist/agentic-loop.js +182 -31
- package/dist/cli.js +3 -3
- package/dist/config.js +76 -22
- package/dist/mcp.js +15 -0
- package/dist/providers.js +8 -15
- package/dist/sessions.js +13 -3
- package/dist/skills.js +2 -1
- package/dist/sub-agent.js +138 -20
- package/dist/system-prompt.js +45 -0
- package/dist/tools/bash.js +1 -1
- package/dist/tools/index.js +1 -1
- package/dist/utils/approval.js +8 -8
- package/dist/utils/cost-tracker.js +9 -3
- package/dist/utils/file-time.js +0 -9
- package/package.json +23 -3
package/README.md
CHANGED
|
@@ -61,7 +61,6 @@ protoagent init --project --force
|
|
|
61
61
|
## Interactive Commands
|
|
62
62
|
|
|
63
63
|
- `/help` — Show available slash commands
|
|
64
|
-
- `/clear` — Start a fresh conversation in a new session
|
|
65
64
|
- `/collapse` — Collapse long system and tool output
|
|
66
65
|
- `/expand` — Expand collapsed messages
|
|
67
66
|
- `/quit` or `/exit` — Save and exit
|
package/dist/App.js
CHANGED
|
@@ -43,8 +43,7 @@ Here's how the terminal UI is laid out (showcasing all options at once for demon
|
|
|
43
43
|
├─────────────────────────────────────────┤
|
|
44
44
|
│ tokens: 1234↓ 56↑ | ctx: 12% | $0.02 │ static-ish, updates after each turn
|
|
45
45
|
├─────────────────────────────────────────┤
|
|
46
|
-
│ /
|
|
47
|
-
│ /quit — Exit ProtoAgent │
|
|
46
|
+
│ /quit — Exit ProtoAgent │ dynamic, shown when typing /
|
|
48
47
|
├─────────────────────────────────────────┤
|
|
49
48
|
│ ⠹ Running read_file... │ dynamic, shown while loading
|
|
50
49
|
├─────────────────────────────────────────┤
|
|
@@ -59,17 +58,17 @@ Here's how the terminal UI is laid out (showcasing all options at once for demon
|
|
|
59
58
|
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
60
59
|
import { Box, Text, Static, useApp, useInput, useStdout } from 'ink';
|
|
61
60
|
import { LeftBar } from './components/LeftBar.js';
|
|
62
|
-
import { TextInput, Select
|
|
61
|
+
import { TextInput, Select } from '@inkjs/ui';
|
|
63
62
|
import { OpenAI } from 'openai';
|
|
64
|
-
import { readConfig, writeConfig, resolveApiKey } from './config.js';
|
|
65
|
-
import { loadRuntimeConfig } from './runtime-config.js';
|
|
66
|
-
import {
|
|
63
|
+
import { readConfig, writeConfig, writeInitConfig, resolveApiKey, TargetSelection, ModelSelection, ApiKeyInput } from './config.js';
|
|
64
|
+
import { loadRuntimeConfig, getActiveRuntimeConfigPath } from './runtime-config.js';
|
|
65
|
+
import { getProvider, getModelPricing, getRequestDefaultParams } from './providers.js';
|
|
67
66
|
import { runAgenticLoop, initializeMessages, } from './agentic-loop.js';
|
|
68
|
-
import {
|
|
67
|
+
import { setDangerouslySkipPermissions, setApprovalHandler, clearApprovalHandler } from './tools/index.js';
|
|
69
68
|
import { setLogLevel, LogLevel, initLogFile, logger } from './utils/logger.js';
|
|
70
69
|
import { createSession, ensureSystemPromptAtTop, saveSession, loadSession, generateTitle, } from './sessions.js';
|
|
71
70
|
import { clearTodos, getTodosForSession, setTodosForSession } from './tools/todo.js';
|
|
72
|
-
import { initializeMcp, closeMcp } from './mcp.js';
|
|
71
|
+
import { initializeMcp, closeMcp, getConnectedMcpServers } from './mcp.js';
|
|
73
72
|
import { generateSystemPrompt } from './system-prompt.js';
|
|
74
73
|
// ─── Scrollback helpers ───
|
|
75
74
|
// These functions append text to the permanent scrollback buffer via the
|
|
@@ -84,16 +83,25 @@ function printBanner(addStatic) {
|
|
|
84
83
|
'',
|
|
85
84
|
].join('\n'));
|
|
86
85
|
}
|
|
87
|
-
function printRuntimeHeader(addStatic, config, session,
|
|
86
|
+
function printRuntimeHeader(addStatic, config, session, dangerouslySkipPermissions) {
|
|
88
87
|
const provider = getProvider(config.provider);
|
|
89
88
|
let line = `Model: ${provider?.name || config.provider} / ${config.model}`;
|
|
90
|
-
if (
|
|
89
|
+
if (dangerouslySkipPermissions)
|
|
91
90
|
line += ' (auto-approve all)';
|
|
92
91
|
if (session)
|
|
93
|
-
line += ` | Session: ${session.id
|
|
94
|
-
let text =
|
|
92
|
+
line += ` | Session: ${session.id}`;
|
|
93
|
+
let text = `\x1b[2m${line}\x1b[0m\n`;
|
|
94
|
+
const logFilePath = logger.getLogFilePath();
|
|
95
95
|
if (logFilePath) {
|
|
96
|
-
text +=
|
|
96
|
+
text += `\x1b[2mDebug logs: ${logFilePath}\x1b[0m\n`;
|
|
97
|
+
}
|
|
98
|
+
const configPath = getActiveRuntimeConfigPath();
|
|
99
|
+
if (configPath) {
|
|
100
|
+
text += `\x1b[2mConfig file: ${configPath}\x1b[0m\n`;
|
|
101
|
+
}
|
|
102
|
+
const mcpServers = getConnectedMcpServers();
|
|
103
|
+
if (mcpServers.length > 0) {
|
|
104
|
+
text += `\x1b[2mMCPs: ${mcpServers.join(', ')}\x1b[0m\n`;
|
|
97
105
|
}
|
|
98
106
|
text += '\n';
|
|
99
107
|
addStatic(text);
|
|
@@ -119,6 +127,63 @@ function printMessageToScrollback(addStatic, role, text) {
|
|
|
119
127
|
}
|
|
120
128
|
addStatic(`${normalized}\n\n`);
|
|
121
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* Format a sub-agent tool call into a human-readable activity string.
|
|
132
|
+
* Shows what the sub-agent is actually doing, e.g. "Sub-agent reading file package.json"
|
|
133
|
+
*/
|
|
134
|
+
function formatSubAgentActivity(tool, args) {
|
|
135
|
+
if (!args || typeof args !== 'object') {
|
|
136
|
+
return `Sub-agent running ${tool}...`;
|
|
137
|
+
}
|
|
138
|
+
const argEntries = Object.entries(args);
|
|
139
|
+
if (argEntries.length === 0) {
|
|
140
|
+
return `Sub-agent running ${tool}...`;
|
|
141
|
+
}
|
|
142
|
+
// Extract the most meaningful argument based on the tool
|
|
143
|
+
let detail = '';
|
|
144
|
+
const firstValue = argEntries[0]?.[1];
|
|
145
|
+
switch (tool) {
|
|
146
|
+
case 'read_file':
|
|
147
|
+
detail = typeof args.file_path === 'string' ? args.file_path : '';
|
|
148
|
+
break;
|
|
149
|
+
case 'write_file':
|
|
150
|
+
detail = typeof args.file_path === 'string' ? args.file_path : '';
|
|
151
|
+
break;
|
|
152
|
+
case 'edit_file':
|
|
153
|
+
detail = typeof args.file_path === 'string' ? args.file_path : '';
|
|
154
|
+
break;
|
|
155
|
+
case 'list_directory':
|
|
156
|
+
detail = typeof args.directory_path === 'string' ? args.directory_path : '(current)';
|
|
157
|
+
break;
|
|
158
|
+
case 'search_files':
|
|
159
|
+
detail = typeof args.search_term === 'string' ? `"${args.search_term}"` : '';
|
|
160
|
+
break;
|
|
161
|
+
case 'bash':
|
|
162
|
+
detail = typeof args.command === 'string'
|
|
163
|
+
? args.command.split(/\s+/).slice(0, 3).join(' ') + (args.command.split(/\s+/).length > 3 ? '...' : '')
|
|
164
|
+
: '';
|
|
165
|
+
break;
|
|
166
|
+
case 'todo_write':
|
|
167
|
+
detail = Array.isArray(args.todos) ? `${args.todos.length} task(s)` : '';
|
|
168
|
+
break;
|
|
169
|
+
case 'webfetch':
|
|
170
|
+
detail = typeof args.url === 'string' ? new URL(args.url).hostname : '';
|
|
171
|
+
break;
|
|
172
|
+
case 'sub_agent':
|
|
173
|
+
// Nested sub-agent
|
|
174
|
+
detail = 'nested task...';
|
|
175
|
+
break;
|
|
176
|
+
default:
|
|
177
|
+
// Use the first argument value as fallback
|
|
178
|
+
detail = typeof firstValue === 'string'
|
|
179
|
+
? firstValue.length > 30 ? firstValue.slice(0, 30) + '...' : firstValue
|
|
180
|
+
: '';
|
|
181
|
+
}
|
|
182
|
+
if (detail) {
|
|
183
|
+
return `Sub-agent ${tool.replace(/_/g, ' ')}: ${detail}`;
|
|
184
|
+
}
|
|
185
|
+
return `Sub-agent running ${tool}...`;
|
|
186
|
+
}
|
|
122
187
|
function replayMessagesToScrollback(addStatic, messages) {
|
|
123
188
|
for (const message of messages) {
|
|
124
189
|
const msgAny = message;
|
|
@@ -154,7 +219,6 @@ function clipToRows(text, terminalRows) {
|
|
|
154
219
|
}
|
|
155
220
|
// ─── Available slash commands ───
|
|
156
221
|
const SLASH_COMMANDS = [
|
|
157
|
-
{ name: '/clear', description: 'Clear conversation and start fresh' },
|
|
158
222
|
{ name: '/help', description: 'Show all available commands' },
|
|
159
223
|
{ name: '/quit', description: 'Exit ProtoAgent' },
|
|
160
224
|
{ name: '/exit', description: 'Alias for /quit' },
|
|
@@ -162,7 +226,6 @@ const SLASH_COMMANDS = [
|
|
|
162
226
|
const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
163
227
|
const HELP_TEXT = [
|
|
164
228
|
'Commands:',
|
|
165
|
-
' /clear - Clear conversation and start fresh',
|
|
166
229
|
' /help - Show this help',
|
|
167
230
|
' /quit - Exit ProtoAgent',
|
|
168
231
|
' /exit - Alias for /quit',
|
|
@@ -234,44 +297,37 @@ const ApprovalPrompt = ({ request, onRespond }) => {
|
|
|
234
297
|
const UsageDisplay = ({ usage, totalCost }) => {
|
|
235
298
|
if (!usage && totalCost === 0)
|
|
236
299
|
return null;
|
|
237
|
-
return (_jsxs(Box, { marginTop: 1, children: [usage && (_jsxs(Box, { children: [_jsxs(Box, { backgroundColor: "#064e3b", paddingX: 1, children: [_jsx(Text, { color: "
|
|
300
|
+
return (_jsxs(Box, { marginTop: 1, children: [usage && (_jsxs(Box, { children: [_jsxs(Box, { backgroundColor: "#064e3b", paddingX: 1, children: [_jsx(Text, { color: "white", children: "tokens: " }), _jsxs(Text, { color: "white", bold: true, children: [usage.inputTokens, "\u2193 ", usage.outputTokens, "\u2191"] })] }), _jsxs(Box, { backgroundColor: "#065f46", paddingX: 1, children: [_jsx(Text, { color: "white", children: "ctx: " }), _jsxs(Text, { color: "white", bold: true, children: [usage.contextPercent.toFixed(0), "%"] })] })] })), totalCost > 0 && (_jsxs(Box, { backgroundColor: "#064e3b", paddingX: 1, children: [_jsx(Text, { color: "black", children: "cost: " }), _jsxs(Text, { color: "black", bold: true, children: ["$", totalCost.toFixed(4)] })] }))] }));
|
|
238
301
|
};
|
|
239
302
|
/** Inline setup wizard — shown when no config exists. */
|
|
240
303
|
const InlineSetup = ({ onComplete }) => {
|
|
241
|
-
const [setupStep, setSetupStep] = useState('
|
|
304
|
+
const [setupStep, setSetupStep] = useState('target');
|
|
305
|
+
const [target, setTarget] = useState('project');
|
|
242
306
|
const [selectedProviderId, setSelectedProviderId] = useState('');
|
|
243
307
|
const [selectedModelId, setSelectedModelId] = useState('');
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
308
|
+
const handleModelSelect = (providerId, modelId) => {
|
|
309
|
+
setSelectedProviderId(providerId);
|
|
310
|
+
setSelectedModelId(modelId);
|
|
311
|
+
setSetupStep('api_key');
|
|
312
|
+
};
|
|
313
|
+
const handleConfigComplete = (config) => {
|
|
314
|
+
writeInitConfig(target);
|
|
315
|
+
writeConfig(config, target);
|
|
316
|
+
onComplete(config);
|
|
317
|
+
};
|
|
318
|
+
if (setupStep === 'target') {
|
|
319
|
+
return (_jsx(Box, { marginTop: 1, children: _jsx(TargetSelection, { title: "First-time setup", subtitle: "Create a ProtoAgent runtime config:", onSelect: (value) => {
|
|
320
|
+
setTarget(value);
|
|
321
|
+
setSetupStep('provider');
|
|
322
|
+
} }) }));
|
|
323
|
+
}
|
|
249
324
|
if (setupStep === 'provider') {
|
|
250
|
-
return (
|
|
251
|
-
const [providerId, modelId] = value.split(':::');
|
|
252
|
-
setSelectedProviderId(providerId);
|
|
253
|
-
setSelectedModelId(modelId);
|
|
254
|
-
setSetupStep('api_key');
|
|
255
|
-
} }) })] }));
|
|
325
|
+
return (_jsx(Box, { marginTop: 1, children: _jsx(ModelSelection, { setSelectedProviderId: setSelectedProviderId, setSelectedModelId: setSelectedModelId, onSelect: handleModelSelect, title: "First-time setup" }) }));
|
|
256
326
|
}
|
|
257
|
-
|
|
258
|
-
const hasResolvedAuth = Boolean(resolveApiKey({ provider: selectedProviderId, apiKey: undefined }));
|
|
259
|
-
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: "yellow", bold: true, children: "First-time setup" }), _jsxs(Text, { dimColor: true, children: ["Selected: ", provider?.name, " / ", selectedModelId] }), _jsx(Text, { children: hasResolvedAuth ? 'Optional API key:' : 'Enter your API key:' }), apiKeyError && _jsx(Text, { color: "red", children: apiKeyError }), _jsx(PasswordInput, { placeholder: hasResolvedAuth ? 'Press enter to keep resolved auth' : `Paste your ${provider?.apiKeyEnvVar || 'API'} key`, onSubmit: (value) => {
|
|
260
|
-
if (value.trim().length === 0 && !hasResolvedAuth) {
|
|
261
|
-
setApiKeyError('API key cannot be empty.');
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
const newConfig = {
|
|
265
|
-
provider: selectedProviderId,
|
|
266
|
-
model: selectedModelId,
|
|
267
|
-
...(value.trim().length > 0 ? { apiKey: value.trim() } : {}),
|
|
268
|
-
};
|
|
269
|
-
writeConfig(newConfig, 'project');
|
|
270
|
-
onComplete(newConfig);
|
|
271
|
-
} })] }));
|
|
327
|
+
return (_jsx(Box, { marginTop: 1, children: _jsx(ApiKeyInput, { selectedProviderId: selectedProviderId, selectedModelId: selectedModelId, target: target, title: "First-time setup", showProviderHeaders: false, onComplete: handleConfigComplete }) }));
|
|
272
328
|
};
|
|
273
329
|
// ─── Main App ───
|
|
274
|
-
export const App = ({
|
|
330
|
+
export const App = ({ dangerouslySkipPermissions = false, logLevel, sessionId, }) => {
|
|
275
331
|
const { exit } = useApp();
|
|
276
332
|
const { stdout } = useStdout();
|
|
277
333
|
const terminalRows = stdout?.rows ?? 24;
|
|
@@ -309,7 +365,6 @@ export const App = ({ dangerouslyAcceptAll = false, logLevel, sessionId, }) => {
|
|
|
309
365
|
const [threadErrors, setThreadErrors] = useState([]);
|
|
310
366
|
const [initialized, setInitialized] = useState(false);
|
|
311
367
|
const [needsSetup, setNeedsSetup] = useState(false);
|
|
312
|
-
const [logFilePath, setLogFilePath] = useState(null);
|
|
313
368
|
// Input reset key — incremented on submit to force TextInput remount and clear
|
|
314
369
|
const [inputResetKey, setInputResetKey] = useState(0);
|
|
315
370
|
// Approval state
|
|
@@ -331,7 +386,6 @@ export const App = ({ dangerouslyAcceptAll = false, logLevel, sessionId, }) => {
|
|
|
331
386
|
const abortControllerRef = useRef(null);
|
|
332
387
|
const didPrintIntroRef = useRef(false);
|
|
333
388
|
const printedThreadErrorIdsRef = useRef(new Set());
|
|
334
|
-
const printedLogPathRef = useRef(null);
|
|
335
389
|
// ─── Post-config initialization (reused after inline setup) ───
|
|
336
390
|
const initializeWithConfig = useCallback(async (loadedConfig) => {
|
|
337
391
|
setConfig(loadedConfig);
|
|
@@ -350,7 +404,7 @@ export const App = ({ dangerouslyAcceptAll = false, logLevel, sessionId, }) => {
|
|
|
350
404
|
setCompletionMessages(loadedSession.completionMessages);
|
|
351
405
|
if (!didPrintIntroRef.current) {
|
|
352
406
|
printBanner(addStatic);
|
|
353
|
-
printRuntimeHeader(addStatic, loadedConfig, loadedSession,
|
|
407
|
+
printRuntimeHeader(addStatic, loadedConfig, loadedSession, dangerouslySkipPermissions);
|
|
354
408
|
replayMessagesToScrollback(addStatic, loadedSession.completionMessages);
|
|
355
409
|
didPrintIntroRef.current = true;
|
|
356
410
|
}
|
|
@@ -369,13 +423,13 @@ export const App = ({ dangerouslyAcceptAll = false, logLevel, sessionId, }) => {
|
|
|
369
423
|
setSession(newSession);
|
|
370
424
|
if (!didPrintIntroRef.current) {
|
|
371
425
|
printBanner(addStatic);
|
|
372
|
-
printRuntimeHeader(addStatic, loadedConfig, newSession,
|
|
426
|
+
printRuntimeHeader(addStatic, loadedConfig, newSession, dangerouslySkipPermissions);
|
|
373
427
|
didPrintIntroRef.current = true;
|
|
374
428
|
}
|
|
375
429
|
}
|
|
376
430
|
setNeedsSetup(false);
|
|
377
431
|
setInitialized(true);
|
|
378
|
-
}, [
|
|
432
|
+
}, [dangerouslySkipPermissions, sessionId, addStatic]);
|
|
379
433
|
// ─── Initialization ───
|
|
380
434
|
useEffect(() => {
|
|
381
435
|
if (!loading) {
|
|
@@ -392,13 +446,6 @@ export const App = ({ dangerouslyAcceptAll = false, logLevel, sessionId, }) => {
|
|
|
392
446
|
addStatic(`\x1b[31mError: ${error}\x1b[0m\n\n`);
|
|
393
447
|
}
|
|
394
448
|
}, [error, addStatic]);
|
|
395
|
-
useEffect(() => {
|
|
396
|
-
if (!didPrintIntroRef.current || !logFilePath || printedLogPathRef.current === logFilePath) {
|
|
397
|
-
return;
|
|
398
|
-
}
|
|
399
|
-
printedLogPathRef.current = logFilePath;
|
|
400
|
-
addStatic(`Debug logs: ${logFilePath}\n\n`);
|
|
401
|
-
}, [logFilePath, addStatic]);
|
|
402
449
|
useEffect(() => {
|
|
403
450
|
for (const threadError of threadErrors) {
|
|
404
451
|
if (threadError.transient || printedThreadErrorIdsRef.current.has(threadError.id)) {
|
|
@@ -415,15 +462,14 @@ export const App = ({ dangerouslyAcceptAll = false, logLevel, sessionId, }) => {
|
|
|
415
462
|
const level = LogLevel[logLevel.toUpperCase()];
|
|
416
463
|
if (level !== undefined) {
|
|
417
464
|
setLogLevel(level);
|
|
418
|
-
|
|
419
|
-
setLogFilePath(logPath);
|
|
465
|
+
initLogFile();
|
|
420
466
|
logger.info(`ProtoAgent started with log level: ${logLevel}`);
|
|
421
|
-
logger.info(`Log file: ${
|
|
467
|
+
logger.info(`Log file: ${logger.getLogFilePath()}`);
|
|
422
468
|
}
|
|
423
469
|
}
|
|
424
470
|
// Set global approval mode
|
|
425
|
-
if (
|
|
426
|
-
|
|
471
|
+
if (dangerouslySkipPermissions) {
|
|
472
|
+
setDangerouslySkipPermissions(true);
|
|
427
473
|
}
|
|
428
474
|
// Register interactive approval handler
|
|
429
475
|
setApprovalHandler(async (req) => {
|
|
@@ -477,23 +523,6 @@ export const App = ({ dangerouslyAcceptAll = false, logLevel, sessionId, }) => {
|
|
|
477
523
|
setError(`Failed to save session before exit: ${err.message}`);
|
|
478
524
|
}
|
|
479
525
|
return true;
|
|
480
|
-
case '/clear':
|
|
481
|
-
// Re-initialize messages with just the system prompt
|
|
482
|
-
initializeMessages().then((msgs) => {
|
|
483
|
-
setCompletionMessages(msgs);
|
|
484
|
-
setHelpMessage(null);
|
|
485
|
-
setLastUsage(null);
|
|
486
|
-
setTotalCost(0);
|
|
487
|
-
setThreadErrors([]);
|
|
488
|
-
if (session) {
|
|
489
|
-
const newSession = createSession(config.model, config.provider);
|
|
490
|
-
clearTodos(session.id);
|
|
491
|
-
clearTodos(newSession.id);
|
|
492
|
-
newSession.completionMessages = msgs;
|
|
493
|
-
setSession(newSession);
|
|
494
|
-
}
|
|
495
|
-
});
|
|
496
|
-
return true;
|
|
497
526
|
case '/expand':
|
|
498
527
|
case '/collapse':
|
|
499
528
|
// expand/collapse removed — transcript lives in scrollback
|
|
@@ -566,14 +595,18 @@ export const App = ({ dangerouslyAcceptAll = false, logLevel, sessionId, }) => {
|
|
|
566
595
|
}
|
|
567
596
|
case 'sub_agent_iteration':
|
|
568
597
|
if (event.subAgentTool) {
|
|
569
|
-
const { tool, status } = event.subAgentTool;
|
|
598
|
+
const { tool, status, args } = event.subAgentTool;
|
|
570
599
|
if (status === 'running') {
|
|
571
|
-
setActiveTool(
|
|
600
|
+
setActiveTool(formatSubAgentActivity(tool, args));
|
|
572
601
|
}
|
|
573
602
|
else {
|
|
574
603
|
setActiveTool(null);
|
|
575
604
|
}
|
|
576
605
|
}
|
|
606
|
+
// Handle sub-agent usage update
|
|
607
|
+
if (event.subAgentUsage) {
|
|
608
|
+
setTotalCost((prev) => prev + event.subAgentUsage.cost);
|
|
609
|
+
}
|
|
577
610
|
break;
|
|
578
611
|
case 'tool_call':
|
|
579
612
|
if (event.toolCall) {
|
|
@@ -770,7 +803,7 @@ export const App = ({ dangerouslyAcceptAll = false, logLevel, sessionId, }) => {
|
|
|
770
803
|
initializeWithConfig(newConfig).catch((err) => {
|
|
771
804
|
setError(`Initialization failed: ${err.message}`);
|
|
772
805
|
});
|
|
773
|
-
} })), isStreaming && (_jsxs(Text, { wrap: "wrap", children: [clipToRows(streamingText, terminalRows), _jsx(Text, { dimColor: true, children: "\u258D" })] })), threadErrors.filter((threadError) => threadError.transient).map((threadError) => (_jsx(LeftBar, { color: "
|
|
806
|
+
} })), isStreaming && (_jsxs(Text, { wrap: "wrap", children: [clipToRows(streamingText, terminalRows), _jsx(Text, { dimColor: true, children: "\u258D" })] })), threadErrors.filter((threadError) => threadError.transient).map((threadError) => (_jsx(LeftBar, { color: "gray", marginBottom: 1, children: _jsx(Text, { color: "gray", children: threadError.message }) }, `thread-error-${threadError.id}`))), pendingApproval && (_jsx(ApprovalPrompt, { request: pendingApproval.request, onRespond: (response) => {
|
|
774
807
|
pendingApproval.resolve(response);
|
|
775
808
|
setPendingApproval(null);
|
|
776
809
|
} })), initialized && !pendingApproval && loading && !isStreaming && (_jsx(Box, { children: _jsxs(Text, { color: "green", bold: true, children: [SPINNER_FRAMES[spinnerFrame], ' ', activeTool ? `Running ${activeTool}...` : 'Working...'] }) })), initialized && !pendingApproval && inputText.startsWith('/') && (_jsx(CommandFilter, { inputText: inputText })), _jsx(UsageDisplay, { usage: lastUsage ?? null, totalCost: totalCost }), initialized && !pendingApproval && (_jsx(Box, { children: _jsxs(Box, { flexDirection: "row", children: [_jsx(Box, { width: 2, flexShrink: 0, children: _jsx(Text, { color: "green", bold: true, children: '>' }) }), _jsx(Box, { flexGrow: 1, minWidth: 10, children: _jsx(TextInput, { defaultValue: inputText, onChange: setInputText, placeholder: "Type your message... (/help for commands)", onSubmit: handleSubmit }, inputResetKey) })] }) })), quittingSession && (_jsxs(Box, { flexDirection: "column", marginTop: 1, paddingX: 1, marginBottom: 1, children: [_jsx(Text, { dimColor: true, children: "Session saved. Resume with:" }), _jsxs(Text, { color: "green", children: ["protoagent --session ", quittingSession.id] })] }))] }));
|