@zhive/cli 0.6.3 → 0.6.5

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 (103) hide show
  1. package/dist/CLAUDE.md +7 -0
  2. package/dist/backtest/CLAUDE.md +7 -0
  3. package/dist/cli.js +20 -0
  4. package/dist/commands/agent/commands/profile.js +3 -2
  5. package/dist/commands/agent/commands/profile.test.js +10 -12
  6. package/dist/commands/doctor/commands/index.js +93 -0
  7. package/dist/commands/megathread/commands/create-comment.js +4 -9
  8. package/dist/commands/megathread/commands/create-comment.test.js +15 -173
  9. package/dist/commands/megathread/commands/create-comments.js +83 -0
  10. package/dist/commands/megathread/commands/index.js +2 -0
  11. package/dist/commands/megathread/commands/list.js +5 -5
  12. package/dist/commands/megathread/commands/list.test.js +14 -14
  13. package/dist/commands/start/commands/prediction.js +3 -4
  14. package/dist/commands/start/hooks/useChat.js +40 -41
  15. package/dist/commands/start/services/command-registry.js +1 -1
  16. package/dist/index.js +2 -0
  17. package/dist/{agent → services/agent}/analysis.js +5 -5
  18. package/dist/{load-agent-env.js → services/agent/env.js} +1 -1
  19. package/dist/{agent → services/agent/helpers}/model.js +2 -2
  20. package/dist/{agent → services/agent/prompts}/memory-prompt.js +20 -22
  21. package/dist/{agent → services/agent/prompts}/prompt.js +80 -54
  22. package/dist/{agent → services/agent}/tools/market/client.js +1 -1
  23. package/dist/{agent → services/agent}/tools/mindshare/client.js +1 -1
  24. package/dist/{agents.js → services/config/agent.js} +2 -2
  25. package/dist/{config.js → services/config/config.js} +1 -7
  26. package/dist/services/config/constant.js +8 -0
  27. package/dist/shared/agent/config.js +75 -0
  28. package/dist/shared/agent/env.js +30 -0
  29. package/dist/shared/agent/helpers/model.js +92 -0
  30. package/dist/shared/ai-providers.js +66 -0
  31. package/dist/shared/config/agent.js +0 -11
  32. package/dist/shared/config/agent.test.js +4 -35
  33. package/package.json +2 -2
  34. package/dist/agent/app.js +0 -122
  35. package/dist/agent/commands/registry.js +0 -12
  36. package/dist/agent/components/AsciiTicker.js +0 -81
  37. package/dist/agent/components/CommandInput.js +0 -65
  38. package/dist/agent/components/HoneycombBoot.js +0 -291
  39. package/dist/agent/components/Spinner.js +0 -37
  40. package/dist/agent/hooks/useAgent.js +0 -480
  41. package/dist/agent/objects.js +0 -1
  42. package/dist/agent/process-lifecycle.js +0 -18
  43. package/dist/agent/run-headless.js +0 -189
  44. package/dist/agent/theme.js +0 -41
  45. package/dist/avatar.js +0 -34
  46. package/dist/backtest/default-backtest-data.js +0 -200
  47. package/dist/backtest/fetch.js +0 -41
  48. package/dist/backtest/import.js +0 -106
  49. package/dist/backtest/index.js +0 -10
  50. package/dist/backtest/results.js +0 -113
  51. package/dist/backtest/runner.js +0 -134
  52. package/dist/backtest/storage.js +0 -11
  53. package/dist/backtest/types.js +0 -1
  54. package/dist/commands/install.js +0 -50
  55. package/dist/commands/start/ui/PollText.js +0 -23
  56. package/dist/commands/start/ui/PredictionsPanel.js +0 -88
  57. package/dist/commands/start/ui/SpinnerContext.js +0 -20
  58. package/dist/components/InputGuard.js +0 -6
  59. package/dist/components/stdout-spinner.js +0 -48
  60. package/dist/create/CreateApp.js +0 -153
  61. package/dist/create/ai-generate.js +0 -147
  62. package/dist/create/generate.js +0 -73
  63. package/dist/create/steps/ApiKeyStep.js +0 -97
  64. package/dist/create/steps/AvatarStep.js +0 -16
  65. package/dist/create/steps/BioStep.js +0 -14
  66. package/dist/create/steps/DoneStep.js +0 -14
  67. package/dist/create/steps/IdentityStep.js +0 -163
  68. package/dist/create/steps/NameStep.js +0 -71
  69. package/dist/create/steps/ScaffoldStep.js +0 -58
  70. package/dist/create/steps/SoulStep.js +0 -58
  71. package/dist/create/steps/StrategyStep.js +0 -58
  72. package/dist/create/validate-api-key.js +0 -47
  73. package/dist/create/welcome.js +0 -304
  74. package/dist/list/ListApp.js +0 -79
  75. package/dist/migrate-templates/MigrateApp.js +0 -131
  76. package/dist/migrate-templates/migrate.js +0 -86
  77. package/dist/presets.js +0 -613
  78. package/dist/start/AgentProcessManager.js +0 -98
  79. package/dist/start/Dashboard.js +0 -92
  80. package/dist/start/SelectAgentApp.js +0 -81
  81. package/dist/start/StartApp.js +0 -189
  82. package/dist/start/patch-headless.js +0 -101
  83. package/dist/start/patch-managed-mode.js +0 -142
  84. package/dist/start/start-command.js +0 -24
  85. package/dist/theme.js +0 -54
  86. /package/dist/{agent → services/agent}/config.js +0 -0
  87. /package/dist/{agent → services/agent}/helpers.js +0 -0
  88. /package/dist/{agent → services/agent/prompts}/chat-prompt.js +0 -0
  89. /package/dist/{agent → services/agent}/skills/index.js +0 -0
  90. /package/dist/{agent → services/agent}/skills/skill-parser.js +0 -0
  91. /package/dist/{agent → services/agent}/skills/types.js +0 -0
  92. /package/dist/{agent → services/agent/tools}/edit-section.js +0 -0
  93. /package/dist/{agent → services/agent/tools}/fetch-rules.js +0 -0
  94. /package/dist/{agent → services/agent}/tools/index.js +0 -0
  95. /package/dist/{agent → services/agent}/tools/market/index.js +0 -0
  96. /package/dist/{agent → services/agent}/tools/market/tools.js +0 -0
  97. /package/dist/{agent → services/agent}/tools/mindshare/index.js +0 -0
  98. /package/dist/{agent → services/agent}/tools/mindshare/tools.js +0 -0
  99. /package/dist/{agent → services/agent}/tools/read-skill-tool.js +0 -0
  100. /package/dist/{agent → services/agent}/tools/ta/index.js +0 -0
  101. /package/dist/{agent → services/agent}/tools/ta/indicators.js +0 -0
  102. /package/dist/{agent → services/agent}/types.js +0 -0
  103. /package/dist/{ai-providers.js → services/ai-providers.js} +0 -0
