zhitalk 0.0.4 → 0.0.6
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 +2 -2
- package/dist/agent/agent.js +57 -63
- package/dist/agent/cli.js +39 -73
- package/dist/agent/colors.js +6 -44
- package/dist/agent/commands.js +22 -28
- package/dist/agent/config.js +20 -62
- package/dist/agent/context.js +8 -12
- package/dist/agent/db.js +17 -27
- package/dist/agent/hooks.d.ts +1 -1
- package/dist/agent/hooks.js +13 -22
- package/dist/agent/mcp/client.js +25 -29
- package/dist/agent/mcp/index.d.ts +1 -1
- package/dist/agent/mcp/index.js +8 -13
- package/dist/agent/mcp/wrapper.d.ts +2 -2
- package/dist/agent/mcp/wrapper.js +5 -8
- package/dist/agent/model.js +6 -10
- package/dist/agent/permission/exec.js +6 -9
- package/dist/agent/permission/is-dangerous-path.js +13 -19
- package/dist/agent/permission/is-safe-domains.js +1 -4
- package/dist/agent/permission/network.js +3 -6
- package/dist/agent/permission/read.js +3 -6
- package/dist/agent/permission/util.js +16 -26
- package/dist/agent/permission/write.js +5 -8
- package/dist/agent/prompt.js +9 -15
- package/dist/agent/skills.js +19 -24
- package/dist/agent/tools/agent_tool.js +2 -38
- package/dist/agent/tools/exec_tool.js +4 -7
- package/dist/agent/tools/load_skill_tool.js +3 -6
- package/dist/agent/tools/memory_create_tool.js +4 -10
- package/dist/agent/tools/memory_delete_tool.js +4 -10
- package/dist/agent/tools/memory_retrieve_tool.js +3 -6
- package/dist/agent/tools/profile_update_tool.js +11 -14
- package/dist/agent/tools/read_file_tool.js +3 -6
- package/dist/agent/tools/run_js_tool.js +3 -6
- package/dist/agent/tools/run_py_tool.js +4 -7
- package/dist/agent/tools/search.js +1 -4
- package/dist/agent/tools/web_fetch_tool.js +1 -4
- package/dist/agent/tools/web_search_tool.js +5 -8
- package/dist/agent/tools/write_file_tool.js +5 -8
- package/dist/agent/tools.js +76 -81
- package/dist/agent/utils.js +2 -6
- package/dist/index.js +29 -56
- package/dist/install.js +14 -50
- package/jest.config.js +11 -0
- package/package.json +7 -6
- package/pnpm-workspace.yaml +4 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Zhitalk
|
|
1
|
+
# 智语 Zhitalk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[智语 Zhitalk](https://zhitalk.chat/) 是一个 AI Agent 个人助手,像 OpenClaw 小龙虾一样。 包含 tools skills memory hook subagent MCP-server 等 Agent 功能。你可以和它聊天,给它分配任务,让它操作文件...
|
|
4
4
|
|
|
5
5
|
## Usage
|
|
6
6
|
|
package/dist/agent/agent.js
CHANGED
|
@@ -1,41 +1,35 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const read_1 = require("./permission/read");
|
|
17
|
-
const write_1 = require("./permission/write");
|
|
18
|
-
const exec_1 = require("./permission/exec");
|
|
19
|
-
const network_1 = require("./permission/network");
|
|
20
|
-
const hooks_1 = require("./hooks");
|
|
21
|
-
const model_1 = require("./model");
|
|
1
|
+
import { SqliteSaver } from '@langchain/langgraph-checkpoint-sqlite';
|
|
2
|
+
import { SystemMessage, AIMessage, HumanMessage, ToolMessage, } from '@langchain/core/messages';
|
|
3
|
+
import { StateGraph, Annotation, START, END, interrupt, Command, } from '@langchain/langgraph';
|
|
4
|
+
import { messagesStateReducer } from '@langchain/langgraph';
|
|
5
|
+
import { DB_PATH } from './db.js';
|
|
6
|
+
import { tools, maybePersistedOutput, initTools } from './tools.js';
|
|
7
|
+
import { compressMessages } from './context.js';
|
|
8
|
+
import { systemPrompt } from './prompt.js';
|
|
9
|
+
import { formatToolLog } from './colors.js';
|
|
10
|
+
import { checkReadPermission } from './permission/read.js';
|
|
11
|
+
import { checkWritePermission } from './permission/write.js';
|
|
12
|
+
import { checkExecPermission } from './permission/exec.js';
|
|
13
|
+
import { checkNetworkPermission } from './permission/network.js';
|
|
14
|
+
import { runPreToolUseHooks, runPostToolUseHooks } from './hooks.js';
|
|
15
|
+
import { createModel } from './model.js';
|
|
22
16
|
// ── 模型 ──────────────────────────────────────────────────
|
|
23
|
-
const model =
|
|
17
|
+
const model = createModel({ streaming: true });
|
|
24
18
|
// ── State Schema ──────────────────────────────────────────
|
|
25
|
-
const StateAnnotation =
|
|
26
|
-
messages:
|
|
27
|
-
reducer:
|
|
19
|
+
const StateAnnotation = Annotation.Root({
|
|
20
|
+
messages: Annotation({
|
|
21
|
+
reducer: messagesStateReducer,
|
|
28
22
|
default: () => [],
|
|
29
23
|
}),
|
|
30
|
-
contextSummary:
|
|
24
|
+
contextSummary: Annotation({
|
|
31
25
|
reducer: (_prev, next) => next,
|
|
32
26
|
default: () => null,
|
|
33
27
|
}),
|
|
34
|
-
compressionCount:
|
|
28
|
+
compressionCount: Annotation({
|
|
35
29
|
reducer: (_prev, next) => next,
|
|
36
30
|
default: () => 0,
|
|
37
31
|
}),
|
|
38
|
-
lastCompressedIndex:
|
|
32
|
+
lastCompressedIndex: Annotation({
|
|
39
33
|
reducer: (_prev, next) => next,
|
|
40
34
|
default: () => 0,
|
|
41
35
|
}),
|
|
@@ -43,10 +37,10 @@ const StateAnnotation = langgraph_1.Annotation.Root({
|
|
|
43
37
|
// ── Graph Nodes ───────────────────────────────────────────
|
|
44
38
|
function shouldContinue(state) {
|
|
45
39
|
const lastMessage = state.messages[state.messages.length - 1];
|
|
46
|
-
if (
|
|
40
|
+
if (AIMessage.isInstance(lastMessage) && lastMessage.tool_calls?.length) {
|
|
47
41
|
return 'tools';
|
|
48
42
|
}
|
|
49
|
-
return
|
|
43
|
+
return END;
|
|
50
44
|
}
|
|
51
45
|
function simplifyToolMessages(messages) {
|
|
52
46
|
const toolIndices = [];
|
|
@@ -65,7 +59,7 @@ function simplifyToolMessages(messages) {
|
|
|
65
59
|
const toolMsg = msg;
|
|
66
60
|
if (toolMsg.name === 'read_file')
|
|
67
61
|
return msg;
|
|
68
|
-
return new
|
|
62
|
+
return new ToolMessage({
|
|
69
63
|
content: `[Previous: used ${toolMsg.name}]`,
|
|
70
64
|
tool_call_id: toolMsg.tool_call_id,
|
|
71
65
|
name: toolMsg.name,
|
|
@@ -73,7 +67,7 @@ function simplifyToolMessages(messages) {
|
|
|
73
67
|
});
|
|
74
68
|
}
|
|
75
69
|
// ── 记忆 ──────────────────────────────────────────────────
|
|
76
|
-
const checkpointer =
|
|
70
|
+
const checkpointer = SqliteSaver.fromConnString(DB_PATH);
|
|
77
71
|
// ── Agent Graph 工厂 ──────────────────────────────────────
|
|
78
72
|
function createAgentGraph(toolList) {
|
|
79
73
|
const modelWithTheseTools = model.bindTools(toolList);
|
|
@@ -81,7 +75,7 @@ function createAgentGraph(toolList) {
|
|
|
81
75
|
let modelMessages = state.messages ?? [];
|
|
82
76
|
// compact context
|
|
83
77
|
if (state.contextSummary && state.lastCompressedIndex > 0) {
|
|
84
|
-
const summaryMsg = new
|
|
78
|
+
const summaryMsg = new SystemMessage(`历史对话摘要:\n\n${state.contextSummary}`);
|
|
85
79
|
modelMessages = [
|
|
86
80
|
summaryMsg,
|
|
87
81
|
...modelMessages.slice(state.lastCompressedIndex),
|
|
@@ -91,7 +85,7 @@ function createAgentGraph(toolList) {
|
|
|
91
85
|
modelMessages = simplifyToolMessages(modelMessages);
|
|
92
86
|
// keep recent 300 items
|
|
93
87
|
modelMessages = modelMessages.slice(0, 300);
|
|
94
|
-
const messages = [new
|
|
88
|
+
const messages = [new SystemMessage(systemPrompt), ...modelMessages];
|
|
95
89
|
const response = await modelWithTheseTools.invoke(messages, config);
|
|
96
90
|
return { messages: [response] };
|
|
97
91
|
}
|
|
@@ -102,12 +96,12 @@ function createAgentGraph(toolList) {
|
|
|
102
96
|
.map((msg) => msg.tool_call_id));
|
|
103
97
|
let aiMessage;
|
|
104
98
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
105
|
-
if (
|
|
99
|
+
if (AIMessage.isInstance(messages[i])) {
|
|
106
100
|
aiMessage = messages[i];
|
|
107
101
|
break;
|
|
108
102
|
}
|
|
109
103
|
}
|
|
110
|
-
if (!aiMessage || !
|
|
104
|
+
if (!aiMessage || !AIMessage.isInstance(aiMessage)) {
|
|
111
105
|
throw new Error('ToolNode only accepts AIMessages as input.');
|
|
112
106
|
}
|
|
113
107
|
const toolCalls = aiMessage.tool_calls?.filter((call) => call.id == null || !toolMessageIds.has(call.id)) ?? [];
|
|
@@ -122,16 +116,16 @@ function createAgentGraph(toolList) {
|
|
|
122
116
|
const level = tool?.permission_level;
|
|
123
117
|
let decision;
|
|
124
118
|
if (level === 'read') {
|
|
125
|
-
decision =
|
|
119
|
+
decision = checkReadPermission(call);
|
|
126
120
|
}
|
|
127
121
|
else if (level === 'write') {
|
|
128
|
-
decision =
|
|
122
|
+
decision = checkWritePermission(call);
|
|
129
123
|
}
|
|
130
124
|
else if (level === 'exec') {
|
|
131
|
-
decision =
|
|
125
|
+
decision = checkExecPermission(call);
|
|
132
126
|
}
|
|
133
127
|
else if (level === 'network') {
|
|
134
|
-
decision =
|
|
128
|
+
decision = checkNetworkPermission(call);
|
|
135
129
|
}
|
|
136
130
|
else if (level === 'mcp') {
|
|
137
131
|
decision = { action: 'confirm' };
|
|
@@ -143,7 +137,7 @@ function createAgentGraph(toolList) {
|
|
|
143
137
|
allowCalls.push(call);
|
|
144
138
|
}
|
|
145
139
|
else if (decision.action === 'block') {
|
|
146
|
-
blockMessages.push(new
|
|
140
|
+
blockMessages.push(new ToolMessage({
|
|
147
141
|
content: decision.reason,
|
|
148
142
|
tool_call_id: call.id ?? '',
|
|
149
143
|
name: call.name,
|
|
@@ -156,18 +150,18 @@ function createAgentGraph(toolList) {
|
|
|
156
150
|
async function executeCalls(calls) {
|
|
157
151
|
return Promise.all(calls.map(async (call) => {
|
|
158
152
|
const tool = toolList.find((t) => t.name === call.name);
|
|
159
|
-
console.log(
|
|
153
|
+
console.log(formatToolLog(call.name, JSON.stringify(call.args)));
|
|
160
154
|
try {
|
|
161
155
|
const threadId = config?.configurable?.thread_id || '';
|
|
162
156
|
// PreToolUse hook
|
|
163
|
-
const preResult = await
|
|
157
|
+
const preResult = await runPreToolUseHooks({
|
|
164
158
|
toolName: call.name,
|
|
165
159
|
toolArgs: call.args,
|
|
166
160
|
toolCallId: call.id ?? '',
|
|
167
161
|
threadId,
|
|
168
162
|
});
|
|
169
163
|
if (preResult.action === 'block') {
|
|
170
|
-
return new
|
|
164
|
+
return new ToolMessage({
|
|
171
165
|
content: preResult.reason,
|
|
172
166
|
tool_call_id: call.id ?? '',
|
|
173
167
|
name: call.name,
|
|
@@ -178,7 +172,7 @@ function createAgentGraph(toolList) {
|
|
|
178
172
|
const output = await tool.invoke({ ...call, type: 'tool_call' }, config);
|
|
179
173
|
let content = typeof output === 'string' ? output : JSON.stringify(output);
|
|
180
174
|
// PostToolUse hook
|
|
181
|
-
const postResult = await
|
|
175
|
+
const postResult = await runPostToolUseHooks({
|
|
182
176
|
toolName: call.name,
|
|
183
177
|
toolArgs: call.args,
|
|
184
178
|
toolOutput: content,
|
|
@@ -194,15 +188,15 @@ function createAgentGraph(toolList) {
|
|
|
194
188
|
if (preResult.action === 'inject') {
|
|
195
189
|
content = `[Hook injection]\n${preResult.message}\n\n${content}`;
|
|
196
190
|
}
|
|
197
|
-
const finalContent = await
|
|
198
|
-
return new
|
|
191
|
+
const finalContent = await maybePersistedOutput(content, call.id ?? '');
|
|
192
|
+
return new ToolMessage({
|
|
199
193
|
content: finalContent,
|
|
200
194
|
tool_call_id: call.id ?? '',
|
|
201
195
|
name: call.name,
|
|
202
196
|
});
|
|
203
197
|
}
|
|
204
198
|
catch (e) {
|
|
205
|
-
return new
|
|
199
|
+
return new ToolMessage({
|
|
206
200
|
content: `Error: ${e.message}\n Please fix your mistakes.`,
|
|
207
201
|
tool_call_id: call.id ?? '',
|
|
208
202
|
name: call.name,
|
|
@@ -214,9 +208,9 @@ function createAgentGraph(toolList) {
|
|
|
214
208
|
if (confirmCalls.length === 0) {
|
|
215
209
|
return { messages: [...allowOutputs, ...blockMessages] };
|
|
216
210
|
}
|
|
217
|
-
const result =
|
|
211
|
+
const result = interrupt({ toolCalls: confirmCalls });
|
|
218
212
|
if (result !== 'approved') {
|
|
219
|
-
const deniedMessages = confirmCalls.map((call) => new
|
|
213
|
+
const deniedMessages = confirmCalls.map((call) => new ToolMessage({
|
|
220
214
|
content: 'Tool execution was denied by the user.',
|
|
221
215
|
tool_call_id: call.id ?? '',
|
|
222
216
|
name: call.name,
|
|
@@ -228,13 +222,13 @@ function createAgentGraph(toolList) {
|
|
|
228
222
|
const confirmOutputs = await executeCalls(confirmCalls);
|
|
229
223
|
return { messages: [...allowOutputs, ...blockMessages, ...confirmOutputs] };
|
|
230
224
|
}
|
|
231
|
-
const workflow = new
|
|
225
|
+
const workflow = new StateGraph(StateAnnotation)
|
|
232
226
|
.addNode('model_request', modelRequest)
|
|
233
227
|
.addNode('tools', toolNode)
|
|
234
|
-
.addEdge(
|
|
228
|
+
.addEdge(START, 'model_request')
|
|
235
229
|
.addConditionalEdges('model_request', shouldContinue, {
|
|
236
230
|
tools: 'tools',
|
|
237
|
-
[
|
|
231
|
+
[END]: END,
|
|
238
232
|
})
|
|
239
233
|
.addEdge('tools', 'model_request');
|
|
240
234
|
return workflow.compile({
|
|
@@ -244,10 +238,10 @@ function createAgentGraph(toolList) {
|
|
|
244
238
|
// ── Agent 创建 ────────────────────────────────────────────
|
|
245
239
|
let agent = null;
|
|
246
240
|
let subAgent = null;
|
|
247
|
-
async function initAgent() {
|
|
248
|
-
await
|
|
249
|
-
agent = createAgentGraph(
|
|
250
|
-
subAgent = createAgentGraph(
|
|
241
|
+
export async function initAgent() {
|
|
242
|
+
await initTools();
|
|
243
|
+
agent = createAgentGraph(tools);
|
|
244
|
+
subAgent = createAgentGraph(tools.filter((t) => t.name !== 'agent_tool'));
|
|
251
245
|
}
|
|
252
246
|
function getAgent() {
|
|
253
247
|
if (!agent)
|
|
@@ -264,7 +258,7 @@ async function _runAgent(compiledAgent, userMessage, onToken, onToolConfirmation
|
|
|
264
258
|
const config = { configurable: { thread_id: threadId } };
|
|
265
259
|
let fullResponse = '';
|
|
266
260
|
let usageMetadata;
|
|
267
|
-
let input = { messages: [new
|
|
261
|
+
let input = { messages: [new HumanMessage(userMessage)] };
|
|
268
262
|
while (true) {
|
|
269
263
|
const stream = await compiledAgent.stream(input, {
|
|
270
264
|
...config,
|
|
@@ -296,7 +290,7 @@ async function _runAgent(compiledAgent, userMessage, onToken, onToolConfirmation
|
|
|
296
290
|
if (!interruptedTask)
|
|
297
291
|
break;
|
|
298
292
|
const confirmed = await onToolConfirmation(interruptedTask.interrupts[0].value.toolCalls);
|
|
299
|
-
input = new
|
|
293
|
+
input = new Command({ resume: confirmed ? 'approved' : 'denied' });
|
|
300
294
|
}
|
|
301
295
|
return { response: fullResponse, usageMetadata };
|
|
302
296
|
}
|
|
@@ -308,7 +302,7 @@ async function _runAgent(compiledAgent, userMessage, onToken, onToolConfirmation
|
|
|
308
302
|
* @param {string} threadId - 会话 ID,相同 ID 自动续上历史记录
|
|
309
303
|
* @returns {Promise<{ response: string; usageMetadata?: UsageMetadata }>} 完整的 AI 回复文本及 token 使用信息
|
|
310
304
|
*/
|
|
311
|
-
async function runAgentStream(userMessage, onToken, onToolConfirmation, threadId = 'default-session', signal) {
|
|
305
|
+
export async function runAgentStream(userMessage, onToken, onToolConfirmation, threadId = 'default-session', signal) {
|
|
312
306
|
return _runAgent(getAgent(), userMessage, onToken, onToolConfirmation, threadId, signal);
|
|
313
307
|
}
|
|
314
308
|
/**
|
|
@@ -316,14 +310,14 @@ async function runAgentStream(userMessage, onToken, onToolConfirmation, threadId
|
|
|
316
310
|
* @param {string} prompt - 给 subagent 的任务提示
|
|
317
311
|
* @returns {Promise<string>} subagent 的最终回复
|
|
318
312
|
*/
|
|
319
|
-
async function runSubAgent(prompt) {
|
|
313
|
+
export async function runSubAgent(prompt) {
|
|
320
314
|
const threadId = `subagent-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
321
315
|
const result = await _runAgent(getSubAgent(), prompt.trim(), () => { }, // 不需要流式输出
|
|
322
316
|
async () => true, // subagent 自动确认 tools
|
|
323
317
|
threadId, undefined);
|
|
324
318
|
return result.response;
|
|
325
319
|
}
|
|
326
|
-
async function compressContext(threadId) {
|
|
320
|
+
export async function compressContext(threadId) {
|
|
327
321
|
const config = { configurable: { thread_id: threadId } };
|
|
328
322
|
const currentState = await getAgent().getState(config);
|
|
329
323
|
const messages = currentState.values.messages || [];
|
|
@@ -335,7 +329,7 @@ async function compressContext(threadId) {
|
|
|
335
329
|
return { didCompress: false, count };
|
|
336
330
|
}
|
|
337
331
|
const toCompress = messages.slice(lastIndex, messages.length - recentKeep);
|
|
338
|
-
const newSummary = await
|
|
332
|
+
const newSummary = await compressMessages(toCompress, existingSummary);
|
|
339
333
|
await getAgent().updateState(config, {
|
|
340
334
|
contextSummary: newSummary,
|
|
341
335
|
lastCompressedIndex: messages.length - recentKeep,
|
package/dist/agent/cli.js
CHANGED
|
@@ -1,48 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.interactiveChat = interactiveChat;
|
|
37
|
-
const readline = __importStar(require("readline"));
|
|
38
|
-
const fs_1 = require("fs");
|
|
39
|
-
const path_1 = require("path");
|
|
40
|
-
const agent_1 = require("./agent");
|
|
41
|
-
const context_1 = require("./context");
|
|
42
|
-
const colors_1 = require("./colors");
|
|
43
|
-
const commands_1 = require("./commands");
|
|
44
|
-
const hooks_1 = require("./hooks");
|
|
45
|
-
const pkg = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../../package.json'), 'utf-8'));
|
|
1
|
+
import * as readline from 'readline';
|
|
2
|
+
import { readFileSync } from 'fs';
|
|
3
|
+
import { join, dirname } from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { runAgentStream, compressContext } from './agent.js';
|
|
6
|
+
import { getModelContextLimit } from './context.js';
|
|
7
|
+
import { color, formatToolLog } from './colors.js';
|
|
8
|
+
import { threadId, commands } from './commands.js';
|
|
9
|
+
import { runSessionStartHooks } from './hooks.js';
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, '../../package.json'), 'utf-8'));
|
|
46
12
|
function createInterface() {
|
|
47
13
|
return readline.createInterface({
|
|
48
14
|
input: process.stdin,
|
|
@@ -50,14 +16,14 @@ function createInterface() {
|
|
|
50
16
|
});
|
|
51
17
|
}
|
|
52
18
|
async function printBanner() {
|
|
53
|
-
const figlet = (await
|
|
54
|
-
const { default: boxen } = await
|
|
55
|
-
console.log(
|
|
19
|
+
const figlet = (await import('figlet')).default;
|
|
20
|
+
const { default: boxen } = await import('boxen');
|
|
21
|
+
console.log(color.banner(figlet.textSync(pkg.name, { font: 'Slant' })));
|
|
56
22
|
const info = [
|
|
57
|
-
`${
|
|
58
|
-
`${
|
|
59
|
-
`${
|
|
60
|
-
`${
|
|
23
|
+
`${color.gray('Description')}: ${pkg.description}`,
|
|
24
|
+
`${color.gray('Version')}: ${pkg.version}`,
|
|
25
|
+
`${color.gray('Author')}: ${pkg.author}`,
|
|
26
|
+
`${color.gray('Docs')}: ${pkg.docs}`,
|
|
61
27
|
].join('\n');
|
|
62
28
|
console.log(boxen(info, {
|
|
63
29
|
padding: 1,
|
|
@@ -67,7 +33,7 @@ async function printBanner() {
|
|
|
67
33
|
console.log('Usage:');
|
|
68
34
|
console.log(' ESC - Cancel AI request');
|
|
69
35
|
console.log(' exit - Exit the chat');
|
|
70
|
-
for (const [name, cmd] of
|
|
36
|
+
for (const [name, cmd] of commands) {
|
|
71
37
|
console.log(` /${name.padEnd(8)} - ${cmd.description}`);
|
|
72
38
|
}
|
|
73
39
|
console.log();
|
|
@@ -83,12 +49,12 @@ function prompt(question) {
|
|
|
83
49
|
}
|
|
84
50
|
async function chat(userInput) {
|
|
85
51
|
const rl = createInterface();
|
|
86
|
-
process.stdout.write('\n' +
|
|
52
|
+
process.stdout.write('\n' + color.aiPrefix());
|
|
87
53
|
const controller = new AbortController();
|
|
88
54
|
// 监听 ESC 键,中断 AI 请求
|
|
89
55
|
const escListener = (_str, key) => {
|
|
90
56
|
if (key.name === 'escape' || key.name === 'esc') {
|
|
91
|
-
process.stdout.write('\n\n' +
|
|
57
|
+
process.stdout.write('\n\n' + color.cancelled('[Cancelled]') + '\n');
|
|
92
58
|
controller.abort();
|
|
93
59
|
rl.close();
|
|
94
60
|
}
|
|
@@ -97,18 +63,18 @@ async function chat(userInput) {
|
|
|
97
63
|
process.stdin.on('keypress', escListener);
|
|
98
64
|
let usageMetadata;
|
|
99
65
|
try {
|
|
100
|
-
const result = await
|
|
66
|
+
const result = await runAgentStream(userInput, (token) => {
|
|
101
67
|
process.stdout.write(token);
|
|
102
68
|
}, async (toolCalls) => {
|
|
103
69
|
for (const call of toolCalls) {
|
|
104
|
-
console.log(
|
|
70
|
+
console.log(formatToolLog(call.name, JSON.stringify(call.args)));
|
|
105
71
|
}
|
|
106
72
|
const answer = await new Promise((resolve) => {
|
|
107
73
|
rl.question('确认执行以上工具? (y/n): ', resolve);
|
|
108
74
|
});
|
|
109
75
|
return (answer.trim().toLowerCase() === 'y' ||
|
|
110
76
|
answer.trim().toLowerCase() === 'yes');
|
|
111
|
-
},
|
|
77
|
+
}, threadId, controller.signal);
|
|
112
78
|
usageMetadata = result.usageMetadata;
|
|
113
79
|
}
|
|
114
80
|
catch (err) {
|
|
@@ -121,23 +87,23 @@ async function chat(userInput) {
|
|
|
121
87
|
rl.close();
|
|
122
88
|
}
|
|
123
89
|
if (usageMetadata) {
|
|
124
|
-
const limit =
|
|
90
|
+
const limit = getModelContextLimit();
|
|
125
91
|
const percentage = (usageMetadata.total_tokens / limit) * 100;
|
|
126
92
|
const percentageStr = percentage.toFixed(1);
|
|
127
93
|
const tokenText = `Tokens: ${usageMetadata.total_tokens.toLocaleString()} / ${limit.toLocaleString()} (${percentageStr}%)`;
|
|
128
94
|
if (percentage >= 80) {
|
|
129
95
|
process.stdout.write('\n' +
|
|
130
|
-
|
|
96
|
+
color.error(tokenText) +
|
|
131
97
|
'\n' +
|
|
132
|
-
|
|
98
|
+
color.error('警告:Context window 接近大模型接口上限,即将压缩 Context,可能会丢失信息') +
|
|
133
99
|
'\n' +
|
|
134
|
-
|
|
100
|
+
color.error('建议输入 /new 命令开启新会话'));
|
|
135
101
|
try {
|
|
136
|
-
const result = await
|
|
102
|
+
const result = await compressContext(threadId);
|
|
137
103
|
if (result.didCompress) {
|
|
138
|
-
process.stdout.write('\n' +
|
|
104
|
+
process.stdout.write('\n' + color.error(`Context 已压缩(第 ${result.count} 次),已保留最近 6 条消息`) + '\n');
|
|
139
105
|
if (result.count >= 3) {
|
|
140
|
-
process.stdout.write(
|
|
106
|
+
process.stdout.write(color.error('强烈建议输入 /new 命令开启新会话,以避免信息丢失') + '\n');
|
|
141
107
|
}
|
|
142
108
|
}
|
|
143
109
|
}
|
|
@@ -146,32 +112,32 @@ async function chat(userInput) {
|
|
|
146
112
|
}
|
|
147
113
|
}
|
|
148
114
|
else {
|
|
149
|
-
process.stdout.write('\n' +
|
|
115
|
+
process.stdout.write('\n' + color.tokenInfo(tokenText));
|
|
150
116
|
}
|
|
151
117
|
}
|
|
152
118
|
process.stdout.write('\n\n');
|
|
153
119
|
}
|
|
154
|
-
async function interactiveChat() {
|
|
120
|
+
export async function interactiveChat() {
|
|
155
121
|
await printBanner();
|
|
156
|
-
await
|
|
122
|
+
await runSessionStartHooks(threadId);
|
|
157
123
|
while (true) {
|
|
158
|
-
const userInput = await prompt(
|
|
124
|
+
const userInput = await prompt(color.userPrefix());
|
|
159
125
|
if (!userInput.trim())
|
|
160
126
|
continue;
|
|
161
127
|
if (userInput.toLowerCase() === 'exit') {
|
|
162
|
-
console.log(
|
|
128
|
+
console.log(color.goodbye('再见!'));
|
|
163
129
|
break;
|
|
164
130
|
}
|
|
165
131
|
if (userInput.startsWith('/')) {
|
|
166
132
|
const parts = userInput.trim().split(/\s+/);
|
|
167
133
|
const cmdName = parts[0].slice(1);
|
|
168
134
|
const args = parts.slice(1);
|
|
169
|
-
const cmd =
|
|
135
|
+
const cmd = commands.get(cmdName);
|
|
170
136
|
if (cmd) {
|
|
171
137
|
await cmd.execute(args);
|
|
172
138
|
}
|
|
173
139
|
else {
|
|
174
|
-
console.log(
|
|
140
|
+
console.log(color.error(`Unknown command: ${cmdName}`));
|
|
175
141
|
}
|
|
176
142
|
continue;
|
|
177
143
|
}
|
|
@@ -179,7 +145,7 @@ async function interactiveChat() {
|
|
|
179
145
|
await chat(userInput);
|
|
180
146
|
}
|
|
181
147
|
catch (err) {
|
|
182
|
-
console.error(
|
|
148
|
+
console.error(color.error(`请求出错: ${err.message}`));
|
|
183
149
|
}
|
|
184
150
|
}
|
|
185
151
|
}
|
package/dist/agent/colors.js
CHANGED
|
@@ -1,44 +1,6 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.color = void 0;
|
|
37
|
-
exports.initColors = initColors;
|
|
38
|
-
exports.formatToolLog = formatToolLog;
|
|
39
1
|
let _chalk = null;
|
|
40
|
-
async function initColors() {
|
|
41
|
-
const mod = (await
|
|
2
|
+
export async function initColors() {
|
|
3
|
+
const mod = (await import('chalk'));
|
|
42
4
|
_chalk = mod.default;
|
|
43
5
|
}
|
|
44
6
|
function createPlainFallback() {
|
|
@@ -55,7 +17,7 @@ function ck() {
|
|
|
55
17
|
}
|
|
56
18
|
return _chalk;
|
|
57
19
|
}
|
|
58
|
-
|
|
20
|
+
export const color = {
|
|
59
21
|
banner: (text) => ck().cyanBright.bold(text),
|
|
60
22
|
userPrefix: () => ck().greenBright.bold('You: '),
|
|
61
23
|
aiPrefix: () => ck().cyanBright.bold('AI: '),
|
|
@@ -72,10 +34,10 @@ exports.color = {
|
|
|
72
34
|
info: (text) => ck().blueBright(text),
|
|
73
35
|
good: (text) => ck().greenBright(text),
|
|
74
36
|
};
|
|
75
|
-
function formatToolLog(name, detail) {
|
|
76
|
-
const parts = [
|
|
37
|
+
export function formatToolLog(name, detail) {
|
|
38
|
+
const parts = [color.toolTag(), color.toolName(name), color.toolAction()];
|
|
77
39
|
if (detail) {
|
|
78
|
-
parts.push(
|
|
40
|
+
parts.push(color.toolArg(detail));
|
|
79
41
|
}
|
|
80
42
|
return '\n' + parts.join(' ');
|
|
81
43
|
}
|