@seandong/seno 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 (104) hide show
  1. package/README.md +70 -0
  2. package/dist/agent/conversation.d.ts +39 -0
  3. package/dist/agent/conversation.js +60 -0
  4. package/dist/agent/conversation.js.map +1 -0
  5. package/dist/agent/loop.d.ts +41 -0
  6. package/dist/agent/loop.js +203 -0
  7. package/dist/agent/loop.js.map +1 -0
  8. package/dist/agent/session.d.ts +63 -0
  9. package/dist/agent/session.js +135 -0
  10. package/dist/agent/session.js.map +1 -0
  11. package/dist/cli/commands.d.ts +52 -0
  12. package/dist/cli/commands.js +667 -0
  13. package/dist/cli/commands.js.map +1 -0
  14. package/dist/cli/logger.d.ts +38 -0
  15. package/dist/cli/logger.js +79 -0
  16. package/dist/cli/logger.js.map +1 -0
  17. package/dist/cli/output.d.ts +75 -0
  18. package/dist/cli/output.js +305 -0
  19. package/dist/cli/output.js.map +1 -0
  20. package/dist/cli/prompt.d.ts +30 -0
  21. package/dist/cli/prompt.js +196 -0
  22. package/dist/cli/prompt.js.map +1 -0
  23. package/dist/cli/repl.d.ts +27 -0
  24. package/dist/cli/repl.js +485 -0
  25. package/dist/cli/repl.js.map +1 -0
  26. package/dist/commands/init.d.ts +4 -0
  27. package/dist/commands/init.js +170 -0
  28. package/dist/commands/init.js.map +1 -0
  29. package/dist/commands/model.d.ts +10 -0
  30. package/dist/commands/model.js +270 -0
  31. package/dist/commands/model.js.map +1 -0
  32. package/dist/config/manager.d.ts +67 -0
  33. package/dist/config/manager.js +194 -0
  34. package/dist/config/manager.js.map +1 -0
  35. package/dist/config/types.d.ts +98 -0
  36. package/dist/config/types.js +2 -0
  37. package/dist/config/types.js.map +1 -0
  38. package/dist/errors.d.ts +37 -0
  39. package/dist/errors.js +54 -0
  40. package/dist/errors.js.map +1 -0
  41. package/dist/index.d.ts +2 -0
  42. package/dist/index.js +185 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/llm/anthropic.d.ts +27 -0
  45. package/dist/llm/anthropic.js +189 -0
  46. package/dist/llm/anthropic.js.map +1 -0
  47. package/dist/llm/factory.d.ts +47 -0
  48. package/dist/llm/factory.js +163 -0
  49. package/dist/llm/factory.js.map +1 -0
  50. package/dist/llm/openai-codex.d.ts +45 -0
  51. package/dist/llm/openai-codex.js +398 -0
  52. package/dist/llm/openai-codex.js.map +1 -0
  53. package/dist/llm/openai.d.ts +16 -0
  54. package/dist/llm/openai.js +288 -0
  55. package/dist/llm/openai.js.map +1 -0
  56. package/dist/llm/provider.d.ts +19 -0
  57. package/dist/llm/provider.js +2 -0
  58. package/dist/llm/provider.js.map +1 -0
  59. package/dist/llm/types.d.ts +102 -0
  60. package/dist/llm/types.js +2 -0
  61. package/dist/llm/types.js.map +1 -0
  62. package/dist/mcp/bridge.d.ts +30 -0
  63. package/dist/mcp/bridge.js +73 -0
  64. package/dist/mcp/bridge.js.map +1 -0
  65. package/dist/mcp/config.d.ts +6 -0
  66. package/dist/mcp/config.js +26 -0
  67. package/dist/mcp/config.js.map +1 -0
  68. package/dist/mcp/manager.d.ts +54 -0
  69. package/dist/mcp/manager.js +171 -0
  70. package/dist/mcp/manager.js.map +1 -0
  71. package/dist/prompts/system.d.ts +14 -0
  72. package/dist/prompts/system.js +194 -0
  73. package/dist/prompts/system.js.map +1 -0
  74. package/dist/skills/loader.d.ts +7 -0
  75. package/dist/skills/loader.js +81 -0
  76. package/dist/skills/loader.js.map +1 -0
  77. package/dist/skills/registry.d.ts +48 -0
  78. package/dist/skills/registry.js +104 -0
  79. package/dist/skills/registry.js.map +1 -0
  80. package/dist/skills/sync.d.ts +34 -0
  81. package/dist/skills/sync.js +179 -0
  82. package/dist/skills/sync.js.map +1 -0
  83. package/dist/skills/types.d.ts +29 -0
  84. package/dist/skills/types.js +2 -0
  85. package/dist/skills/types.js.map +1 -0
  86. package/dist/tools/ask.d.ts +16 -0
  87. package/dist/tools/ask.js +57 -0
  88. package/dist/tools/ask.js.map +1 -0
  89. package/dist/tools/registry.d.ts +54 -0
  90. package/dist/tools/registry.js +114 -0
  91. package/dist/tools/registry.js.map +1 -0
  92. package/dist/tools/shell.d.ts +10 -0
  93. package/dist/tools/shell.js +131 -0
  94. package/dist/tools/shell.js.map +1 -0
  95. package/dist/tools/ssh.d.ts +40 -0
  96. package/dist/tools/ssh.js +302 -0
  97. package/dist/tools/ssh.js.map +1 -0
  98. package/dist/tools/types.d.ts +20 -0
  99. package/dist/tools/types.js +2 -0
  100. package/dist/tools/types.js.map +1 -0
  101. package/dist/utils/retry.d.ts +20 -0
  102. package/dist/utils/retry.js +33 -0
  103. package/dist/utils/retry.js.map +1 -0
  104. package/package.json +51 -0
