@zhive/cli 0.6.3 → 0.6.4
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/CLAUDE.md +7 -0
- package/dist/backtest/CLAUDE.md +7 -0
- package/dist/cli.js +20 -0
- package/dist/commands/agent/commands/profile.js +3 -2
- package/dist/commands/agent/commands/profile.test.js +10 -12
- package/dist/commands/doctor/commands/index.js +93 -0
- package/dist/commands/megathread/commands/create-comment.js +4 -9
- package/dist/commands/megathread/commands/create-comment.test.js +15 -173
- package/dist/commands/megathread/commands/list.js +5 -5
- package/dist/commands/megathread/commands/list.test.js +14 -14
- package/dist/commands/start/commands/prediction.js +3 -4
- package/dist/commands/start/hooks/useChat.js +40 -41
- package/dist/commands/start/services/command-registry.js +1 -1
- package/dist/index.js +2 -0
- package/dist/{agent → services/agent}/analysis.js +5 -5
- package/dist/{load-agent-env.js → services/agent/env.js} +1 -1
- package/dist/{agent → services/agent/helpers}/model.js +2 -2
- package/dist/{agent → services/agent/prompts}/memory-prompt.js +20 -22
- package/dist/{agent → services/agent/prompts}/prompt.js +80 -54
- package/dist/{agent → services/agent}/tools/market/client.js +1 -1
- package/dist/{agent → services/agent}/tools/mindshare/client.js +1 -1
- package/dist/{agents.js → services/config/agent.js} +2 -2
- package/dist/{config.js → services/config/config.js} +1 -7
- package/dist/services/config/constant.js +8 -0
- package/dist/shared/agent/config.js +75 -0
- package/dist/shared/agent/env.js +30 -0
- package/dist/shared/agent/helpers/model.js +92 -0
- package/dist/shared/ai-providers.js +66 -0
- package/dist/shared/config/agent.js +0 -11
- package/dist/shared/config/agent.test.js +4 -35
- package/package.json +2 -2
- package/dist/agent/app.js +0 -122
- package/dist/agent/commands/registry.js +0 -12
- package/dist/agent/components/AsciiTicker.js +0 -81
- package/dist/agent/components/CommandInput.js +0 -65
- package/dist/agent/components/HoneycombBoot.js +0 -291
- package/dist/agent/components/Spinner.js +0 -37
- package/dist/agent/hooks/useAgent.js +0 -480
- package/dist/agent/objects.js +0 -1
- package/dist/agent/process-lifecycle.js +0 -18
- package/dist/agent/run-headless.js +0 -189
- package/dist/agent/theme.js +0 -41
- package/dist/avatar.js +0 -34
- package/dist/backtest/default-backtest-data.js +0 -200
- package/dist/backtest/fetch.js +0 -41
- package/dist/backtest/import.js +0 -106
- package/dist/backtest/index.js +0 -10
- package/dist/backtest/results.js +0 -113
- package/dist/backtest/runner.js +0 -134
- package/dist/backtest/storage.js +0 -11
- package/dist/backtest/types.js +0 -1
- package/dist/commands/install.js +0 -50
- package/dist/commands/start/ui/PollText.js +0 -23
- package/dist/commands/start/ui/PredictionsPanel.js +0 -88
- package/dist/commands/start/ui/SpinnerContext.js +0 -20
- package/dist/components/InputGuard.js +0 -6
- package/dist/components/stdout-spinner.js +0 -48
- package/dist/create/CreateApp.js +0 -153
- package/dist/create/ai-generate.js +0 -147
- package/dist/create/generate.js +0 -73
- package/dist/create/steps/ApiKeyStep.js +0 -97
- package/dist/create/steps/AvatarStep.js +0 -16
- package/dist/create/steps/BioStep.js +0 -14
- package/dist/create/steps/DoneStep.js +0 -14
- package/dist/create/steps/IdentityStep.js +0 -163
- package/dist/create/steps/NameStep.js +0 -71
- package/dist/create/steps/ScaffoldStep.js +0 -58
- package/dist/create/steps/SoulStep.js +0 -58
- package/dist/create/steps/StrategyStep.js +0 -58
- package/dist/create/validate-api-key.js +0 -47
- package/dist/create/welcome.js +0 -304
- package/dist/list/ListApp.js +0 -79
- package/dist/migrate-templates/MigrateApp.js +0 -131
- package/dist/migrate-templates/migrate.js +0 -86
- package/dist/presets.js +0 -613
- package/dist/start/AgentProcessManager.js +0 -98
- package/dist/start/Dashboard.js +0 -92
- package/dist/start/SelectAgentApp.js +0 -81
- package/dist/start/StartApp.js +0 -189
- package/dist/start/patch-headless.js +0 -101
- package/dist/start/patch-managed-mode.js +0 -142
- package/dist/start/start-command.js +0 -24
- package/dist/theme.js +0 -54
- /package/dist/{agent → services/agent}/config.js +0 -0
- /package/dist/{agent → services/agent}/helpers.js +0 -0
- /package/dist/{agent → services/agent/prompts}/chat-prompt.js +0 -0
- /package/dist/{agent → services/agent}/skills/index.js +0 -0
- /package/dist/{agent → services/agent}/skills/skill-parser.js +0 -0
- /package/dist/{agent → services/agent}/skills/types.js +0 -0
- /package/dist/{agent → services/agent/tools}/edit-section.js +0 -0
- /package/dist/{agent → services/agent/tools}/fetch-rules.js +0 -0
- /package/dist/{agent → services/agent}/tools/index.js +0 -0
- /package/dist/{agent → services/agent}/tools/market/index.js +0 -0
- /package/dist/{agent → services/agent}/tools/market/tools.js +0 -0
- /package/dist/{agent → services/agent}/tools/mindshare/index.js +0 -0
- /package/dist/{agent → services/agent}/tools/mindshare/tools.js +0 -0
- /package/dist/{agent → services/agent}/tools/read-skill-tool.js +0 -0
- /package/dist/{agent → services/agent}/tools/ta/index.js +0 -0
- /package/dist/{agent → services/agent}/tools/ta/indicators.js +0 -0
- /package/dist/{agent → services/agent}/types.js +0 -0
- /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
|
-
}
|
package/dist/agent/objects.js
DELETED
|
@@ -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
|
-
}
|