@onesclawkolor/onesclaw 0.1.0

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 (141) hide show
  1. package/README.md +65 -0
  2. package/dist/agent/conversation.d.ts +34 -0
  3. package/dist/agent/conversation.js +61 -0
  4. package/dist/agent/conversation.js.map +1 -0
  5. package/dist/agent/loop.d.ts +40 -0
  6. package/dist/agent/loop.js +213 -0
  7. package/dist/agent/loop.js.map +1 -0
  8. package/dist/agent/session.d.ts +73 -0
  9. package/dist/agent/session.js +225 -0
  10. package/dist/agent/session.js.map +1 -0
  11. package/dist/audit/file-sink.d.ts +6 -0
  12. package/dist/audit/file-sink.js +21 -0
  13. package/dist/audit/file-sink.js.map +1 -0
  14. package/dist/audit/ids.d.ts +3 -0
  15. package/dist/audit/ids.js +15 -0
  16. package/dist/audit/ids.js.map +1 -0
  17. package/dist/audit/types.d.ts +13 -0
  18. package/dist/audit/types.js +2 -0
  19. package/dist/audit/types.js.map +1 -0
  20. package/dist/cli/commands.d.ts +31 -0
  21. package/dist/cli/commands.js +433 -0
  22. package/dist/cli/commands.js.map +1 -0
  23. package/dist/cli/logger.d.ts +57 -0
  24. package/dist/cli/logger.js +79 -0
  25. package/dist/cli/logger.js.map +1 -0
  26. package/dist/cli/output.d.ts +59 -0
  27. package/dist/cli/output.js +306 -0
  28. package/dist/cli/output.js.map +1 -0
  29. package/dist/cli/prompt.d.ts +29 -0
  30. package/dist/cli/prompt.js +197 -0
  31. package/dist/cli/prompt.js.map +1 -0
  32. package/dist/cli/repl.d.ts +4 -0
  33. package/dist/cli/repl.js +486 -0
  34. package/dist/cli/repl.js.map +1 -0
  35. package/dist/commands/init.d.ts +4 -0
  36. package/dist/commands/init.js +84 -0
  37. package/dist/commands/init.js.map +1 -0
  38. package/dist/commands/model.d.ts +3 -0
  39. package/dist/commands/model.js +178 -0
  40. package/dist/commands/model.js.map +1 -0
  41. package/dist/commands/plugin-init.d.ts +23 -0
  42. package/dist/commands/plugin-init.js +303 -0
  43. package/dist/commands/plugin-init.js.map +1 -0
  44. package/dist/commands/provider-auth.d.ts +14 -0
  45. package/dist/commands/provider-auth.js +153 -0
  46. package/dist/commands/provider-auth.js.map +1 -0
  47. package/dist/config/manager.d.ts +71 -0
  48. package/dist/config/manager.js +201 -0
  49. package/dist/config/manager.js.map +1 -0
  50. package/dist/config/types.d.ts +43 -0
  51. package/dist/config/types.js +2 -0
  52. package/dist/config/types.js.map +1 -0
  53. package/dist/errors.d.ts +37 -0
  54. package/dist/errors.js +55 -0
  55. package/dist/errors.js.map +1 -0
  56. package/dist/index.d.ts +2 -0
  57. package/dist/index.js +207 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/llm/anthropic.d.ts +83 -0
  60. package/dist/llm/anthropic.js +190 -0
  61. package/dist/llm/anthropic.js.map +1 -0
  62. package/dist/llm/factory.d.ts +105 -0
  63. package/dist/llm/factory.js +164 -0
  64. package/dist/llm/factory.js.map +1 -0
  65. package/dist/llm/openai-codex.d.ts +102 -0
  66. package/dist/llm/openai-codex.js +445 -0
  67. package/dist/llm/openai-codex.js.map +1 -0
  68. package/dist/llm/openai.d.ts +71 -0
  69. package/dist/llm/openai.js +289 -0
  70. package/dist/llm/openai.js.map +1 -0
  71. package/dist/llm/provider.d.ts +1 -0
  72. package/dist/llm/provider.js +2 -0
  73. package/dist/llm/provider.js.map +1 -0
  74. package/dist/llm/types.d.ts +72 -0
  75. package/dist/llm/types.js +2 -0
  76. package/dist/llm/types.js.map +1 -0
  77. package/dist/mcp/bridge.d.ts +17 -0
  78. package/dist/mcp/bridge.js +74 -0
  79. package/dist/mcp/bridge.js.map +1 -0
  80. package/dist/mcp/config.d.ts +10 -0
  81. package/dist/mcp/config.js +27 -0
  82. package/dist/mcp/config.js.map +1 -0
  83. package/dist/mcp/manager.d.ts +67 -0
  84. package/dist/mcp/manager.js +207 -0
  85. package/dist/mcp/manager.js.map +1 -0
  86. package/dist/memory/scope.d.ts +4 -0
  87. package/dist/memory/scope.js +14 -0
  88. package/dist/memory/scope.js.map +1 -0
  89. package/dist/memory/store.d.ts +28 -0
  90. package/dist/memory/store.js +126 -0
  91. package/dist/memory/store.js.map +1 -0
  92. package/dist/prompts/system.d.ts +4 -0
  93. package/dist/prompts/system.js +197 -0
  94. package/dist/prompts/system.js.map +1 -0
  95. package/dist/skills/loader.d.ts +25 -0
  96. package/dist/skills/loader.js +98 -0
  97. package/dist/skills/loader.js.map +1 -0
  98. package/dist/skills/registry.d.ts +57 -0
  99. package/dist/skills/registry.js +132 -0
  100. package/dist/skills/registry.js.map +1 -0
  101. package/dist/skills/sync.d.ts +33 -0
  102. package/dist/skills/sync.js +180 -0
  103. package/dist/skills/sync.js.map +1 -0
  104. package/dist/skills/types.d.ts +1 -0
  105. package/dist/skills/types.js +2 -0
  106. package/dist/skills/types.js.map +1 -0
  107. package/dist/tools/ask.d.ts +30 -0
  108. package/dist/tools/ask.js +60 -0
  109. package/dist/tools/ask.js.map +1 -0
  110. package/dist/tools/confirmation.d.ts +12 -0
  111. package/dist/tools/confirmation.js +75 -0
  112. package/dist/tools/confirmation.js.map +1 -0
  113. package/dist/tools/plugin-init.d.ts +29 -0
  114. package/dist/tools/plugin-init.js +47 -0
  115. package/dist/tools/plugin-init.js.map +1 -0
  116. package/dist/tools/registry.d.ts +56 -0
  117. package/dist/tools/registry.js +123 -0
  118. package/dist/tools/registry.js.map +1 -0
  119. package/dist/tools/safety.d.ts +2 -0
  120. package/dist/tools/safety.js +30 -0
  121. package/dist/tools/safety.js.map +1 -0
  122. package/dist/tools/server.d.ts +91 -0
  123. package/dist/tools/server.js +149 -0
  124. package/dist/tools/server.js.map +1 -0
  125. package/dist/tools/shell.d.ts +11 -0
  126. package/dist/tools/shell.js +174 -0
  127. package/dist/tools/shell.js.map +1 -0
  128. package/dist/tools/skills-sync.d.ts +19 -0
  129. package/dist/tools/skills-sync.js +29 -0
  130. package/dist/tools/skills-sync.js.map +1 -0
  131. package/dist/tools/ssh.d.ts +62 -0
  132. package/dist/tools/ssh.js +343 -0
  133. package/dist/tools/ssh.js.map +1 -0
  134. package/dist/tools/types.d.ts +10 -0
  135. package/dist/tools/types.js +2 -0
  136. package/dist/tools/types.js.map +1 -0
  137. package/dist/utils/retry.d.ts +7 -0
  138. package/dist/utils/retry.js +34 -0
  139. package/dist/utils/retry.js.map +1 -0
  140. package/install.sh +171 -0
  141. package/package.json +49 -0
