neoctl 0.2.40 → 0.2.42
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 +43 -585
- package/dist/context/prompts.js +2 -1
- package/dist/context/prompts.js.map +1 -1
- package/dist/core/run-agent.js +2 -0
- package/dist/core/run-agent.js.map +1 -1
- package/dist/repl/index.js +13 -1
- package/dist/repl/index.js.map +1 -1
- package/dist/tools/builtins/image-capabilities.d.ts +21 -0
- package/dist/tools/builtins/image-capabilities.js +97 -0
- package/dist/tools/builtins/image-capabilities.js.map +1 -0
- package/dist/tools/builtins/image-generation-tool.d.ts +14 -7
- package/dist/tools/builtins/image-generation-tool.js +141 -143
- package/dist/tools/builtins/image-generation-tool.js.map +1 -1
- package/dist/tools/builtins/image-output-verification.d.ts +14 -0
- package/dist/tools/builtins/image-output-verification.js +183 -0
- package/dist/tools/builtins/image-output-verification.js.map +1 -0
- package/dist/tools/registry.d.ts +2 -0
- package/dist/tools/registry.js +6 -0
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/run-tool-use.js +5 -0
- package/dist/tools/run-tool-use.js.map +1 -1
- package/dist/web/image-result-metadata.d.ts +20 -0
- package/dist/web/image-result-metadata.js +20 -0
- package/dist/web/image-result-metadata.js.map +1 -0
- package/dist/web/index.d.ts +4 -1
- package/dist/web/index.js +20 -5
- package/dist/web/index.js.map +1 -1
- package/docs/prompt-config.md +1 -1
- package/package.json +22 -20
- package/dist/agents/agent-report-security.test.d.ts +0 -1
- package/dist/agents/agent-report-security.test.js +0 -301
- package/dist/agents/agent-report-security.test.js.map +0 -1
- package/dist/agents/agent-tool-persistence.test.d.ts +0 -1
- package/dist/agents/agent-tool-persistence.test.js +0 -319
- package/dist/agents/agent-tool-persistence.test.js.map +0 -1
- package/dist/agents/coordination-boundary.test.d.ts +0 -1
- package/dist/agents/coordination-boundary.test.js +0 -58
- package/dist/agents/coordination-boundary.test.js.map +0 -1
- package/dist/agents/live-preview-redaction-security.test.d.ts +0 -1
- package/dist/agents/live-preview-redaction-security.test.js +0 -286
- package/dist/agents/live-preview-redaction-security.test.js.map +0 -1
- package/dist/agents/no-nested-delegation.test.d.ts +0 -1
- package/dist/agents/no-nested-delegation.test.js +0 -38
- package/dist/agents/no-nested-delegation.test.js.map +0 -1
- package/dist/agents/obs07-11-run-facts.test.d.ts +0 -1
- package/dist/agents/obs07-11-run-facts.test.js +0 -459
- package/dist/agents/obs07-11-run-facts.test.js.map +0 -1
- package/dist/agents/smoke-agent-lifecycle.d.ts +0 -1
- package/dist/agents/smoke-agent-lifecycle.js +0 -192
- package/dist/agents/smoke-agent-lifecycle.js.map +0 -1
- package/dist/agents/smoke-agents.d.ts +0 -1
- package/dist/agents/smoke-agents.js +0 -362
- package/dist/agents/smoke-agents.js.map +0 -1
- package/dist/context/prompt-config.test.d.ts +0 -1
- package/dist/context/prompt-config.test.js +0 -128
- package/dist/context/prompt-config.test.js.map +0 -1
- package/dist/context/smoke-context.d.ts +0 -1
- package/dist/context/smoke-context.js +0 -502
- package/dist/context/smoke-context.js.map +0 -1
- package/dist/core/obs04-visible-data.test.d.ts +0 -1
- package/dist/core/obs04-visible-data.test.js +0 -147
- package/dist/core/obs04-visible-data.test.js.map +0 -1
- package/dist/core/query-session-settings.test.d.ts +0 -1
- package/dist/core/query-session-settings.test.js +0 -252
- package/dist/core/query-session-settings.test.js.map +0 -1
- package/dist/core/run-agent-pause.test.d.ts +0 -1
- package/dist/core/run-agent-pause.test.js +0 -52
- package/dist/core/run-agent-pause.test.js.map +0 -1
- package/dist/core/run-agent-persistence.test.d.ts +0 -1
- package/dist/core/run-agent-persistence.test.js +0 -222
- package/dist/core/run-agent-persistence.test.js.map +0 -1
- package/dist/core/session-prompt-inheritance.test.d.ts +0 -1
- package/dist/core/session-prompt-inheritance.test.js +0 -132
- package/dist/core/session-prompt-inheritance.test.js.map +0 -1
- package/dist/core/session-settings-prompt.test.d.ts +0 -1
- package/dist/core/session-settings-prompt.test.js +0 -266
- package/dist/core/session-settings-prompt.test.js.map +0 -1
- package/dist/core/smoke-core-loop.d.ts +0 -1
- package/dist/core/smoke-core-loop.js +0 -290
- package/dist/core/smoke-core-loop.js.map +0 -1
- package/dist/core/smoke-image-integrity.d.ts +0 -1
- package/dist/core/smoke-image-integrity.js +0 -67
- package/dist/core/smoke-image-integrity.js.map +0 -1
- package/dist/execution/docker.test.d.ts +0 -1
- package/dist/execution/docker.test.js +0 -57
- package/dist/execution/docker.test.js.map +0 -1
- package/dist/model/openai-native-image-guard.test.d.ts +0 -1
- package/dist/model/openai-native-image-guard.test.js +0 -101
- package/dist/model/openai-native-image-guard.test.js.map +0 -1
- package/dist/model/openai-responses-instructions.test.d.ts +0 -1
- package/dist/model/openai-responses-instructions.test.js +0 -64
- package/dist/model/openai-responses-instructions.test.js.map +0 -1
- package/dist/model/smoke-openai.d.ts +0 -1
- package/dist/model/smoke-openai.js +0 -44
- package/dist/model/smoke-openai.js.map +0 -1
- package/dist/model/smoke-responses-mapper.d.ts +0 -1
- package/dist/model/smoke-responses-mapper.js +0 -156
- package/dist/model/smoke-responses-mapper.js.map +0 -1
- package/dist/plugins/smoke-plugin-system.d.ts +0 -1
- package/dist/plugins/smoke-plugin-system.js +0 -63
- package/dist/plugins/smoke-plugin-system.js.map +0 -1
- package/dist/repl/smoke-run-command.d.ts +0 -1
- package/dist/repl/smoke-run-command.js +0 -43
- package/dist/repl/smoke-run-command.js.map +0 -1
- package/dist/secrets/smoke-secrets.d.ts +0 -1
- package/dist/secrets/smoke-secrets.js +0 -73
- package/dist/secrets/smoke-secrets.js.map +0 -1
- package/dist/session/session-store-safety.test.d.ts +0 -1
- package/dist/session/session-store-safety.test.js +0 -107
- package/dist/session/session-store-safety.test.js.map +0 -1
- package/dist/session/smoke-session.d.ts +0 -1
- package/dist/session/smoke-session.js +0 -233
- package/dist/session/smoke-session.js.map +0 -1
- package/dist/skills/smoke-skills.d.ts +0 -1
- package/dist/skills/smoke-skills.js +0 -109
- package/dist/skills/smoke-skills.js.map +0 -1
- package/dist/tasks/subagent-tools.test.d.ts +0 -1
- package/dist/tasks/subagent-tools.test.js +0 -159
- package/dist/tasks/subagent-tools.test.js.map +0 -1
- package/dist/tasks/task-ack-size.test.d.ts +0 -1
- package/dist/tasks/task-ack-size.test.js +0 -101
- package/dist/tasks/task-ack-size.test.js.map +0 -1
- package/dist/tasks/task-persistence.test.d.ts +0 -1
- package/dist/tasks/task-persistence.test.js +0 -331
- package/dist/tasks/task-persistence.test.js.map +0 -1
- package/dist/tools/smoke-exec-process.d.ts +0 -1
- package/dist/tools/smoke-exec-process.js +0 -127
- package/dist/tools/smoke-exec-process.js.map +0 -1
- package/dist/tools/smoke-terminal-output-chain.d.ts +0 -1
- package/dist/tools/smoke-terminal-output-chain.js +0 -245
- package/dist/tools/smoke-terminal-output-chain.js.map +0 -1
- package/dist/tools/smoke-tool-system.d.ts +0 -1
- package/dist/tools/smoke-tool-system.js +0 -412
- package/dist/tools/smoke-tool-system.js.map +0 -1
- package/dist/tools/terminal-background-history.test.d.ts +0 -1
- package/dist/tools/terminal-background-history.test.js +0 -77
- package/dist/tools/terminal-background-history.test.js.map +0 -1
- package/dist/tools/terminal-output-persistence.test.d.ts +0 -1
- package/dist/tools/terminal-output-persistence.test.js +0 -50
- package/dist/tools/terminal-output-persistence.test.js.map +0 -1
- package/dist/tools/terminal-output-store.test.d.ts +0 -1
- package/dist/tools/terminal-output-store.test.js +0 -364
- package/dist/tools/terminal-output-store.test.js.map +0 -1
- package/dist/web/agent-content-detail.test.d.ts +0 -1
- package/dist/web/agent-content-detail.test.js +0 -307
- package/dist/web/agent-content-detail.test.js.map +0 -1
- package/dist/web/agent-parent-messages.test.d.ts +0 -1
- package/dist/web/agent-parent-messages.test.js +0 -58
- package/dist/web/agent-parent-messages.test.js.map +0 -1
- package/dist/web/agent-tool-payload-security.test.d.ts +0 -1
- package/dist/web/agent-tool-payload-security.test.js +0 -120
- package/dist/web/agent-tool-payload-security.test.js.map +0 -1
- package/dist/web/prompt-config-protocol.test.d.ts +0 -1
- package/dist/web/prompt-config-protocol.test.js +0 -78
- package/dist/web/prompt-config-protocol.test.js.map +0 -1
- package/dist/web/session-prompt-integration.test.d.ts +0 -1
- package/dist/web/session-prompt-integration.test.js +0 -57
- package/dist/web/session-prompt-integration.test.js.map +0 -1
- package/dist/web/session-settings.test.d.ts +0 -1
- package/dist/web/session-settings.test.js +0 -254
- package/dist/web/session-settings.test.js.map +0 -1
- package/dist/web/smoke-agent-content-http.d.ts +0 -1
- package/dist/web/smoke-agent-content-http.js +0 -446
- package/dist/web/smoke-agent-content-http.js.map +0 -1
- package/dist/web/smoke-plan-payload.d.ts +0 -1
- package/dist/web/smoke-plan-payload.js +0 -30
- package/dist/web/smoke-plan-payload.js.map +0 -1
- package/dist/web/smoke-runtime-context-protocol.d.ts +0 -1
- package/dist/web/smoke-runtime-context-protocol.js +0 -42
- package/dist/web/smoke-runtime-context-protocol.js.map +0 -1
- package/dist/web/smoke-status-semantics.d.ts +0 -1
- package/dist/web/smoke-status-semantics.js +0 -90
- package/dist/web/smoke-status-semantics.js.map +0 -1
- package/dist/web/smoke-task-session-entrypoints.d.ts +0 -1
- package/dist/web/smoke-task-session-entrypoints.js +0 -96
- package/dist/web/smoke-task-session-entrypoints.js.map +0 -1
- package/dist/web/smoke-terminal-output-http.d.ts +0 -1
- package/dist/web/smoke-terminal-output-http.js +0 -377
- package/dist/web/smoke-terminal-output-http.js.map +0 -1
- package/dist/web/smoke-tool-call-detail.d.ts +0 -1
- package/dist/web/smoke-tool-call-detail.js +0 -106
- package/dist/web/smoke-tool-call-detail.js.map +0 -1
- package/dist/web/smoke-tool-call-http.d.ts +0 -1
- package/dist/web/smoke-tool-call-http.js +0 -100
- package/dist/web/smoke-tool-call-http.js.map +0 -1
- package/dist/web/smoke-tool-detail-fields-http.d.ts +0 -1
- package/dist/web/smoke-tool-detail-fields-http.js +0 -121
- package/dist/web/smoke-tool-detail-fields-http.js.map +0 -1
- package/dist/web/smoke-web-agent-tasks.d.ts +0 -1
- package/dist/web/smoke-web-agent-tasks.js +0 -50
- package/dist/web/smoke-web-agent-tasks.js.map +0 -1
- package/dist/web/smoke-web-history.d.ts +0 -1
- package/dist/web/smoke-web-history.js +0 -183
- package/dist/web/smoke-web-history.js.map +0 -1
- package/dist/web/smoke-web-queue.d.ts +0 -1
- package/dist/web/smoke-web-queue.js +0 -7
- package/dist/web/smoke-web-queue.js.map +0 -1
- package/dist/web/smoke-web-terminal-tasks.d.ts +0 -1
- package/dist/web/smoke-web-terminal-tasks.js +0 -238
- package/dist/web/smoke-web-terminal-tasks.js.map +0 -1
- package/dist/web/terminal-presentation.test.d.ts +0 -1
- package/dist/web/terminal-presentation.test.js +0 -33
- package/dist/web/terminal-presentation.test.js.map +0 -1
- package/dist/web/tool-detail-fields.test.d.ts +0 -1
- package/dist/web/tool-detail-fields.test.js +0 -121
- package/dist/web/tool-detail-fields.test.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,601 +1,59 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## 特性亮点
|
|
6
|
-
|
|
7
|
-
- **流式多轮 Agent Loop**:模型输出、thinking、工具调用、工具结果和终止状态都通过统一事件流传递。
|
|
8
|
-
- **OpenAI 兼容模型网关**:支持 `/v1/responses` 与 `/v1/chat/completions`,`OPENAI_ENDPOINT=auto` 时会优先尝试 Responses API,并在兼容网关不支持时回退到 Chat Completions。
|
|
9
|
-
- **内置工程工具集**:文件读写、文本替换、命令执行、目录列表、ripgrep 搜索、Web 搜索、计划展示、子代理和后台任务控制。
|
|
10
|
-
- **上下文预算与手动压缩**:在每次模型调用前注入用户/系统上下文、估算上下文占用并预算大型工具结果;默认不自动压缩会话,用户可通过 `/compact` 主动压缩。
|
|
11
|
-
- **会话持久化与恢复**:默认记录 JSONL transcript,大型工具结果落盘保存,支持最近/指定会话恢复和交互式会话浏览;Web 恢复快照只返回图片引用,图片通过独立接口按需加载,避免多图会话被 base64 阻塞。
|
|
12
|
-
- **子代理与后台终端**:同一套 query loop 可运行同步子代理、后台子代理、fork 子代理,并可持续轮询和操作异步终端。
|
|
13
|
-
- **TTY REPL 体验**:Ink UI、slash command 补全、Markdown 渲染、流式状态栏、token 使用统计、剪贴板文本/图片粘贴、会话标题和终端标题更新。
|
|
14
|
-
|
|
15
|
-
## 快速开始
|
|
16
|
-
|
|
17
|
-
要求 Node.js >= 20。
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
npm install
|
|
21
|
-
npm run build
|
|
22
|
-
npm start
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
开发模式:
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
npm run dev
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
构建当前平台的便携可执行分发目录:
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
npm run standalone
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
产物输出到 `standalone/<platform>-<arch>/`,例如 Windows x64 为 `standalone/win32-x64/neo.exe`。该目录内包含内嵌 Node.js 的启动器、`dist/`、`node_modules/` 和当前平台的 `vendor/ripgrep/`,目标机器无需预装 Node.js;分发时请压缩并保留整个目录结构,不要只复制单个 `neo.exe`。
|
|
38
|
-
|
|
39
|
-
推送 `v*` tag 或手动触发 GitHub Actions 的 `Build standalone executables` workflow,会分别生成:
|
|
40
|
-
|
|
41
|
-
- `neo-win32-x64.zip`
|
|
42
|
-
- `neo-linux-x64.tar.gz`
|
|
43
|
-
- `neo-darwin-x64.tar.gz`
|
|
44
|
-
- `neo-darwin-arm64.tar.gz`
|
|
45
|
-
|
|
46
|
-
首次启动会创建用户级配置文件:
|
|
47
|
-
|
|
48
|
-
- Windows:`%APPDATA%\neo\.env`
|
|
49
|
-
- macOS/Linux:`~/.config/neo/.env`
|
|
50
|
-
|
|
51
|
-
可以运行 `/login` 交互式填写并保存,也可以手动编辑。OpenAI 的 key、base URL、model 写在 `OPENAI_*` 下;共享运行参数保留 `MODEL_*`。
|
|
52
|
-
|
|
53
|
-
```env
|
|
54
|
-
# Active provider
|
|
55
|
-
MODEL_PROVIDER=openai
|
|
56
|
-
|
|
57
|
-
# OpenAI provider settings
|
|
58
|
-
OPENAI_API_KEY=your-openai-api-key
|
|
59
|
-
OPENAI_BASE_URL=https://api.openai.com
|
|
60
|
-
OPENAI_MODEL=gpt-5.6
|
|
61
|
-
OPENAI_ENDPOINT=auto
|
|
62
|
-
|
|
63
|
-
# Shared model runtime settings
|
|
64
|
-
MODEL_REASONING_EFFORT=high
|
|
65
|
-
MODEL_REASONING_SUMMARY=auto
|
|
66
|
-
# MODEL_MAX_OUTPUT_TOKENS=32768
|
|
67
|
-
MODEL_TIMEOUT_MS=120000
|
|
68
|
-
MODEL_STREAM_IDLE_TIMEOUT_MS=120000
|
|
69
|
-
MODEL_MAX_RETRIES=2
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
也可以在当前工作目录放 `.env`,或通过 `NEO_ENV_FILE=/path/to/.env` 指定配置文件。加载顺序是:当前目录 `.env` → 用户级 `.env` → `NEO_ENV_FILE`,后者优先级最高。
|
|
73
|
-
|
|
74
|
-
## 常用命令
|
|
75
|
-
|
|
76
|
-
```bash
|
|
77
|
-
npm run typecheck # TypeScript 类型检查
|
|
78
|
-
npm run build # 编译到 dist,并复制模型元数据
|
|
79
|
-
npm run vendor:rg # 显式补齐当前平台的 ripgrep 到 vendor/ripgrep
|
|
80
|
-
npm run vendor:rg:all # 显式补齐全部支持平台的 ripgrep
|
|
81
|
-
npm run verify:rg # 校验六个平台资源完整且已由 Git 跟踪
|
|
82
|
-
npm run standalone # 构建当前平台的便携可执行分发目录
|
|
83
|
-
npm run standalone:clean # 清理 standalone 构建产物
|
|
84
|
-
npm run smoke:core # 核心 query loop 冒烟测试
|
|
85
|
-
npm run smoke:tools # 工具体系冒烟测试
|
|
86
|
-
npm run smoke:context # 上下文和压缩冒烟测试
|
|
87
|
-
npm run smoke:session # 会话持久化冒烟测试
|
|
88
|
-
npm run smoke:agents # 子代理/任务冒烟测试
|
|
89
|
-
npm run smoke:skills # skill 模块冒烟测试
|
|
90
|
-
npm run smoke:responses # OpenAI Responses mapper 冒烟测试
|
|
91
|
-
npm run smoke:openai -- "Say pong"
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
六个支持平台的 `vendor/ripgrep/<platform>-<arch>/rg[.exe]`、manifest 和许可证文件都是不可缺失的发布资源,并全部由 Git 纳管。`postinstall` 会校验安装包内资源,`prepack` 还会校验 Git 跟踪状态;缺失、空文件、格式错误或未纳管都会直接导致安装/发布失败。`vendor:rg` 仅用于显式补齐资源,网络受限时可临时设置 HTTP/HTTPS 代理后执行。
|
|
95
|
-
|
|
96
|
-
`postinstall` 还会运行 `scripts/patch-ink-clear-terminal.cjs`,对 Ink 的满屏重绘逻辑做一个本地兼容 patch:Ink 在动态输出高度达到终端高度时原本会调用 `ansiEscapes.clearTerminal`,该序列在现代终端中包含 `ESC[3J`,会清空 scrollback buffer,导致 TTY REPL 在长 Markdown 输出或子代理活动期间出现“滚动条冲顶/归零”的现象。patch 会把该分支替换为只清可见屏幕的 `ESC[2J ESC[H`,保留终端 scrollback。升级 Ink 后如果脚本提示找不到预期代码,需要重新检查 `node_modules/ink/build/ink.js` 的满屏渲染分支。
|
|
97
|
-
|
|
98
|
-
## REPL 用法
|
|
99
|
-
|
|
100
|
-
启动后直接输入自然语言任务即可。命令行参数也可用 `-`/`--` 形式调用同名 REPL slash command:
|
|
101
|
-
|
|
102
|
-
```bash
|
|
103
|
-
neo -help
|
|
104
|
-
neo run "总结当前仓库"
|
|
105
|
-
echo "检查当前改动" | neo run --json
|
|
106
|
-
neo -web
|
|
107
|
-
neo -web --port 3001
|
|
108
|
-
neo -model
|
|
109
|
-
neo -model gpt-5.6 high
|
|
110
|
-
neo -new
|
|
111
|
-
```
|
|
1
|
+
# Neo Engine
|
|
2
|
+
|
|
3
|
+
Neo 的 TypeScript 核心运行时,提供 `neo` 命令行、模型调用、工具执行、会话管理和子代理任务。Web 和 Desktop 共用这套核心。
|
|
112
4
|
|
|
113
|
-
|
|
5
|
+
子代理调度及管理工具(`subagent_run/output/list/get/stop/message/resume`)默认关闭:未配置时不会向模型暴露,也不能通过工具别名调用。Web/Desktop 可在工具设置中显式开启,会话设置可覆盖全局设置;已有明确保存的设置保留。SDK 使用者可通过 `ToolRegistry.setEnabled(name, true)` 显式开启。子代理内部的 `subagent_report` 汇报通道不受此默认开关影响。
|
|
114
6
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
除 `-help` 会直接打印帮助并退出、`-web` 会启动 Web UI 外,其它命令会启动 REPL 并执行对应内部命令,例如 `neo -model` 等同于进入 REPL 后输入 `/model`。
|
|
118
|
-
|
|
119
|
-
常用 slash commands:
|
|
120
|
-
|
|
121
|
-
| 命令 | 作用 |
|
|
122
|
-
| --- | --- |
|
|
123
|
-
| `/help` | 显示命令列表 |
|
|
124
|
-
| `/model` | 查看当前模型和 reasoning 设置 |
|
|
125
|
-
| `/model <model-id>` | 切换模型 |
|
|
126
|
-
| `/model <model-id> <effort>` | 切换模型并设置 reasoning effort |
|
|
127
|
-
| `/model <effort>` | 只切换 reasoning effort |
|
|
128
|
-
| `/login` | 交互式选择供应者、编辑配置并保存到 env 文件 |
|
|
129
|
-
| `/cost` | 查看当前 REPL 会话累计 token 使用量 |
|
|
130
|
-
| `/compact` | 手动压缩早期上下文 |
|
|
131
|
-
| `/pure` | 在风险/WAF 阻断后清理上下文但不重置会话 |
|
|
132
|
-
| `/sessions` | 打开会话浏览器 |
|
|
133
|
-
| `/state` | 查看 query engine 状态与通信日志状态 |
|
|
134
|
-
| `/log <absolute-dir>` | 将模型通信日志写入指定绝对目录 |
|
|
135
|
-
| `/log off` | 关闭模型通信日志 |
|
|
136
|
-
| `/reset` | 清空当前历史,并在 transcript 中写入 reset marker |
|
|
137
|
-
| `/exit` / `/quit` | 退出 |
|
|
138
|
-
|
|
139
|
-
交互细节:
|
|
140
|
-
|
|
141
|
-
- `Tab` 可补全 slash command。
|
|
142
|
-
- 上/下方向键可浏览输入历史,也可在补全面板中移动选择。
|
|
143
|
-
- `/sessions` 中使用上/下选择,会话多页时左/右或 PageUp/PageDown 翻页,Enter 恢复,Esc 关闭,`d`/Delete/Backspace 删除选中的非活跃会话。
|
|
144
|
-
- `Ctrl+V` / `Cmd+V` 或右键粘贴会读取系统剪贴板;长文本会以附件形式折叠,图片会作为 image block 发送给支持图片输入的模型。
|
|
145
|
-
- 空输入时第一次 `Ctrl+C` 会尝试中断当前任务或提示再次退出,第二次退出;有输入内容时 `Ctrl+C` 清空输入。
|
|
146
|
-
|
|
147
|
-
## 架构概览
|
|
148
|
-
|
|
149
|
-
```text
|
|
150
|
-
src/
|
|
151
|
-
repl/ Ink 终端 UI、输入编辑、slash commands、剪贴板、会话浏览
|
|
152
|
-
core/ QueryEngine、多轮 query loop、消息管线、事件流、子代理 runner
|
|
153
|
-
model/ 模型网关、OpenAI adapter、HTTP/SSE、重试、错误归一化、模型元数据
|
|
154
|
-
tools/ Tool 接口、注册表、schema 校验、执行编排、内置工具
|
|
155
|
-
context/ system prompt、用户/系统上下文、上下文指标、压缩器
|
|
156
|
-
session/ JSONL transcript、会话列表/恢复、大型工具结果落盘
|
|
157
|
-
agents/ AgentTool、AgentDefinition、本地后台任务输出
|
|
158
|
-
tasks/ TaskStore、TaskOutput/TaskList/TaskGet/TaskStop/TaskResume/SendMessage
|
|
159
|
-
skills/ 可复用 prompt workflow 的 SkillTool 与内存 catalog
|
|
160
|
-
app/ AppState port 和内存实现
|
|
161
|
-
safety/ permission / sandbox / audit 的接口边界
|
|
162
|
-
types/ message 与 event 类型
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
### 运行主线
|
|
166
|
-
|
|
167
|
-
`QueryEngine` 是 REPL 与核心 loop 之间的状态封装:
|
|
168
|
-
|
|
169
|
-
1. 接收用户输入并追加到历史。
|
|
170
|
-
2. 记录 session transcript。
|
|
171
|
-
3. 生成一次 system init message,用于展示本轮可用工具、模型、命令等信息。
|
|
172
|
-
4. 调用 `query()` 进入流式多轮循环。
|
|
173
|
-
5. 将模型消息、工具结果、压缩边界和终止状态持续写回历史与 transcript。
|
|
174
|
-
|
|
175
|
-
`query()` 的每轮流程:
|
|
176
|
-
|
|
177
|
-
1. 构建 runtime context:system prompt、user context、system context。
|
|
178
|
-
2. 根据 compact boundary 选择参与模型调用的消息。
|
|
179
|
-
3. 对大型工具结果做预算处理;启用 session 时会将超大结果写到 `.agent/sessions/<session>/tool-results/` 并用预览替换。
|
|
180
|
-
4. 修复缺失的 tool_use/tool_result 配对,避免模型 API 拒绝历史。
|
|
181
|
-
5. 估算 context metrics;默认不按预算自动压缩。
|
|
182
|
-
6. 流式调用模型网关。
|
|
183
|
-
7. 收集 assistant 文本、thinking、tool_use 和 usage。
|
|
184
|
-
8. 如有工具调用,按并发安全规则执行工具,把 tool_result 放入下一轮。
|
|
185
|
-
9. 无工具调用时结束;如果因输出 token 达限且没有工具调用,会尝试提高输出预算继续。
|
|
186
|
-
10. 遇到 context length 错误时直接返回模型错误,不自动改写历史或压缩后重试。
|
|
187
|
-
|
|
188
|
-
事件类型定义在 `src/types/events.ts`,包括 `state`、`context.metrics`、`assistant.delta`、`thinking.delta`、`tool.started`、`tool.finished`、`usage`、`terminal` 等。
|
|
189
|
-
|
|
190
|
-
## 模型层
|
|
191
|
-
|
|
192
|
-
模型访问通过 `ModelGateway` 抽象。当前内置 provider 为 OpenAI:
|
|
193
|
-
|
|
194
|
-
- `openai-adapter.ts`:端点选择、认证、超时、重试、Responses→Chat fallback。
|
|
195
|
-
- `openai-responses-mapper.ts`:Responses API 请求和流事件归一化。
|
|
196
|
-
- `openai-chat-mapper.ts`:Chat Completions 请求和流事件归一化。
|
|
197
|
-
- `http-transport.ts` / `sse-decoder.ts`:HTTP 请求与 SSE 流解析。
|
|
198
|
-
- `errors.ts`:将 provider 错误归一为 `ModelAPIError` 分类。
|
|
199
|
-
- `context-window.ts` + `model-metadata.json`:静态模型元数据,用于 context window、reasoning effort 和图片输入能力判断。
|
|
200
|
-
|
|
201
|
-
支持的配置变量:
|
|
202
|
-
|
|
203
|
-
| 变量 | 说明 |
|
|
204
|
-
| --- | --- |
|
|
205
|
-
| `MODEL_PROVIDER` | `openai` |
|
|
206
|
-
| `OPENAI_API_KEY` | OpenAI API Key |
|
|
207
|
-
| `OPENAI_BASE_URL` | OpenAI 服务地址,默认 `https://api.openai.com` |
|
|
208
|
-
| `OPENAI_MODEL` | 默认模型,默认为 `gpt-5.6` |
|
|
209
|
-
| `OPENAI_ENDPOINT` | `responses`、`chat` 或 `auto` |
|
|
210
|
-
| `MODEL_REASONING_EFFORT` | 共享运行设置:`none`、`minimal`、`low`、`medium`、`high`、`xhigh`、`max` |
|
|
211
|
-
| `MODEL_REASONING_SUMMARY` | `auto`、`concise`、`detailed` |
|
|
212
|
-
| `MODEL_MAX_OUTPUT_TOKENS` | 可选的最大输出 token;未设置时采用 API/模型默认值 |
|
|
213
|
-
| `MODEL_CONTEXT_WINDOW_TOKENS` | 覆盖模型上下文窗口估算 |
|
|
214
|
-
| `MODEL_TIMEOUT_MS` | 请求超时 |
|
|
215
|
-
| `MODEL_STREAM_IDLE_TIMEOUT_MS` | 流式响应空闲超时 |
|
|
216
|
-
| `MODEL_MAX_RETRIES` | provider 重试次数 |
|
|
217
|
-
|
|
218
|
-
## 工具体系
|
|
219
|
-
|
|
220
|
-
工具实现统一遵循 `Tool<TInput>` 接口,包含:
|
|
221
|
-
|
|
222
|
-
- 名称与 alias。
|
|
223
|
-
- JSON Schema 输入定义。
|
|
224
|
-
- 元数据:是否只读、是否可并发、是否可见、最大结果大小等。
|
|
225
|
-
- 输入 normalize 与自定义校验。
|
|
226
|
-
- 权限决策入口 `canUseTool`。
|
|
227
|
-
- 执行函数 `call()` / `execute()`。
|
|
228
|
-
- 结果映射、进度消息渲染、上下文修改器。
|
|
229
|
-
|
|
230
|
-
`ToolRegistry` 负责注册和按 prompt cache 友好顺序输出工具定义;`runToolUse()` 负责 schema 校验、权限检查、进度事件、执行、结果映射和异常转 tool_result;`runTools()` 会把同一轮模型产生的工具调用按并发安全性分批执行。默认并发上限为 10,可用 `AGENT_MAX_TOOL_USE_CONCURRENCY` 调整。
|
|
231
|
-
|
|
232
|
-
REPL 当前注册的内置工具:
|
|
233
|
-
|
|
234
|
-
| 工具 | 作用 |
|
|
235
|
-
| --- | --- |
|
|
236
|
-
| `echo` | 返回输入文本,主要用于测试链路 |
|
|
237
|
-
| `read` / `view` | 按行范围读取文本文件 |
|
|
238
|
-
| `list` | 列目录,支持递归、隐藏文件、深度、排除项和数量限制 |
|
|
239
|
-
| `grep` | 通过 bundled ripgrep 搜索工作区文本 |
|
|
240
|
-
| `write` | 创建或覆盖文本文件 |
|
|
241
|
-
| `edit` / `replace` | 基于唯一字符串替换修改文件,容忍 LF/CRLF 和直/弯引号差异 |
|
|
242
|
-
| `exec_command` | 创建可持续交互的异步终端 |
|
|
243
|
-
| `write_stdin` | 轮询终端增量输出、写入字符、中断或终止后台终端 |
|
|
244
|
-
| `search` | 通过可插拔 provider 搜索 Web;OpenAI 模型提供者默认走 GPT web search,否则默认 Exa MCP;可显式切换 provider |
|
|
245
|
-
| `image2` | 仅在 `MODEL_PROVIDER=openai` 时注册;通过 OpenAI Images API 生成图片并返回可展示的 data URL;非 OpenAI provider 不暴露绘图工具,系统提示会要求模型说明当前不具备绘图能力 |
|
|
246
|
-
| `plan` | 输出和更新当前任务计划 |
|
|
247
|
-
| `agent` | 启动同步/后台/fork 子代理 |
|
|
248
|
-
| `TaskOutput` | 读取后台任务输出,可阻塞等待完成 |
|
|
249
|
-
| `TaskList` | 列出后台任务 |
|
|
250
|
-
| `TaskGet` | 查看单个后台任务详情 |
|
|
251
|
-
| `TaskStop` | 停止后台任务 |
|
|
252
|
-
| `TaskResume` | 以新指令恢复已结束/失败/停止的后台 agent 任务 |
|
|
253
|
-
| `SendMessage` | 给命名后台 agent 排队消息 |
|
|
254
|
-
|
|
255
|
-
### 文件与搜索
|
|
256
|
-
|
|
257
|
-
- `read` 对大文件使用 offset/limit 分段读取,避免一次性塞满上下文。
|
|
258
|
-
- `list` 默认跳过 `.git`、`node_modules`、`dist`、`build`、`coverage` 等重目录。
|
|
259
|
-
- `grep` 不依赖系统 PATH,会调用 `vendor/ripgrep` 中的平台二进制;支持 glob、大小写模式、fixed strings、隐藏文件、上下文行、结果数和列宽限制。
|
|
260
|
-
- `search` 默认使用 OpenAI Responses API 的 `web_search`,URL、Key 和模型分别继承 `OPENAI_SEARCH_*`,未单独配置时继承 `OPENAI_*`。Base URL 会同时兼容带 `/v1` 和不带 `/v1` 的写法。只有 OpenAI 搜索不可用或对部分查询不可用时,模型才切换到 Exa 官方 `https://mcp.exa.ai/mcp` 的 `web_search_exa`。OpenAI 搜索可通过 `OPENAI_SEARCH_API_KEY`、`OPENAI_SEARCH_BASE_URL`、`OPENAI_SEARCH_MODEL`、`OPENAI_SEARCH_TOOL_TYPE`、`OPENAI_SEARCH_CONTEXT_SIZE` 配置;Exa 可通过 `EXA_MCP_URL`、`EXA_MCP_TOOL_NAME` 配置;两者超时可用 `SEARCH_TIMEOUT_MS` 配置。
|
|
261
|
-
- `image2` 按 OpenAI 图片生成官方接口实现,底层请求 `POST /v1/images/generations`;底层 OpenAI 图片模型只允许 `gpt-image-2`,默认也是 `gpt-image-2`。可用 `OPENAI_IMAGE_API_KEY` / `OPENAI_API_KEY`、`OPENAI_IMAGE_BASE_URL` / `OPENAI_BASE_URL`、`OPENAI_IMAGE_MODEL`、`OPENAI_IMAGE_TIMEOUT_MS` 配置,其中 `OPENAI_IMAGE_MODEL` 若不是 `gpt-image-2` 会被 image2 校验拒绝。只有 `MODEL_PROVIDER=openai` 时 REPL/Web 运行时会注册该工具;切换到 Anthropic 等其他 provider 后会移除该工具,并在系统提示中要求模型告知用户当前模型/供应者不具备绘图工具。
|
|
262
|
-
|
|
263
|
-
### 命令执行
|
|
264
|
-
|
|
265
|
-
`exec_command` 根据平台和 `shell` 参数选择 PowerShell、cmd、bash 或 sh。命令启动后持续收集输出;首次等待期内结束则直接返回,仍在运行则返回 `session_id`,进程不会依赖当前模型轮次存活。`timeout_ms` 约束命令进入后台前的前台阶段;一旦命令让出成为后台终端,超时计时器会被清除,任务将持续运行到自行退出、显式停止或宿主进程关闭。
|
|
7
|
+
## 安装使用
|
|
266
8
|
|
|
267
|
-
|
|
268
|
-
- `timeout_ms`:命令进入后台前的前台阶段超时上限;后台任务不设自动超时。
|
|
269
|
-
- `yield_time_ms`:首次等待时间;到期后将仍在运行的命令交还为后台终端。
|
|
270
|
-
- `max_output_chars`:分别限制每次待读取的 stdout/stderr,超限时保留开头和结尾。
|
|
271
|
-
- `tty=true`:通过 PTY/ConPTY 运行需要真实终端语义的交互程序。
|
|
9
|
+
需要 Node.js 20+。
|
|
272
10
|
|
|
273
|
-
|
|
11
|
+
```sh
|
|
12
|
+
npm install -g neoctl
|
|
13
|
+
neo
|
|
14
|
+
```
|
|
274
15
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
## 上下文与压缩
|
|
278
|
-
|
|
279
|
-
`DefaultContextManager` 每轮构建两类上下文:
|
|
280
|
-
|
|
281
|
-
- **User context**:当前日期,以及项目记忆文件内容。默认读取 `AGENTS.md`、`CLAUDE.md`、`.agent/memory.md`、`.codex/memory.md`、`.github/copilot-instructions.md`。
|
|
282
|
-
- **System context**:cwd、platform、git branch、recent commit、status。
|
|
283
|
-
|
|
284
|
-
`prompts.ts` 将 system prompt 分为可缓存稳定段和动态段,中间使用 `__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__` 标记。`message-pipeline.ts` 在模型调用前把 user context 作为用户消息 prepend,并把 system context append 到 system prompt。
|
|
285
|
-
|
|
286
|
-
压缩实现位于 `src/context/compaction.ts`:
|
|
287
|
-
|
|
288
|
-
- `DeterministicCompactor` 提供可预测的 snip、microcompact、summary fallback。
|
|
289
|
-
- 默认运行时使用 `ModelDrivenCompactor`:达到上下文窗口阈值时主动压缩,模型返回上下文超限错误时执行响应式压缩并重试;如需仅允许手动压缩,可显式注入 `ManualOnlyCompactor`。
|
|
290
|
-
- 当工具结果过大时,session 模式下 `FileToolResultMemory` 会把完整结果写入文件,仅把预览和路径留在上下文中。
|
|
291
|
-
|
|
292
|
-
## 会话持久化
|
|
293
|
-
|
|
294
|
-
默认启用 transcript,位置为:
|
|
295
|
-
|
|
296
|
-
```text
|
|
297
|
-
.agent/sessions/<session_id>/transcript.jsonl
|
|
298
|
-
.agent/sessions/<session_id>/tool-results/*
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
会话记录包括用户/助手/工具消息、内容替换记录、title、compact marker 和 reset marker。`/reset` 不删除文件,而是写入 reset marker,使未来 resume 从 reset 后继续。
|
|
302
|
-
|
|
303
|
-
相关环境变量:
|
|
304
|
-
|
|
305
|
-
| 变量 | 作用 |
|
|
306
|
-
| --- | --- |
|
|
307
|
-
| `AGENT_SESSION_TRANSCRIPT=0` | 禁用 transcript |
|
|
308
|
-
| `AGENT_SESSION_DIR=<dir>` | 修改 session 根目录 |
|
|
309
|
-
| `AGENT_SESSION_RESUME=1` | 启动时恢复最近会话 |
|
|
310
|
-
| `AGENT_SESSION_ID=<id>` | 指定 session id;配合 resume 恢复指定会话 |
|
|
311
|
-
| `AGENT_SESSION_TITLE_DELAY_MS` | 会话标题生成延迟,默认 5000ms |
|
|
312
|
-
| `AGENT_TOOL_RESULT_THRESHOLD_CHARS` | 大型工具结果落盘阈值 |
|
|
313
|
-
|
|
314
|
-
每次用户输入后,`QueryEngine` 会延迟启动一个无工具的标题子代理:先生成初始短标题,后续在已有标题基础上进行一次 refinement。标题用于 `/sessions` 列表和终端标题。
|
|
315
|
-
|
|
316
|
-
## 子代理与任务
|
|
317
|
-
|
|
318
|
-
`agent` 工具通过 `runAgent()` 复用主 query loop,但使用独立的消息、上下文和工具池。子代理定义支持工具 allow/deny、模型覆盖、最大轮数、背景运行、隔离类型和自定义 system prompt。
|
|
319
|
-
|
|
320
|
-
调用模式:
|
|
321
|
-
|
|
322
|
-
- **同步子代理**:默认模式;当前工具调用等待子代理完成后返回最终文本、耗时、token 和工具调用数。
|
|
323
|
-
- **后台子代理**:`run_in_background=true` 或 `mode=background`;立即返回 `task_id` 和 output file。
|
|
324
|
-
- **fork 子代理**:`mode=fork`;继承父上下文,但追加反递归和作用域约束。
|
|
325
|
-
- **并行同步子代理**:同一模型轮次中多个 `agent` 调用设置 `parallel=true` 后可被并发批处理。
|
|
326
|
-
|
|
327
|
-
后台任务由 `TaskStore` 管理,完成、失败或停止后会写入:
|
|
328
|
-
|
|
329
|
-
```text
|
|
330
|
-
.agent-tasks/<task_id>.txt
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
控制工具:
|
|
334
|
-
|
|
335
|
-
- `TaskList()`:列任务。
|
|
336
|
-
- `TaskGet({ task_id })`:查详情。
|
|
337
|
-
- `TaskOutput({ task_id, block, timeout_ms })`:读输出,可等待完成。
|
|
338
|
-
- `TaskStop({ task_id })`:停止任务。
|
|
339
|
-
- `TaskResume({ task_id, directive })`:带新指令恢复任务。
|
|
340
|
-
- `SendMessage({ target, message })`:向命名或指定 agent id 的后台任务追加待处理消息。
|
|
341
|
-
|
|
342
|
-
子代理相关限制:
|
|
343
|
-
|
|
344
|
-
- `AGENT_SUBAGENT_MAX_TURNS` 可覆盖子代理最大轮数。
|
|
345
|
-
- `AGENT_SUBAGENT_WALL_TIMEOUT_MS` 可设置子代理墙钟超时。
|
|
346
|
-
- fork 子代理不能继续生成更多子代理,避免递归失控。
|
|
347
|
-
|
|
348
|
-
## Skill 模块
|
|
349
|
-
|
|
350
|
-
`src/skills` 提供可复用 prompt workflow 与插件化 catalog。设计参考通用的 `SKILL.md` + frontmatter 目录形态、OpenAI Agents SDK 的 tools / agents-as-tools / guardrails 组合方式,以及 OpenClaw 的多目录、插件目录和 skill gating 思路。默认 REPL 运行时当前未注册 skill catalog,嵌入方可按需装配。
|
|
351
|
-
|
|
352
|
-
核心能力:
|
|
353
|
-
|
|
354
|
-
- `SkillDescriptor` 支持 `version`、`tags`、`inputSchema`、`outputSchema`、`permissions`、`examples`、`trustLevel`、`source` 等插件元数据。
|
|
355
|
-
- `InMemorySkillCatalog` 适合测试和静态注入。
|
|
356
|
-
- `FileSystemSkillCatalog` 支持 `.neo/skills/<skill-name>/SKILL.md` 风格目录,也可合并 workspace、user、plugin、remote mirror 等多个 root。
|
|
357
|
-
- `CompositeSkillCatalog` 可按优先级合并多个 catalog。
|
|
358
|
-
- `createSkillTool()` 会创建 `skill` 调用工具。
|
|
359
|
-
- inline skill 会向下一轮模型注入 meta user message,并可修改主循环模型/effort,同时记录 `activeSkill`。
|
|
360
|
-
- `createSkillAwareCanUseTool()` 可基于 active skill 的 `allowedTools` 做运行期工具 gating。
|
|
361
|
-
- fork skill 会返回 `fork_required`,需要调用方用 AgentTool / 子 agent 编排承接。
|
|
362
|
-
- `createSkillManagementTools()` 提供 `skill_list`、`skill_read`、`skill_validate`、`skill_create`、`skill_update`、`skill_delete`,方便父项目实现 agent 自动生成 skill。
|
|
363
|
-
|
|
364
|
-
`SKILL.md` 示例:
|
|
365
|
-
|
|
366
|
-
```md
|
|
367
|
-
---
|
|
368
|
-
name: review-code
|
|
369
|
-
description: Review code changes for correctness and risk.
|
|
370
|
-
version: 1.0.0
|
|
371
|
-
execution: inline
|
|
372
|
-
allowed-tools:
|
|
373
|
-
- read
|
|
374
|
-
- grep
|
|
375
|
-
tags:
|
|
376
|
-
- code-review
|
|
377
|
-
trust-level: workspace
|
|
378
|
-
---
|
|
379
|
-
|
|
380
|
-
Review the provided changes. Focus on correctness, security, tests, and migration risk.
|
|
381
|
-
Return concise findings with file references when available.
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
父项目装配示例:
|
|
385
|
-
|
|
386
|
-
```ts
|
|
387
|
-
import {
|
|
388
|
-
FileSystemSkillCatalog,
|
|
389
|
-
createSkillTool,
|
|
390
|
-
createSkillManagementTools,
|
|
391
|
-
createSkillAwareCanUseTool,
|
|
392
|
-
} from "neoctl";
|
|
393
|
-
|
|
394
|
-
const skills = new FileSystemSkillCatalog({
|
|
395
|
-
roots: [
|
|
396
|
-
{ root: ".neo/skills", kind: "workspace" },
|
|
397
|
-
{ root: ".neo/plugins/acme/skills", kind: "plugin", plugin: "acme", readonly: true },
|
|
398
|
-
],
|
|
399
|
-
});
|
|
400
|
-
|
|
401
|
-
tools.register(createSkillTool(skills));
|
|
402
|
-
for (const tool of createSkillManagementTools(skills, { requireApproval: true })) tools.register(tool);
|
|
403
|
-
|
|
404
|
-
const canUseTool = createSkillAwareCanUseTool(skills, parentCanUseTool);
|
|
405
|
-
```
|
|
406
|
-
|
|
407
|
-
建议:开放 `skill_create`/`skill_update` 给模型时保持 approval;对 remote/plugin skill 使用只读 root;生产环境使用 `createSkillAwareCanUseTool()` 或父级权限系统强制 `allowedTools`。
|
|
408
|
-
|
|
409
|
-
## 插件协议
|
|
16
|
+
首次使用输入 `/login` 配置模型。常用命令:
|
|
410
17
|
|
|
411
|
-
|
|
18
|
+
```sh
|
|
19
|
+
neo -help # 查看帮助
|
|
20
|
+
neo run "总结当前仓库" # 执行一次任务
|
|
21
|
+
neo -web # 打开核心自带的 Web 界面
|
|
22
|
+
```
|
|
412
23
|
|
|
413
|
-
|
|
24
|
+
对话中可用 `/new` 新建会话、`/sessions` 查看历史、`/compact` 压缩上下文。
|
|
414
25
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
26
|
+
## 模型配置
|
|
27
|
+
|
|
28
|
+
支持 OpenAI 兼容的 Responses 和 Chat Completions 接口。除交互配置外,也可在工作目录的 `.env` 中填写:
|
|
29
|
+
|
|
30
|
+
```env
|
|
31
|
+
MODEL_PROVIDER=openai
|
|
32
|
+
OPENAI_API_KEY=your-api-key
|
|
33
|
+
OPENAI_BASE_URL=https://api.openai.com
|
|
34
|
+
OPENAI_MODEL=your-model-name
|
|
35
|
+
OPENAI_ENDPOINT=auto
|
|
424
36
|
```
|
|
425
37
|
|
|
426
|
-
|
|
38
|
+
将密钥和模型名替换为实际值。`NEO_ENV_FILE` 可指定其他配置文件。
|
|
427
39
|
|
|
428
|
-
|
|
429
|
-
- `promptSections`: 符合 `PromptSection` 协议的系统提示词段。
|
|
430
|
-
- `route(req, res, url, helpers)`: 由嵌入后台托管的 HTTP 路由处理器。
|
|
40
|
+
## 源码开发
|
|
431
41
|
|
|
432
|
-
|
|
433
|
-
import { loadNeoPlugins } from "neoctl";
|
|
42
|
+
在 `engine/` 目录执行:
|
|
434
43
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
});
|
|
44
|
+
```sh
|
|
45
|
+
npm ci
|
|
46
|
+
npm run dev
|
|
439
47
|
```
|
|
440
48
|
|
|
441
|
-
|
|
49
|
+
| 命令 | 用途 |
|
|
50
|
+
| --- | --- |
|
|
51
|
+
| `npm run build` | 编译源码到 `dist/` |
|
|
52
|
+
| `npm start` | 运行已构建的 CLI |
|
|
53
|
+
| `npm run typecheck` | 检查源码和测试类型 |
|
|
54
|
+
| `npm test` | 运行单元测试 |
|
|
55
|
+
| `npm run standalone` | 构建当前平台的便携分发目录 |
|
|
56
|
+
|
|
57
|
+
源码位于 `src/`,测试位于 `tests/`。便携构建输出到 `standalone/<平台>-<架构>/`。
|
|
442
58
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
包入口会导出核心 agent 编排运行时、模型网关、上下文管理、任务/子代理、工具系统、session 与 safety 边界:
|
|
446
|
-
|
|
447
|
-
```ts
|
|
448
|
-
import {
|
|
449
|
-
QueryEngine,
|
|
450
|
-
ToolRegistry,
|
|
451
|
-
createModelGatewayFromEnv,
|
|
452
|
-
readFileTool,
|
|
453
|
-
listDirectoryTool,
|
|
454
|
-
grepTool,
|
|
455
|
-
createExecTools,
|
|
456
|
-
planTool,
|
|
457
|
-
} from "neoctl";
|
|
458
|
-
|
|
459
|
-
const tools = new ToolRegistry();
|
|
460
|
-
tools.register(readFileTool);
|
|
461
|
-
tools.register(listDirectoryTool);
|
|
462
|
-
tools.register(grepTool);
|
|
463
|
-
for (const tool of createExecTools()) tools.register(tool);
|
|
464
|
-
tools.register(planTool);
|
|
465
|
-
|
|
466
|
-
const engine = new QueryEngine({
|
|
467
|
-
agentId: "main",
|
|
468
|
-
modelGateway: createModelGatewayFromEnv(),
|
|
469
|
-
tools,
|
|
470
|
-
});
|
|
471
|
-
|
|
472
|
-
for await (const event of engine.sendUserText("Summarize this repository")) {
|
|
473
|
-
console.log(event);
|
|
474
|
-
}
|
|
475
|
-
```
|
|
476
|
-
|
|
477
|
-
Vue 等前端项目如果通过 API 消费消息,可使用展示层投影工具把内部 `Message` 转为可直接渲染的 DTO。`image2` 生成结果会被写入 `image` block;`imageMode: "data-url"` 时图片块会提供可直接赋给 `<img :src>` 的 `thumbnail.src` / `original.src`:
|
|
478
|
-
|
|
479
|
-
```ts
|
|
480
|
-
import { extractDisplayImages, toDisplayAgentEvent, toDisplayMessages } from "neoctl";
|
|
481
|
-
|
|
482
|
-
const displayMessages = toDisplayMessages(engine.getHistoryMessages(), {
|
|
483
|
-
imageMode: "data-url",
|
|
484
|
-
includeThinking: false,
|
|
485
|
-
includeToolUse: false,
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
// 如果只想拿图片列表:
|
|
489
|
-
const images = extractDisplayImages(displayMessages);
|
|
490
|
-
// images[0]?.src 可直接返回给 Vue 的 <img :src>
|
|
491
|
-
```
|
|
492
|
-
|
|
493
|
-
```vue
|
|
494
|
-
<template v-for="message in displayMessages" :key="message.id">
|
|
495
|
-
<template v-for="(block, index) in message.blocks" :key="index">
|
|
496
|
-
<img
|
|
497
|
-
v-if="block.type === 'image' && block.thumbnail"
|
|
498
|
-
:src="block.thumbnail.src"
|
|
499
|
-
:alt="block.label || 'generated image'"
|
|
500
|
-
class="message-image-thumb"
|
|
501
|
-
/>
|
|
502
|
-
</template>
|
|
503
|
-
</template>
|
|
504
|
-
```
|
|
505
|
-
|
|
506
|
-
SSE/WebSocket 流式推送事件时,可以在后端把单个 `AgentEvent` 投影为 `DisplayAgentEvent`,这样 Vue 收到 `event.type === "message"` 时同样能直接渲染图片:
|
|
507
|
-
|
|
508
|
-
```ts
|
|
509
|
-
for await (const event of engine.sendUserText("画一张小猫")) {
|
|
510
|
-
sendSse(toDisplayAgentEvent(event, { imageMode: "data-url" }));
|
|
511
|
-
}
|
|
512
|
-
```
|
|
513
|
-
|
|
514
|
-
也可以用 `imageMode: "metadata-only"` 只返回图片标签、MIME 与大小信息,避免在列表接口中内联 base64。
|
|
515
|
-
|
|
516
|
-
### 简单多会话 / Vue 后端集成
|
|
517
|
-
|
|
518
|
-
如果 Vue 侧只需要“每个用户使用自己的会话”或“一个用户操作,其他用户旁观”,可以使用轻量的 `SimpleSessionRuntime`。它不会改变底层 `QueryEngine` / `SessionStore` 行为,只是在库侧封装:
|
|
519
|
-
|
|
520
|
-
- 每个 `sessionId` 一个活动 `QueryEngine`。
|
|
521
|
-
- 同一 session 默认只允许一个发送任务运行,避免并发写历史。
|
|
522
|
-
- 支持读取 Vue 展示 DTO。
|
|
523
|
-
- 支持 `abort()` 中断当前 session。
|
|
524
|
-
- 支持 `onEvent()` 监听事件,便于服务端广播给 SSE/WebSocket 客户端。
|
|
525
|
-
- 可通过 `sessionRootDir` 做简单用户隔离。
|
|
526
|
-
|
|
527
|
-
```ts
|
|
528
|
-
import { SimpleSessionRuntime, createModelGatewayFromEnv, ToolRegistry } from "neoctl";
|
|
529
|
-
|
|
530
|
-
const tools = new ToolRegistry();
|
|
531
|
-
|
|
532
|
-
const runtime = new SimpleSessionRuntime({
|
|
533
|
-
agentId: "main",
|
|
534
|
-
modelGateway: createModelGatewayFromEnv(),
|
|
535
|
-
tools,
|
|
536
|
-
// 简单多用户推荐:后端根据登录态为每个用户分配独立 session 目录。
|
|
537
|
-
sessionRootDir: `.agent/users/${userId}/sessions`,
|
|
538
|
-
});
|
|
539
|
-
|
|
540
|
-
runtime.onDisplayEvent((event, { sessionId }) => {
|
|
541
|
-
// 可在这里把已投影的 DisplayAgentEvent 广播给正在观看该 session 的 SSE/WebSocket 客户端。
|
|
542
|
-
// image2 图片会以 message.blocks[].type === "image" 且 block.thumbnail.src 可直接渲染的形式出现。
|
|
543
|
-
broadcast(sessionId, event);
|
|
544
|
-
}, { imageMode: "data-url", includeThinking: false, includeToolUse: false });
|
|
545
|
-
|
|
546
|
-
for await (const event of runtime.sendUserText(sessionId, "Summarize this repository")) {
|
|
547
|
-
console.log(event);
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
const displayMessages = await runtime.getDisplayMessages(sessionId, {
|
|
551
|
-
imageMode: "data-url", // Vue <img :src> 用这个;列表页可改为 metadata-only
|
|
552
|
-
includeThinking: false,
|
|
553
|
-
includeToolUse: false,
|
|
554
|
-
});
|
|
555
|
-
const images = await runtime.getDisplayImages(sessionId, { imageMode: "data-url" });
|
|
556
|
-
```
|
|
557
|
-
|
|
558
|
-
常用方法:
|
|
559
|
-
|
|
560
|
-
```ts
|
|
561
|
-
await runtime.newSession();
|
|
562
|
-
await runtime.resumeSession(sessionId);
|
|
563
|
-
await runtime.listSessions(20);
|
|
564
|
-
await runtime.getMessages(sessionId);
|
|
565
|
-
await runtime.getDisplayMessages(sessionId, { imageMode: "metadata-only" });
|
|
566
|
-
await runtime.getDisplayImages(sessionId, { imageMode: "data-url" });
|
|
567
|
-
runtime.isBusy(sessionId);
|
|
568
|
-
runtime.abort(sessionId);
|
|
569
|
-
runtime.release(sessionId);
|
|
570
|
-
```
|
|
571
|
-
|
|
572
|
-
如果同一 session 正在运行,再次发送默认会抛出 `session is busy`。需要新请求打断旧请求时,可以使用:
|
|
573
|
-
|
|
574
|
-
```ts
|
|
575
|
-
runtime.sendUserText(sessionId, text, { busyBehavior: "interrupt" });
|
|
576
|
-
```
|
|
577
|
-
|
|
578
|
-
除根入口外,发布包还通过 package `exports` 暴露 `dist` 下的编译后子路径,便于依赖方按需导入较底层模块:
|
|
579
|
-
|
|
580
|
-
```ts
|
|
581
|
-
import { HttpTransport } from "neoctl/model/http-transport";
|
|
582
|
-
import { createAgentTool } from "neoctl/agents/agent-tool";
|
|
583
|
-
```
|
|
584
|
-
|
|
585
|
-
如果直接从源码运行,请使用 `.ts` 源文件路径或 `tsx`;发布包会通过 `dist` 导出编译后的 `.js` 模块与 `.d.ts` 类型声明。
|
|
586
|
-
|
|
587
|
-
## 运行数据目录
|
|
588
|
-
|
|
589
|
-
| 路径 | 内容 |
|
|
590
|
-
| --- | --- |
|
|
591
|
-
| `.agent/sessions/` | 默认会话 transcript 和大型工具结果 |
|
|
592
|
-
| `.agent-tasks/` | 后台 agent 任务最终输出 |
|
|
593
|
-
| `vendor/ripgrep/` | 当前平台 ripgrep 二进制和 manifest |
|
|
594
|
-
| `dist/` | `npm run build` 生成的编译产物 |
|
|
595
|
-
|
|
596
|
-
## 当前边界
|
|
597
|
-
|
|
598
|
-
- 模型 provider 配置类型目前内置 OpenAI 与 Anthropic provider。
|
|
599
|
-
- `src/safety` 是 permission、sandbox、audit 的接口边界;默认 REPL 没有强制沙箱策略。
|
|
600
|
-
- `src/skills` 已实现工具与 catalog,但默认 REPL 未装配 skill catalog。
|
|
601
|
-
- `isolation=worktree/remote` 在 AgentTool schema 中保留为接口形态,当前本地实现主要通过 `cwd` 和独立消息上下文隔离。
|
|
59
|
+
更多测试命令见 [tests/README.md](tests/README.md)。
|
package/dist/context/prompts.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { IMAGE_SELECTION_GUIDE } from "../tools/builtins/image-capabilities.js";
|
|
1
2
|
import { readBundledSystemPrompt } from "./prompt-config.js";
|
|
2
3
|
import { DEFAULT_TOOL_RESULT_BUDGET_CHARS, MAX_TOOL_RESULT_BUDGET_CHARS } from "../session/tool-result-memory.js";
|
|
3
4
|
export const SYSTEM_PROMPT_DYNAMIC_BOUNDARY = "__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__";
|
|
@@ -25,7 +26,7 @@ export function buildDefaultSystemPromptSections(enabledTools = [], basePrompt =
|
|
|
25
26
|
? "When you need to inspect, describe, OCR, or answer questions about a historical image that is no longer directly present in the active prompt, use the image_inspect tool with its image id (e.g. img_1) or label. The image registry in compact boundary messages lists all available historical images; compacted images are not text-summarized into visual facts, so load the pixels when visual details matter."
|
|
26
27
|
: "This runtime has no image loading tool. Do not pretend to visually inspect stored image paths; ask the user to enable image inspection or select a compatible runtime if visual analysis is required.",
|
|
27
28
|
hasImageGenerationTool
|
|
28
|
-
?
|
|
29
|
+
? `When the user asks for drawing/image generation or image editing/modification, use the image_create tool. ${IMAGE_SELECTION_GUIDE} It supports mode=generate and mode=edit. If image_create validation fails, report the model and exact parameter reason. Successful results may carry warnings: distinguish requested, upstream-reported and byte-verified properties, and clearly disclose material output mismatches.`
|
|
29
30
|
: "This runtime has no drawing/image generation/editing tool. If the user asks you to draw, create, render, generate, or edit an image, say that image generation is unavailable in the current runtime configuration instead of pretending to generate one.",
|
|
30
31
|
hasSecretTools
|
|
31
32
|
? `Secrets: you may inspect secret keys, statuses, and value lengths, but secret values are never shown to you. ${secretRequestInstruction} Do not ask users to paste secret values into the conversation; pass secret keys to enabled tools that accept secret references.`
|