package/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # SENO
2
+
3
+ ONES 企业内部 AI Agent CLI
4
+
5
+ ## 快速开始
6
+
7
+ ### 环境要求
8
+
9
+ - [Bun](https://bun.sh) >= 1.0
10
+
11
+ ### 安装
12
+
13
+ ```bash
14
+ git clone <repo-url>
15
+ cd ones-agent-cli
16
+ bun install
17
+ bun link
18
+ ```
19
+
20
+ ### 初始化
21
+
22
+ ```bash
23
+ seno init
24
+ ```
25
+
26
+ 按照交互提示完成配置:
27
+
28
+ 1. 选择 LLM Provider
29
+ 2. 配置授权(OAuth 或 API Key)
30
+ 3. 选择模型
31
+ 4. 输入 ONES MCP URL
32
+
33
+ 配置文件保存在 `~/.seno/config.json`。
34
+
35
+ ### 使用
36
+
37
+ ```bash
38
+ seno
39
+ ```
40
+
41
+ 启动后直接输入自然语言与 AI 对话。输入 `/` 查看可用命令。
42
+
43
+ ## 核心能力
44
+
45
+ - **运维自动化** — 通过内置 Skills 执行 ONES 安装、升级、备份、巡检等运维操作,支持 SSH 远程执行
46
+ - **插件开发** — 一键初始化 ONES 插件项目,自动检查环境依赖,提供开发文档参考
47
+ - **知识检索** — 智能检索企业内部 Wiki、运维手册、开发者文档、通用技术文档
48
+ - **ONES 协作** — 通过 MCP 直接操作 ONES 平台:任务管理、项目协作、Wiki、工时记录
49
+
50
+ ## 命令参考
51
+
52
+ | 命令 | 说明 |
53
+ |------|------|
54
+ | `/help` | 显示帮助信息 |
55
+ | `/skills list` | 列出所有 Skills |
56
+ | `/skills sync` | 手动同步远程 Skills |
57
+ | `/server list` | 列出所有 SSH 服务器 |
58
+ | `/server add` | 添加新服务器 |
59
+ | `/server remove <name>` | 删除指定服务器 |
60
+ | `/plugin init` | 初始化新插件项目 |
61
+ | `/model set` | 切换 Provider 和模型 |
62
+ | `/model auth` | 配置 Provider 授权 |
63
+ | `/clear` | 清空对话历史 |
64
+ | `/exit` | 退出 |
65
+
66
+ ## 更多文档
67
+
68
+ - [产品介绍](docs/product-intro.md)
69
+ - [架构规范](docs/architecture/ones-agent-cli-spec.md)
70
+ - [命令系统](docs/cli/command-system.md)
@@ -0,0 +1,39 @@
1
+ import type { Message, ContentBlock } from '../llm/types.js';
2
+ /**
3
+ * 对话历史管理器
4
+ * 维护 LLM 对话上下文,格式兼容 Anthropic API
5
+ */
6
+ export declare class Conversation {
7
+ private messages;
8
+ /**
9
+ * 添加用户消息
10
+ */
11
+ addUserMessage(text: string): void;
12
+ /**
13
+ * 添加助手消息(可包含文本和工具调用)
14
+ */
15
+ addAssistantMessage(content: ContentBlock[]): void;
16
+ /**
17
+ * 添加工具执行结果
18
+ * 多个工具结果合并到同一个 user 消息中(Anthropic API 要求)
19
+ */
20
+ addToolResults(results: Array<{
21
+ toolUseId: string;
22
+ content: string;
23
+ isError?: boolean;
24
+ }>): void;
25
+ /**
26
+ * 获取完整消息历史(传给 LLM)
27
+ */
28
+ getMessages(): Message[];
29
+ /**
30
+ * 截断历史消息,保留最近 keepRecent 条
31
+ * 用于 context length exceeded 时自动恢复
32
+ * @returns true 表示成功截断,false 表示已无法再截断
33
+ */
34
+ truncate(keepRecent?: number): boolean;
35
+ /**
36
+ * 清空历史
37
+ */
38
+ clear(): void;
39
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * 对话历史管理器
3
+ * 维护 LLM 对话上下文,格式兼容 Anthropic API
4
+ */
5
+ export class Conversation {
6
+ messages = [];
7
+ /**
8
+ * 添加用户消息
9
+ */
10
+ addUserMessage(text) {
11
+ this.messages.push({ role: 'user', content: text });
12
+ }
13
+ /**
14
+ * 添加助手消息(可包含文本和工具调用)
15
+ */
16
+ addAssistantMessage(content) {
17
+ this.messages.push({ role: 'assistant', content });
18
+ }
19
+ /**
20
+ * 添加工具执行结果
21
+ * 多个工具结果合并到同一个 user 消息中(Anthropic API 要求)
22
+ */
23
+ addToolResults(results) {
24
+ const toolResultBlocks = results.map((r) => ({
25
+ type: 'tool_result',
26
+ tool_use_id: r.toolUseId,
27
+ content: r.content,
28
+ is_error: r.isError,
29
+ }));
30
+ this.messages.push({ role: 'user', content: toolResultBlocks });
31
+ }
32
+ /**
33
+ * 获取完整消息历史(传给 LLM)
34
+ */
35
+ getMessages() {
36
+ return [...this.messages];
37
+ }
38
+ /**
39
+ * 截断历史消息,保留最近 keepRecent 条
40
+ * 用于 context length exceeded 时自动恢复
41
+ * @returns true 表示成功截断,false 表示已无法再截断
42
+ */
43
+ truncate(keepRecent = 6) {
44
+ if (this.messages.length <= keepRecent)
45
+ return false;
46
+ this.messages = this.messages.slice(-keepRecent);
47
+ // 确保首条消息是 user 角色(Anthropic API 要求)
48
+ while (this.messages.length > 0 && this.messages[0].role !== 'user') {
49
+ this.messages.shift();
50
+ }
51
+ return this.messages.length > 0;
52
+ }
53
+ /**
54
+ * 清空历史
55
+ */
56
+ clear() {
57
+ this.messages = [];
58
+ }
59
+ }
60
+ //# sourceMappingURL=conversation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation.js","sourceRoot":"","sources":["../../src/agent/conversation.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,OAAO,YAAY;IACf,QAAQ,GAAc,EAAE,CAAC;IAEjC;;OAEG;IACH,cAAc,CAAC,IAAY;QACzB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC;IAED;;OAEG;IACH,mBAAmB,CAAC,OAAuB;QACzC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC;IACrD,CAAC;IAED;;;OAGG;IACH,cAAc,CACZ,OAIE;QAEF,MAAM,gBAAgB,GAAsB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC9D,IAAI,EAAE,aAAsB;YAC5B,WAAW,EAAE,CAAC,CAAC,SAAS;YACxB,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,QAAQ,EAAE,CAAC,CAAC,OAAO;SACpB,CAAC,CAAC,CAAC;QAEJ,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAClE,CAAC;IAED;;OAEG;IACH,WAAW;QACT,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;IAED;;;;OAIG;IACH,QAAQ,CAAC,aAAqB,CAAC;QAC7B,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,UAAU;YAAE,OAAO,KAAK,CAAC;QACrD,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;YACpE,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACxB,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;IAClC,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;IACrB,CAAC;CACF"}
@@ -0,0 +1,41 @@
1
+ import type { LLMProvider } from '../llm/provider.js';
2
+ import type { StreamEvent, ChatOptions } from '../llm/types.js';
3
+ import type { ToolRegistry } from '../tools/registry.js';
4
+ import type { SessionState } from './session.js';
5
+ /**
6
+ * Agent 核心循环(ReAct 模式)
7
+ *
8
+ * 接收用户输入 → 调用 LLM → 执行工具 → 反馈结果 → 循环直到 LLM 结束
9
+ */
10
+ export declare class AgentLoop {
11
+ private conversation;
12
+ private toolRegistry;
13
+ private llmProvider;
14
+ private baseSystemPrompt;
15
+ private chatOptions;
16
+ private session;
17
+ constructor(params: {
18
+ llmProvider: LLMProvider;
19
+ toolRegistry: ToolRegistry;
20
+ systemPrompt?: string;
21
+ chatOptions?: ChatOptions;
22
+ session?: SessionState;
23
+ });
24
+ /**
25
+ * 动态构建 system prompt
26
+ * 将 session 上下文追加到基础 prompt 后
27
+ */
28
+ private buildSystemPrompt;
29
+ /**
30
+ * 运行时热切换 LLM Provider 和模型
31
+ */
32
+ updateProvider(provider: LLMProvider, model: string): void;
33
+ /**
34
+ * 清空对话历史(/clear 命令使用)
35
+ */
36
+ clearHistory(): void;
37
+ /**
38
+ * 处理用户输入,返回事件流供 REPL 消费
39
+ */
40
+ run(userInput: string): AsyncGenerator<StreamEvent>;
41
+ }
@@ -0,0 +1,203 @@
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
+ }
191
+ // 工具结果添加到对话历史
192
+ this.conversation.addToolResults(toolResults);
193
+ // 继续循环:带工具结果再次调用 LLM
194
+ }
195
+ // 达到最大循环次数
196
+ yield {
197
+ type: 'text_delta',
198
+ text: '\n[已达到最大工具调用轮次,停止处理]',
199
+ };
200
+ yield { type: 'message_end', stop_reason: 'end_turn' };
201
+ }
202
+ }
203
+ //# 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,63 @@
1
+ import type { UserInfo } from '../mcp/manager.js';
2
+ import type { SshServerConfig } from '../config/types.js';
3
+ /**
4
+ * 会话级别状态管理
5
+ *
6
+ * 在同一会话内记忆上下文信息(SSH 连接、Skill 执行状态等),
7
+ * 通过观察工具执行结果自动更新状态,并注入到每次 LLM 调用的 system prompt。
8
+ *
9
+ * 仅内存维护,不持久化。会话结束自动清理。
10
+ */
11
+ export declare class SessionState {
12
+ /** 用户身份(不可变,来自 MCP who_am_i) */
13
+ readonly user: UserInfo | null;
14
+ /** 预配置的 SSH 服务器列表 */
15
+ private servers;
16
+ /** 匹配到服务器名称时注入的 prompt 段落 */
17
+ private sshServersHint;
18
+ /** 最近使用的 SSH host */
19
+ currentHost: string | null;
20
+ /** 当前活跃的 SSH 连接 */
21
+ activeConnections: Set<string>;
22
+ /** 当前正在执行的 Skill name */
23
+ activeSkill: string | null;
24
+ /** 当前 Skill 执行阶段 */
25
+ skillPhase: string | null;
26
+ /** 对话轮数 */
27
+ conversationTurns: number;
28
+ /** 最后活动时间 */
29
+ lastActivity: Date;
30
+ constructor(user: UserInfo | null, servers?: SshServerConfig[]);
31
+ /**
32
+ * 每轮用户输入时调用
33
+ */
34
+ incrementTurn(): void;
35
+ /** SSH 相关关键词,匹配到任一即注入服务器列表 */
36
+ private static readonly SSH_KEYWORDS;
37
+ /**
38
+ * 检查用户输入是否涉及 SSH 操作
39
+ * 匹配服务器名称或 SSH 关键词时,注入服务器列表到 system prompt
40
+ */
41
+ checkUserInput(input: string): void;
42
+ /**
43
+ * 观察工具执行结果,自动更新会话状态
44
+ *
45
+ * 在 loop.ts 工具执行后调用,根据 toolName 和结果更新 session state。
46
+ */
47
+ observe(toolName: string, args: Record<string, unknown>, result: {
48
+ content: string;
49
+ isError?: boolean;
50
+ }): void;
51
+ /**
52
+ * /clear 时部分重置
53
+ * 保留 user(身份不变),清除动态上下文
54
+ */
55
+ clearConversation(): void;
56
+ /**
57
+ * 生成 system prompt 注入段落
58
+ *
59
+ * 无状态时返回空字符串(不污染 prompt)。
60
+ * 有状态时返回 "## 当前会话上下文" 段落。
61
+ */
62
+ toPromptSection(): string;
63
+ }
@@ -0,0 +1,135 @@
1
+ /**
2
+ * 会话级别状态管理
3
+ *
4
+ * 在同一会话内记忆上下文信息(SSH 连接、Skill 执行状态等),
5
+ * 通过观察工具执行结果自动更新状态,并注入到每次 LLM 调用的 system prompt。
6
+ *
7
+ * 仅内存维护,不持久化。会话结束自动清理。
8
+ */
9
+ export class SessionState {
10
+ /** 用户身份(不可变,来自 MCP who_am_i) */
11
+ user;
12
+ /** 预配置的 SSH 服务器列表 */
13
+ servers;
14
+ /** 匹配到服务器名称时注入的 prompt 段落 */
15
+ sshServersHint = null;
16
+ /** 最近使用的 SSH host */
17
+ currentHost = null;
18
+ /** 当前活跃的 SSH 连接 */
19
+ activeConnections = new Set();
20
+ /** 当前正在执行的 Skill name */
21
+ activeSkill = null;
22
+ /** 当前 Skill 执行阶段 */
23
+ skillPhase = null;
24
+ /** 对话轮数 */
25
+ conversationTurns = 0;
26
+ /** 最后活动时间 */
27
+ lastActivity = new Date();
28
+ constructor(user, servers = []) {
29
+ this.user = user;
30
+ this.servers = servers;
31
+ }
32
+ /**
33
+ * 每轮用户输入时调用
34
+ */
35
+ incrementTurn() {
36
+ this.conversationTurns++;
37
+ this.lastActivity = new Date();
38
+ }
39
+ /** SSH 相关关键词,匹配到任一即注入服务器列表 */
40
+ static SSH_KEYWORDS = [
41
+ '连接',
42
+ '服务器',
43
+ 'ssh',
44
+ '远程',
45
+ '登录',
46
+ ];
47
+ /**
48
+ * 检查用户输入是否涉及 SSH 操作
49
+ * 匹配服务器名称或 SSH 关键词时,注入服务器列表到 system prompt
50
+ */
51
+ checkUserInput(input) {
52
+ if (this.servers.length === 0)
53
+ return;
54
+ const lowerInput = input.toLowerCase();
55
+ const matchedByName = this.servers.some((s) => lowerInput.includes(s.name.toLowerCase()));
56
+ const matchedByKeyword = SessionState.SSH_KEYWORDS.some((kw) => lowerInput.includes(kw));
57
+ if (matchedByName || matchedByKeyword) {
58
+ const rows = this.servers.map((s) => `| ${s.name} | ${s.host} | ${s.description || '-'} |`);
59
+ this.sshServersHint = [
60
+ '## 可用 SSH 服务器',
61
+ '',
62
+ '当用户提到连接服务器或在服务器上执行命令时,使用 ssh_execute 工具,将 host 参数设置为下表中的服务器名称(必须精确匹配)。',
63
+ '',
64
+ '| 名称 | 地址 | 说明 |',
65
+ '|------|------|------|',
66
+ ...rows,
67
+ ].join('\n');
68
+ }
69
+ }
70
+ /**
71
+ * 观察工具执行结果,自动更新会话状态
72
+ *
73
+ * 在 loop.ts 工具执行后调用,根据 toolName 和结果更新 session state。
74
+ */
75
+ observe(toolName, args, result) {
76
+ this.lastActivity = new Date();
77
+ // SSH host 记忆:成功执行 ssh_execute 后记录 host
78
+ if (toolName === 'ssh_execute' && !result.isError) {
79
+ const host = args.host;
80
+ if (host) {
81
+ this.currentHost = host;
82
+ this.activeConnections.add(host);
83
+ }
84
+ }
85
+ // Skill 加载追踪:load_skill 成功后记录 skill 名称
86
+ if (toolName === 'load_skill' && !result.isError) {
87
+ const skillName = args.name;
88
+ if (skillName) {
89
+ this.activeSkill = skillName;
90
+ this.skillPhase = 'loaded';
91
+ }
92
+ }
93
+ }
94
+ /**
95
+ * /clear 时部分重置
96
+ * 保留 user(身份不变),清除动态上下文
97
+ */
98
+ clearConversation() {
99
+ this.currentHost = null;
100
+ this.activeConnections.clear();
101
+ this.activeSkill = null;
102
+ this.skillPhase = null;
103
+ this.conversationTurns = 0;
104
+ }
105
+ /**
106
+ * 生成 system prompt 注入段落
107
+ *
108
+ * 无状态时返回空字符串(不污染 prompt)。
109
+ * 有状态时返回 "## 当前会话上下文" 段落。
110
+ */
111
+ toPromptSection() {
112
+ const lines = [];
113
+ if (this.currentHost) {
114
+ lines.push(`当前 SSH 主机:${this.currentHost}`);
115
+ if (this.activeConnections.size > 1) {
116
+ const hosts = Array.from(this.activeConnections).join(', ');
117
+ lines.push(`活跃连接:${hosts}`);
118
+ }
119
+ lines.push('用户后续的 SSH 命令如果没有指定 host,应默认使用当前主机。');
120
+ }
121
+ if (this.activeSkill) {
122
+ lines.push(`当前正在执行 Skill:${this.activeSkill}`);
123
+ if (this.skillPhase) {
124
+ lines.push(`执行阶段:${this.skillPhase}`);
125
+ }
126
+ }
127
+ if (this.sshServersHint) {
128
+ lines.push(this.sshServersHint);
129
+ }
130
+ if (lines.length === 0)
131
+ return '';
132
+ return '## 当前会话上下文\n\n' + lines.join('\n');
133
+ }
134
+ }
135
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/agent/session.ts"],"names":[],"mappings":"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"}