package/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # onesclaw
2
+
3
+ ONES 企业内部 AI Agent CLI。
4
+
5
+ ## Quick Start
6
+
7
+ 公开 npm 安装:
8
+
9
+ ```bash
10
+ npm install -g @onesclawkolor/onesclaw
11
+ onesclaw init
12
+ onesclaw
13
+ ```
14
+
15
+ 或手动安装:
16
+
17
+ ```bash
18
+ npm install -g @onesclawkolor/onesclaw
19
+ onesclaw init
20
+ onesclaw
21
+ ```
22
+
23
+ 公开 npm 发布使用个人 scope,例如当前账号为 `onesclawkolor` 时:
24
+
25
+ ```bash
26
+ npm install -g @onesclawkolor/onesclaw
27
+ onesclaw init
28
+ onesclaw
29
+ ```
30
+
31
+ ## Requirements
32
+
33
+ - Node.js >= 18
34
+ - macOS / Linux(Windows 请使用 WSL)
35
+
36
+ ## Stage Gates
37
+
38
+ - 路线图:`phases.md`
39
+ - 蓝图:`docs/blueprint-v1.md`
40
+ - 阶段门禁文档:`docs/gates/`
41
+ - 发布运维 Runbook:`docs/operations/release-runbook.md`
42
+ - Phase1 冲刺看板:`docs/gates/phase1-sprint-board.md`
43
+ - Phase1 OAuth 矩阵:`docs/gates/phase1-oauth-matrix.md`
44
+ - 核心覆盖率检查:`npm run coverage:core`
45
+ - 运行自检:`npm run doctor`
46
+ - 安装演练:`npm run install:rehearsal`
47
+ - 本地预检:`npm run gate:all:local`
48
+ - 私有发布:`npm run release:publish:private`
49
+ - 公开发布:`npm run release:publish:public`
50
+ - 安装入口上传:`npm run release:install:upload`
51
+ - 远端安装验证:`npm run release:install:verify`
52
+ - 阶段命令:
53
+ - `npm run gate:phase0`
54
+ - `npm run gate:phase1`
55
+ - `npm run gate:phase1:strict-dryrun`
56
+ - `npm run gate:phase1_5`
57
+ - `npm run gate:phase2`
58
+ - `npm run gate:phase3`
59
+ - `npm run gate:phase4`
60
+ - `npm run gate:phase4-skills`
61
+ - `npm run gate:phase5`
62
+ - `npm run gate:phase6-provider`
63
+ - `npm run gate:all:local`
64
+ - `npm run gate:all`
65
+ - 作用域白名单强制模式:`GATE_STRICT_SCOPE=true npm run gate:phaseX`
@@ -0,0 +1,34 @@
1
+ /**
2
+ * 对话历史管理器
3
+ * 维护 LLM 对话上下文,格式兼容 Anthropic API
4
+ */
5
+ export declare class Conversation {
6
+ messages: any[];
7
+ /**
8
+ * 添加用户消息
9
+ */
10
+ addUserMessage(text: any): void;
11
+ /**
12
+ * 添加助手消息(可包含文本和工具调用)
13
+ */
14
+ addAssistantMessage(content: any): void;
15
+ /**
16
+ * 添加工具执行结果
17
+ * 多个工具结果合并到同一个 user 消息中(Anthropic API 要求)
18
+ */
19
+ addToolResults(results: any): void;
20
+ /**
21
+ * 获取完整消息历史(传给 LLM)
22
+ */
23
+ getMessages(): any[];
24
+ /**
25
+ * 截断历史消息,保留最近 keepRecent 条
26
+ * 用于 context length exceeded 时自动恢复
27
+ * @returns true 表示成功截断,false 表示已无法再截断
28
+ */
29
+ truncate(keepRecent?: number): boolean;
30
+ /**
31
+ * 清空历史
32
+ */
33
+ clear(): void;
34
+ }
@@ -0,0 +1,61 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * 对话历史管理器
4
+ * 维护 LLM 对话上下文,格式兼容 Anthropic API
5
+ */
6
+ export class Conversation {
7
+ messages = [];
8
+ /**
9
+ * 添加用户消息
10
+ */
11
+ addUserMessage(text) {
12
+ this.messages.push({ role: 'user', content: text });
13
+ }
14
+ /**
15
+ * 添加助手消息(可包含文本和工具调用)
16
+ */
17
+ addAssistantMessage(content) {
18
+ this.messages.push({ role: 'assistant', content });
19
+ }
20
+ /**
21
+ * 添加工具执行结果
22
+ * 多个工具结果合并到同一个 user 消息中(Anthropic API 要求)
23
+ */
24
+ addToolResults(results) {
25
+ const toolResultBlocks = results.map((r) => ({
26
+ type: 'tool_result',
27
+ tool_use_id: r.toolUseId,
28
+ content: r.content,
29
+ is_error: r.isError,
30
+ }));
31
+ this.messages.push({ role: 'user', content: toolResultBlocks });
32
+ }
33
+ /**
34
+ * 获取完整消息历史(传给 LLM)
35
+ */
36
+ getMessages() {
37
+ return [...this.messages];
38
+ }
39
+ /**
40
+ * 截断历史消息,保留最近 keepRecent 条
41
+ * 用于 context length exceeded 时自动恢复
42
+ * @returns true 表示成功截断,false 表示已无法再截断
43
+ */
44
+ truncate(keepRecent = 6) {
45
+ if (this.messages.length <= keepRecent)
46
+ return false;
47
+ this.messages = this.messages.slice(-keepRecent);
48
+ // 确保首条消息是 user 角色(Anthropic API 要求)
49
+ while (this.messages.length > 0 && this.messages[0].role !== 'user') {
50
+ this.messages.shift();
51
+ }
52
+ return this.messages.length > 0;
53
+ }
54
+ /**
55
+ * 清空历史
56
+ */
57
+ clear() {
58
+ this.messages = [];
59
+ }
60
+ }
61
+ //# sourceMappingURL=conversation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation.js","sourceRoot":"","sources":["../../src/agent/conversation.ts"],"names":[],"mappings":"AAAA,cAAc;AACd;;;GAGG;AACH,MAAM,OAAO,YAAY;IACrB,QAAQ,GAAG,EAAE,CAAC;IACd;;OAEG;IACH,cAAc,CAAC,IAAI;QACf,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,CAAC;IACD;;OAEG;IACH,mBAAmB,CAAC,OAAO;QACvB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC;IACvD,CAAC;IACD;;;OAGG;IACH,cAAc,CAAC,OAAO;QAClB,MAAM,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACzC,IAAI,EAAE,aAAa;YACnB,WAAW,EAAE,CAAC,CAAC,SAAS;YACxB,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,QAAQ,EAAE,CAAC,CAAC,OAAO;SACtB,CAAC,CAAC,CAAC;QACJ,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC,CAAC;IACpE,CAAC;IACD;;OAEG;IACH,WAAW;QACP,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC9B,CAAC;IACD;;;;OAIG;IACH,QAAQ,CAAC,UAAU,GAAG,CAAC;QACnB,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,UAAU;YAClC,OAAO,KAAK,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC;QACjD,oCAAoC;QACpC,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAClE,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QAC1B,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;IACpC,CAAC;IACD;;OAEG;IACH,KAAK;QACD,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;IACvB,CAAC;CACJ"}
@@ -0,0 +1,40 @@
1
+ import type { StreamEvent, ChatOptions } from '../llm/types.js';
2
+ import type { ToolRegistry } from '../tools/registry.js';
3
+ import type { SessionState } from './session.js';
4
+ /**
5
+ * Agent 核心循环(ReAct 模式)
6
+ *
7
+ * 接收用户输入 → 调用 LLM → 执行工具 → 反馈结果 → 循环直到 LLM 结束
8
+ */
9
+ export declare class AgentLoop {
10
+ conversation: any;
11
+ toolRegistry: ToolRegistry;
12
+ llmProvider: any;
13
+ baseSystemPrompt: string;
14
+ chatOptions: ChatOptions;
15
+ session: SessionState | null;
16
+ constructor(params: {
17
+ llmProvider: any;
18
+ toolRegistry: ToolRegistry;
19
+ systemPrompt?: string;
20
+ chatOptions?: ChatOptions;
21
+ session?: SessionState | null;
22
+ });
23
+ /**
24
+ * 动态构建 system prompt
25
+ * 将 session 上下文追加到基础 prompt 后
26
+ */
27
+ buildSystemPrompt(): string;
28
+ /**
29
+ * 运行时热切换 LLM Provider 和模型
30
+ */
31
+ updateProvider(provider: any, model: string): void;
32
+ /**
33
+ * 清空对话历史(/clear 命令使用)
34
+ */
35
+ clearHistory(): void;
36
+ /**
37
+ * 处理用户输入,返回事件流供 REPL 消费
38
+ */
39
+ run(userInput: string): AsyncGenerator<StreamEvent, void, unknown>;
40
+ }
@@ -0,0 +1,213 @@
1
+ import { Conversation } from './conversation.js';
2
+ import { logger } from '../cli/logger.js';
3
+ import { LLMError } from '../errors.js';
4
+ const MAX_ITERATIONS = 20;
5
+ /**
6
+ * Agent 核心循环(ReAct 模式)
7
+ *
8
+ * 接收用户输入 → 调用 LLM → 执行工具 → 反馈结果 → 循环直到 LLM 结束
9
+ */
10
+ export class AgentLoop {
11
+ conversation;
12
+ toolRegistry;
13
+ llmProvider;
14
+ baseSystemPrompt;
15
+ chatOptions;
16
+ session;
17
+ constructor(params) {
18
+ this.conversation = new Conversation();
19
+ this.toolRegistry = params.toolRegistry;
20
+ this.llmProvider = params.llmProvider;
21
+ this.baseSystemPrompt = params.systemPrompt || '';
22
+ this.chatOptions = params.chatOptions || {};
23
+ this.session = params.session || null;
24
+ }
25
+ /**
26
+ * 动态构建 system prompt
27
+ * 将 session 上下文追加到基础 prompt 后
28
+ */
29
+ buildSystemPrompt() {
30
+ const sessionSection = this.session?.toPromptSection() || '';
31
+ if (!sessionSection)
32
+ return this.baseSystemPrompt;
33
+ return this.baseSystemPrompt + '\n\n' + sessionSection;
34
+ }
35
+ /**
36
+ * 运行时热切换 LLM Provider 和模型
37
+ */
38
+ updateProvider(provider, model) {
39
+ this.llmProvider = provider;
40
+ this.chatOptions = { ...this.chatOptions, model };
41
+ }
42
+ /**
43
+ * 清空对话历史(/clear 命令使用)
44
+ */
45
+ clearHistory() {
46
+ this.conversation.clear();
47
+ this.session?.clearConversation();
48
+ }
49
+ /**
50
+ * 处理用户输入,返回事件流供 REPL 消费
51
+ */
52
+ async *run(userInput) {
53
+ this.session?.incrementTurn();
54
+ this.session?.checkUserInput(userInput);
55
+ this.conversation.addUserMessage(userInput);
56
+ for (let iteration = 0; iteration < MAX_ITERATIONS; iteration++) {
57
+ // 通知 REPL:新一轮 LLM 调用开始
58
+ yield { type: 'turn_start' };
59
+ // 累积文本和工具调用,用于重建助手消息
60
+ let accumulatedText = '';
61
+ const toolCalls = [];
62
+ let currentToolId = '';
63
+ let currentToolName = '';
64
+ let currentInputJson = '';
65
+ // 调用 LLM 并转发流式事件
66
+ const stream = this.llmProvider.chat(this.conversation.getMessages(), this.toolRegistry.getToolDefinitions(), {
67
+ ...this.chatOptions,
68
+ system: this.buildSystemPrompt() || undefined,
69
+ });
70
+ let shouldRetryWithTruncation = false;
71
+ for await (const event of stream) {
72
+ switch (event.type) {
73
+ case 'text_delta':
74
+ accumulatedText += event.text;
75
+ yield event;
76
+ break;
77
+ case 'tool_use_start':
78
+ currentToolId = event.id;
79
+ currentToolName = event.name;
80
+ currentInputJson = '';
81
+ yield event;
82
+ break;
83
+ case 'tool_use_delta':
84
+ currentInputJson += event.input_json;
85
+ break;
86
+ case 'tool_use_end':
87
+ toolCalls.push({
88
+ id: currentToolId,
89
+ name: currentToolName,
90
+ inputJson: currentInputJson,
91
+ });
92
+ yield event;
93
+ break;
94
+ case 'message_end':
95
+ yield event;
96
+ break;
97
+ case 'error': {
98
+ // Context length exceeded → 截断历史并重试
99
+ if (event.error instanceof LLMError &&
100
+ event.error.statusCode === 400 &&
101
+ (event.error.message.includes('context') ||
102
+ event.error.message.includes('too long') ||
103
+ event.error.message.includes('max tokens') ||
104
+ event.error.message.includes('too many'))) {
105
+ const truncated = this.conversation.truncate();
106
+ if (truncated) {
107
+ logger.debug('agent', 'Context length exceeded, truncated conversation history, retrying...');
108
+ yield {
109
+ type: 'text_delta',
110
+ text: '\n[对话历史过长,已自动截断,正在重试...]\n',
111
+ };
112
+ shouldRetryWithTruncation = true;
113
+ break;
114
+ }
115
+ }
116
+ yield event;
117
+ return;
118
+ }
119
+ }
120
+ }
121
+ // 截断后重试:跳到外层 for 循环下一轮
122
+ if (shouldRetryWithTruncation) {
123
+ continue;
124
+ }
125
+ // 重建助手消息并保存到对话历史
126
+ const contentBlocks = [];
127
+ if (accumulatedText) {
128
+ contentBlocks.push({ type: 'text', text: accumulatedText });
129
+ }
130
+ for (const call of toolCalls) {
131
+ let input = {};
132
+ try {
133
+ input = call.inputJson ? JSON.parse(call.inputJson) : {};
134
+ }
135
+ catch {
136
+ // 解析失败时用空对象
137
+ }
138
+ const block = {
139
+ type: 'tool_use',
140
+ id: call.id,
141
+ name: call.name,
142
+ input,
143
+ };
144
+ contentBlocks.push(block);
145
+ }
146
+ if (contentBlocks.length > 0) {
147
+ this.conversation.addAssistantMessage(contentBlocks);
148
+ }
149
+ // 无工具调用 → 对话结束
150
+ if (toolCalls.length === 0) {
151
+ return;
152
+ }
153
+ // 执行所有工具并收集结果
154
+ const toolResults = [];
155
+ for (const call of toolCalls) {
156
+ let args = {};
157
+ try {
158
+ args = call.inputJson ? JSON.parse(call.inputJson) : {};
159
+ }
160
+ catch {
161
+ toolResults.push({
162
+ toolUseId: call.id,
163
+ content: `工具参数解析失败: ${call.inputJson}`,
164
+ isError: true,
165
+ });
166
+ continue;
167
+ }
168
+ yield { type: 'tool_execute_start', name: call.name, args };
169
+ const toolStart = Date.now();
170
+ const result = await this.toolRegistry.executeTool(call.name, args);
171
+ const toolDuration = Date.now() - toolStart;
172
+ logger.debug('tool', `${call.name} completed in ${toolDuration}ms`);
173
+ // 观察工具执行结果,更新会话状态
174
+ this.session?.observe(call.name, args, result);
175
+ const maxResultLen = 500;
176
+ const resultSummary = result.content.length > maxResultLen
177
+ ? result.content.slice(0, maxResultLen) + '…'
178
+ : result.content;
179
+ yield {
180
+ type: 'tool_execute_end',
181
+ name: call.name,
182
+ result: resultSummary,
183
+ isError: result.isError,
184
+ };
185
+ toolResults.push({
186
+ toolUseId: call.id,
187
+ content: result.content,
188
+ isError: result.isError,
189
+ });
190
+ // SSH 执行失败时立即终止当前任务,避免继续执行后续操作
191
+ if (call.name === 'ssh_execute' && result.isError) {
192
+ this.conversation.addToolResults(toolResults);
193
+ yield {
194
+ type: 'text_delta',
195
+ text: '\n[ssh_execute 失败,按安全规则已停止当前任务]\n',
196
+ };
197
+ yield { type: 'message_end', stop_reason: 'end_turn' };
198
+ return;
199
+ }
200
+ }
201
+ // 工具结果添加到对话历史
202
+ this.conversation.addToolResults(toolResults);
203
+ // 继续循环:带工具结果再次调用 LLM
204
+ }
205
+ // 达到最大循环次数
206
+ yield {
207
+ type: 'text_delta',
208
+ text: '\n[已达到最大工具调用轮次,停止处理]',
209
+ };
210
+ yield { type: 'message_end', stop_reason: 'end_turn' };
211
+ }
212
+ }
213
+ //# sourceMappingURL=loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.js","sourceRoot":"","sources":["../../src/agent/loop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ import type { MemoryStore } from '../memory/store.js';
2
+ /**
3
+ * 会话级别状态管理。
4
+ *
5
+ * 在同一会话内记忆上下文信息(SSH 连接、Skill 执行状态等),
6
+ * 并将关键状态持久化到 SQLite,跨重启可恢复。
7
+ */
8
+ export declare class SessionState {
9
+ /** 用户身份(不可变,来自 MCP who_am_i) */
10
+ user: any;
11
+ /** 预配置的 SSH 服务器列表 */
12
+ servers: any;
13
+ /** 持久化存储 */
14
+ memoryStore: MemoryStore | null;
15
+ scopeKey: string | null;
16
+ /** 匹配到服务器名称时注入的 prompt 段落 */
17
+ sshServersHint: any;
18
+ /** 最近使用的 SSH host */
19
+ currentHost: any;
20
+ /** 当前活跃的 SSH 连接 */
21
+ activeConnections: Set<string>;
22
+ /** 当前正在执行的 Skill name */
23
+ activeSkill: any;
24
+ /** 当前 Skill 执行阶段 */
25
+ skillPhase: any;
26
+ /** 最近确认/偏好 */
27
+ recentDecisions: string[];
28
+ /** 对话轮数 */
29
+ conversationTurns: number;
30
+ /** 最后活动时间 */
31
+ lastActivity: Date;
32
+ constructor(user: any, servers?: any[], options?: {});
33
+ static create(options: {
34
+ user?: {
35
+ id?: string;
36
+ name?: string;
37
+ email?: string;
38
+ } | null;
39
+ servers?: Array<{
40
+ name: string;
41
+ host: string;
42
+ description?: string;
43
+ }>;
44
+ memoryStore?: MemoryStore | null;
45
+ scopeKey?: string | null;
46
+ }): Promise<SessionState>;
47
+ hydrateFromMemory(): Promise<void>;
48
+ persistToMemory(): void;
49
+ /**
50
+ * 每轮用户输入时调用
51
+ */
52
+ incrementTurn(): void;
53
+ /** SSH 相关关键词,匹配到任一即注入服务器列表 */
54
+ static SSH_KEYWORDS: string[];
55
+ /**
56
+ * 检查用户输入是否涉及 SSH 操作
57
+ * 匹配服务器名称或 SSH 关键词时,注入服务器列表到 system prompt
58
+ */
59
+ checkUserInput(input: any): void;
60
+ private pushDecision;
61
+ /**
62
+ * 观察工具执行结果,自动更新会话状态。
63
+ */
64
+ observe(toolName: any, args: any, result: any): void;
65
+ /**
66
+ * /clear 时清理会话上下文,并删除当前 scope 的持久化记忆。
67
+ */
68
+ clearConversation(): void;
69
+ /**
70
+ * 生成 system prompt 注入段落。
71
+ */
72
+ toPromptSection(): string;
73
+ }