@@ -1,480 +0,0 @@
1
- import { HiveAgent, loadMemory } from '@hive-org/sdk';
2
- import { ToolLoopAgent } from 'ai';
3
- import { useCallback, useEffect, useRef, useState } from 'react';
4
- import { HIVE_FRONTEND_URL } from '../../config.js';
5
- import { buildTextReport, fetchBacktestThreads, loadDefaultBacktest, runBacktest, } from '../../backtest/index.js';
6
- import { extractAndSaveMemory, processMegathreadRound, processSignalAndSummarize, } from '../analysis.js';
7
- import { buildChatPrompt } from '../chat-prompt.js';
8
- import { SLASH_COMMANDS } from '../commands/registry.js';
9
- import { loadAgentConfig } from '../config.js';
10
- import { editSectionTool } from '../edit-section.js';
11
- import { fetchRulesTool } from '../fetch-rules.js';
12
- import { getModel, resolveModelInfo } from '../model.js';
13
- import { getAllTools, getReadSkillTool, getSkillMetadataList, initializeSkills, } from '../tools/index.js';
14
- import { getMarketClient } from '../tools/market/index.js';
15
- export function useAgent() {
16
- const [connected, setConnected] = useState(false);
17
- const [agentName, setAgentName] = useState('agent');
18
- const [agentBio, setAgentBio] = useState('');
19
- const [modelInfo, setModelInfo] = useState(null);
20
- const [pollActivity, setPollActivity] = useState([]);
21
- const [chatActivity, setChatActivity] = useState([]);
22
- const [input, setInput] = useState('');
23
- const [chatStreaming, setChatStreaming] = useState(false);
24
- const [chatBuffer, setChatBuffer] = useState('');
25
- const [predictionCount, setPredictionCount] = useState(0);
26
- const [termWidth, setTermWidth] = useState(process.stdout.columns || 60);
27
- const agentRef = useRef(null);
28
- const sessionMessagesRef = useRef([]);
29
- const memoryRef = useRef('');
30
- const chatCountSinceExtractRef = useRef(0);
31
- const extractingRef = useRef(false);
32
- const recentThreadsRef = useRef([]);
33
- const recentPredictionsRef = useRef([]);
34
- const predictionCountRef = useRef(0);
35
- const soulContentRef = useRef('');
36
- const strategyContentRef = useRef('');
37
- const skillToolsRef = useRef({});
38
- const skillMetadataRef = useRef('');
39
- // ─── Terminal resize tracking ───────────────────────
40
- useEffect(() => {
41
- const onResize = () => {
42
- setTermWidth(process.stdout.columns || 60);
43
- };
44
- process.stdout.on('resize', onResize);
45
- return () => {
46
- process.stdout.off('resize', onResize);
47
- };
48
- }, []);
49
- // ─── Activity helpers ───────────────────────────────
50
- const addPollActivity = useCallback((item) => {
51
- setPollActivity((prev) => {
52
- const updated = [...prev, { ...item, timestamp: new Date() }];
53
- const maxItems = 50;
54
- if (updated.length > maxItems) {
55
- return updated.slice(updated.length - maxItems);
56
- }
57
- return updated;
58
- });
59
- }, []);
60
- const addIdleActivity = useCallback(() => {
61
- setPollActivity((prev) => {
62
- const updated = [
63
- ...prev,
64
- { type: 'idle', text: 'Polled but no new threads', timestamp: new Date() },
65
- ];
66
- const maxItems = 50;
67
- if (updated.length > maxItems) {
68
- return updated.slice(updated.length - maxItems);
69
- }
70
- return updated;
71
- });
72
- }, []);
73
- const updatePollActivity = useCallback((id, updates) => {
74
- setPollActivity((prev) => {
75
- let idx = -1;
76
- for (let i = prev.length - 1; i >= 0; i--) {
77
- if (prev[i].id === id) {
78
- idx = i;
79
- break;
80
- }
81
- }
82
- if (idx === -1)
83
- return prev;
84
- const updated = [...prev];
85
- updated[idx] = { ...updated[idx], ...updates };
86
- return updated;
87
- });
88
- }, []);
89
- const addChatActivity = useCallback((item) => {
90
- setChatActivity((prev) => {
91
- const updated = [...prev, { ...item, timestamp: new Date() }];
92
- const maxItems = 50;
93
- if (updated.length > maxItems) {
94
- return updated.slice(updated.length - maxItems);
95
- }
96
- return updated;
97
- });
98
- }, []);
99
- // ─── Agent lifecycle ────────────────────────────────
100
- useEffect(() => {
101
- const start = async () => {
102
- const { HIVE_API_URL } = await import('../../config.js');
103
- const baseUrl = HIVE_API_URL;
104
- const config = await loadAgentConfig();
105
- setAgentName(config.name);
106
- setAgentBio(config.bio ?? '');
107
- soulContentRef.current = config.soulContent;
108
- strategyContentRef.current = config.strategyContent;
109
- const resolvedModelInfo = resolveModelInfo();
110
- setModelInfo(resolvedModelInfo);
111
- const skillRegistry = await initializeSkills(process.cwd());
112
- const allTools = getAllTools();
113
- const readSkillTool = getReadSkillTool(skillRegistry);
114
- skillToolsRef.current = { ...allTools, readSkill: readSkillTool };
115
- skillMetadataRef.current = getSkillMetadataList(skillRegistry);
116
- const initialMemory = await loadMemory();
117
- memoryRef.current = initialMemory;
118
- const agent = new HiveAgent(baseUrl, {
119
- name: config.name,
120
- avatarUrl: config.avatarUrl,
121
- bio: config.bio ?? undefined,
122
- agentProfile: config.agentProfile,
123
- pollIntervalMs: 30_000,
124
- pollLimit: 5,
125
- onPollEmpty: addIdleActivity,
126
- onStop: async () => { },
127
- onNewThread: async (thread) => {
128
- const threadPreview = thread.text.length > 80 ? thread.text.slice(0, 80) + '\u2026' : thread.text;
129
- const projectTag = `c/${thread.project_id}`;
130
- addPollActivity({
131
- type: 'signal',
132
- id: thread.id,
133
- text: projectTag,
134
- detail: threadPreview,
135
- status: 'analyzing',
136
- });
137
- const summary = `[${thread.project_id}] ${threadPreview}`;
138
- recentThreadsRef.current = [summary, ...recentThreadsRef.current].slice(0, 5);
139
- try {
140
- const result = await processSignalAndSummarize(thread, agent.recentComments, memoryRef.current, soulContentRef.current, strategyContentRef.current, skillToolsRef.current, skillMetadataRef.current);
141
- if (result.skip) {
142
- updatePollActivity(thread.id, {
143
- status: 'skipped',
144
- tokenUsage: result.usage,
145
- });
146
- return;
147
- }
148
- await agent.postComment(thread.id, {
149
- thread_id: thread.id,
150
- text: result.summary,
151
- conviction: result.conviction,
152
- }, thread.text);
153
- const sign = result.conviction >= 0 ? '+' : '';
154
- const threadUrl = `${HIVE_FRONTEND_URL}/c/${thread.project_id}/${thread.id}`;
155
- updatePollActivity(thread.id, {
156
- status: 'posted',
157
- conviction: result.conviction,
158
- result: `[${sign}${result.conviction.toFixed(2)}%] "${result.summary}"`,
159
- url: threadUrl,
160
- tokenUsage: result.usage,
161
- });
162
- predictionCountRef.current += 1;
163
- setPredictionCount(predictionCountRef.current);
164
- const predSummary = `[${sign}${result.conviction.toFixed(2)}%] ${result.summary}`;
165
- recentPredictionsRef.current = [predSummary, ...recentPredictionsRef.current].slice(0, 5);
166
- }
167
- catch (err) {
168
- const raw = err instanceof Error ? err.message : String(err);
169
- const message = raw.length > 120 ? raw.slice(0, 120) + '\u2026' : raw;
170
- updatePollActivity(thread.id, { status: 'error', result: message });
171
- }
172
- },
173
- onNewMegathreadRound: async (round) => {
174
- const hours = Math.round(round.durationMs / 3_600_000);
175
- const timeframe = hours >= 1 ? `${hours}h` : `${Math.round(round.durationMs / 60_000)}m`;
176
- const projectTag = `c/${round.projectId}`;
177
- addPollActivity({
178
- type: 'megathread',
179
- id: round.roundId,
180
- text: `${projectTag} \u00B7 ${timeframe} round`,
181
- detail: round.roundId.split('@')[0],
182
- status: 'analyzing',
183
- });
184
- let priceAtStart;
185
- let currentPrice;
186
- try {
187
- const client = getMarketClient();
188
- const roundStartTimestamp = round.roundId.split('@Z')[0];
189
- const [startResponse, nowResponse] = await Promise.all([
190
- client.getPrice(round.projectId, roundStartTimestamp),
191
- client.getPrice(round.projectId, new Date().toISOString()),
192
- ]);
193
- if (startResponse.price !== null) {
194
- priceAtStart = startResponse.price;
195
- }
196
- if (nowResponse.price !== null) {
197
- currentPrice = nowResponse.price;
198
- }
199
- }
200
- catch {
201
- // Price fetch failed — both stay undefined, prompt falls back to current behavior
202
- }
203
- try {
204
- const result = await processMegathreadRound(round.projectId, round.durationMs, agent.recentComments, memoryRef.current, soulContentRef.current, strategyContentRef.current, skillToolsRef.current, skillMetadataRef.current, priceAtStart, currentPrice);
205
- if (result.skip) {
206
- updatePollActivity(round.roundId, {
207
- status: 'skipped',
208
- tokenUsage: result.usage,
209
- });
210
- return;
211
- }
212
- await agent.postMegathreadComment(round.roundId, {
213
- text: result.summary,
214
- conviction: result.conviction,
215
- tokenId: round.projectId,
216
- roundDuration: round.durationMs,
217
- });
218
- const sign = result.conviction >= 0 ? '+' : '';
219
- const megathreadUrl = `${HIVE_FRONTEND_URL}/c/${round.projectId}/megathread/${timeframe}`;
220
- updatePollActivity(round.roundId, {
221
- status: 'posted',
222
- conviction: result.conviction,
223
- result: `[${sign}${result.conviction.toFixed(2)}%] "${result.summary}"`,
224
- url: megathreadUrl,
225
- tokenUsage: result.usage,
226
- });
227
- predictionCountRef.current += 1;
228
- setPredictionCount(predictionCountRef.current);
229
- const predSummary = `[${sign}${result.conviction.toFixed(2)}%] ${result.summary}`;
230
- recentPredictionsRef.current = [predSummary, ...recentPredictionsRef.current].slice(0, 5);
231
- }
232
- catch (err) {
233
- const raw = err instanceof Error ? err.message : String(err);
234
- const message = raw.length > 120 ? raw.slice(0, 120) + '\u2026' : raw;
235
- updatePollActivity(round.roundId, { status: 'error', result: message });
236
- }
237
- },
238
- });
239
- agentRef.current = agent;
240
- await agent.start();
241
- setConnected(true);
242
- const bio = config.bio ?? '';
243
- if (bio) {
244
- addPollActivity({
245
- type: 'online',
246
- text: `${config.name} agent online \u2014 "${bio}"`,
247
- });
248
- }
249
- };
250
- start().catch((err) => {
251
- const raw = err instanceof Error ? err.message : String(err);
252
- const isNameTaken = raw.includes('409');
253
- const hint = isNameTaken ? ' Change the name in SOUL.md under "# Agent: <name>".' : '';
254
- addPollActivity({ type: 'error', text: `Fatal: ${raw.slice(0, 120)}${hint}` });
255
- });
256
- return () => {
257
- agentRef.current?.stop().catch(() => { });
258
- };
259
- }, []);
260
- // ─── Chat submission ────────────────────────────────
261
- const handleChatSubmit = useCallback(async (message) => {
262
- if (!message.trim() || chatStreaming) {
263
- return;
264
- }
265
- // Handle slash commands
266
- if (message.startsWith('/')) {
267
- const trimmedMessage = message.trim().toLowerCase();
268
- const parts = trimmedMessage.split(/\s+/);
269
- const baseCommand = parts[0];
270
- const commandArg = parts[1];
271
- const commandHandlers = {
272
- '/skills': () => {
273
- const skillsOutput = skillMetadataRef.current || 'No skills loaded.';
274
- addChatActivity({ type: 'chat-agent', text: skillsOutput });
275
- },
276
- '/help': () => {
277
- const helpText = SLASH_COMMANDS.map((cmd) => `${cmd.name} - ${cmd.description}`).join('\n');
278
- addChatActivity({ type: 'chat-agent', text: helpText });
279
- },
280
- '/clear': () => {
281
- setChatActivity([]);
282
- sessionMessagesRef.current = [];
283
- },
284
- '/memory': () => {
285
- const memoryOutput = memoryRef.current || 'No memory stored yet.';
286
- addChatActivity({ type: 'chat-agent', text: memoryOutput });
287
- },
288
- '/backtest': async () => {
289
- const { HIVE_API_URL } = await import('../../config.js');
290
- const numThreads = commandArg ? parseInt(commandArg, 10) : null;
291
- let data;
292
- if (numThreads !== null && !isNaN(numThreads) && numThreads > 0) {
293
- // Fetch from API
294
- addChatActivity({
295
- type: 'chat-agent',
296
- text: `Fetching ${numThreads} resolved threads...`,
297
- });
298
- const fetchResult = await fetchBacktestThreads(numThreads, HIVE_API_URL);
299
- if (fetchResult.success) {
300
- data = fetchResult.data;
301
- }
302
- else {
303
- addChatActivity({
304
- type: 'chat-agent',
305
- text: `API fetch failed (${fetchResult.error}), falling back to default dataset...`,
306
- });
307
- }
308
- }
309
- // Use default dataset
310
- if (!data) {
311
- addChatActivity({
312
- type: 'chat-agent',
313
- text: 'Starting backtest against default dataset...',
314
- });
315
- data = loadDefaultBacktest();
316
- }
317
- try {
318
- const config = {
319
- agentPath: process.cwd(),
320
- soulContent: soulContentRef.current,
321
- strategyContent: strategyContentRef.current,
322
- agentName: agentName,
323
- };
324
- const result = await runBacktest(data, config, {
325
- onThreadStart: (index, total, thread) => {
326
- addChatActivity({
327
- type: 'chat-agent',
328
- text: `Processing ${index + 1}/${total}: ${thread.project_name}...`,
329
- });
330
- },
331
- });
332
- const report = buildTextReport(result);
333
- addChatActivity({ type: 'chat-agent', text: report });
334
- sessionMessagesRef.current.push({ role: 'assistant', content: report });
335
- }
336
- catch (err) {
337
- const errMessage = err instanceof Error ? err.message : String(err);
338
- addChatActivity({ type: 'chat-error', text: `Backtest failed: ${errMessage}` });
339
- }
340
- },
341
- };
342
- const handler = commandHandlers[baseCommand];
343
- if (handler) {
344
- await handler();
345
- return;
346
- }
347
- // Unknown command
348
- addChatActivity({ type: 'chat-error', text: `Unknown command: ${message}` });
349
- return;
350
- }
351
- addChatActivity({ type: 'chat-user', text: message });
352
- sessionMessagesRef.current.push({ role: 'user', content: message });
353
- chatCountSinceExtractRef.current += 1;
354
- if (chatCountSinceExtractRef.current >= 3 && !extractingRef.current) {
355
- extractingRef.current = true;
356
- const messagesSnapshot = [...sessionMessagesRef.current];
357
- extractAndSaveMemory(messagesSnapshot)
358
- .then((newMemory) => {
359
- if (newMemory !== null) {
360
- memoryRef.current = newMemory;
361
- }
362
- chatCountSinceExtractRef.current = 0;
363
- })
364
- .catch(() => { })
365
- .finally(() => {
366
- extractingRef.current = false;
367
- });
368
- }
369
- setChatStreaming(true);
370
- setChatBuffer('');
371
- try {
372
- const { system, prompt } = buildChatPrompt(soulContentRef.current, strategyContentRef.current, {
373
- recentThreadSummaries: recentThreadsRef.current,
374
- recentPredictions: recentPredictionsRef.current,
375
- sessionMessages: sessionMessagesRef.current.slice(-20),
376
- memory: memoryRef.current,
377
- userMessage: message,
378
- });
379
- const model = await getModel();
380
- const cacheableSystem = {
381
- role: 'system',
382
- content: system,
383
- providerOptions: {
384
- anthropic: { cacheControl: { type: 'ephemeral' } },
385
- },
386
- };
387
- const agent = new ToolLoopAgent({
388
- model,
389
- instructions: cacheableSystem,
390
- tools: {
391
- editSection: editSectionTool,
392
- fetchRules: fetchRulesTool,
393
- ...skillToolsRef.current,
394
- },
395
- maxOutputTokens: 4096,
396
- });
397
- const result = await agent.stream({
398
- prompt,
399
- onStepFinish: async ({ toolResults }) => {
400
- for (const toolResult of toolResults) {
401
- if (toolResult.toolName === 'editSection') {
402
- const output = String(toolResult.output);
403
- // Only reload if update was successful
404
- if (output.startsWith('Updated')) {
405
- const config = await loadAgentConfig();
406
- soulContentRef.current = config.soulContent;
407
- strategyContentRef.current = config.strategyContent;
408
- }
409
- }
410
- }
411
- },
412
- });
413
- let fullResponse = '';
414
- let lastFlushTime = 0;
415
- const THROTTLE_MS = 80;
416
- const streamErrors = [];
417
- for await (const part of result.fullStream) {
418
- if (part.type === 'text-delta') {
419
- fullResponse += part.text;
420
- const now = Date.now();
421
- if (now - lastFlushTime >= THROTTLE_MS) {
422
- setChatBuffer(fullResponse);
423
- lastFlushTime = now;
424
- }
425
- }
426
- else if (part.type === 'error') {
427
- const errMsg = typeof part.error === 'string' ? part.error : String(part.error);
428
- streamErrors.push(errMsg);
429
- }
430
- }
431
- // Always flush the final value
432
- setChatBuffer(fullResponse);
433
- // Surface tool results when the model didn't produce follow-up text
434
- const steps = await result.steps;
435
- for (const step of steps) {
436
- for (const toolResult of step.toolResults) {
437
- const output = String(toolResult.output);
438
- if (!fullResponse.includes(output)) {
439
- const suffix = `\n[${output}]`;
440
- fullResponse += suffix;
441
- setChatBuffer(fullResponse);
442
- }
443
- }
444
- }
445
- if (fullResponse.trim().length === 0) {
446
- const errorText = streamErrors.length > 0
447
- ? `Chat error: ${streamErrors.join('; ').slice(0, 120)}`
448
- : 'No response generated. Try again or rephrase.';
449
- addChatActivity({ type: 'chat-error', text: errorText });
450
- setChatBuffer('');
451
- return;
452
- }
453
- sessionMessagesRef.current.push({ role: 'assistant', content: fullResponse });
454
- addChatActivity({ type: 'chat-agent', text: fullResponse });
455
- setChatBuffer('');
456
- }
457
- catch (err) {
458
- const raw = err instanceof Error ? err.message : String(err);
459
- addChatActivity({ type: 'chat-error', text: `Chat error: ${raw.slice(0, 120)}` });
460
- }
461
- finally {
462
- setChatStreaming(false);
463
- }
464
- }, [chatStreaming, addChatActivity]);
465
- return {
466
- connected,
467
- agentName,
468
- agentBio,
469
- modelInfo,
470
- pollActivity,
471
- chatActivity,
472
- input,
473
- chatStreaming,
474
- chatBuffer,
475
- predictionCount,
476
- termWidth,
477
- setInput,
478
- handleChatSubmit,
479
- };
480
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,18 +0,0 @@
1
- import chalk from 'chalk';
2
- import { symbols } from './theme.js';
3
- const exitImmediately = (exitCode = 0) => {
4
- process.exit(exitCode);
5
- };
6
- export function setupProcessLifecycle() {
7
- // Unhandled rejection handler
8
- process.on('unhandledRejection', (reason) => {
9
- const raw = reason instanceof Error ? reason.message : String(reason);
10
- const message = raw.length > 200 ? raw.slice(0, 200) + '\u2026' : raw;
11
- console.error(chalk.red(` ${symbols.cross} Unhandled: ${message}`));
12
- });
13
- // No alternate screen buffer — normal buffer allows terminal scrollback
14
- // so users can scroll up to see historical poll activity.
15
- // <Static> items from Ink flow into the scrollback naturally.
16
- process.on('SIGINT', () => exitImmediately(0));
17
- process.on('SIGTERM', () => exitImmediately(0));
18
- }