feat: add @uncaged/workflow-agent-builtin package #420

Merged
xiaomo merged 2 commits from feat/builtin-agent into main 2026-05-23 07:57:44 +00:00
Owner

What

Built-in role agent (uwf-builtin) that uses workflow config models directly with its own tool-calling run loop. No external agent dependency (no hermes/openclaw/claude-code).

Why

Enable self-contained workflow execution without requiring external agent CLIs.

Changes

  • New package packages/workflow-agent-builtin/ (1848 lines)
    • src/llm/: OpenAI-compatible chat completion client with tool_calls support
    • src/tools/: P0 toolkit — read_file, write_file, run_command (path sandboxed)
    • src/loop.ts: Agent run loop (multi-turn LLM ↔ tool execution)
    • src/prompt.ts: Prompt assembly (aligned with uwf-hermes)
    • src/detail.ts: CAS detail recording per turn
    • src/agent.ts: createBuiltinAgent() via createAgent factory
    • src/cli.ts: CLI entry point (uwf-builtin)
  • workflow-agent-kit: export resolveStorageRoot
  • Root tsconfig + publish-all updated
  • Research doc: docs/builtin-agent-research.md

Config

agents:
  builtin:
    command: uwf-builtin
    args: []
defaultAgent: builtin

Shell tool requires UWF_BUILTIN_ALLOW_SHELL=1.

Tests

5 new tests (LLM parsing, path security, prompt building). All existing tests pass.

## What Built-in role agent (`uwf-builtin`) that uses workflow config models directly with its own tool-calling run loop. No external agent dependency (no hermes/openclaw/claude-code). ## Why Enable self-contained workflow execution without requiring external agent CLIs. ## Changes - New package `packages/workflow-agent-builtin/` (1848 lines) - `src/llm/`: OpenAI-compatible chat completion client with tool_calls support - `src/tools/`: P0 toolkit — read_file, write_file, run_command (path sandboxed) - `src/loop.ts`: Agent run loop (multi-turn LLM ↔ tool execution) - `src/prompt.ts`: Prompt assembly (aligned with uwf-hermes) - `src/detail.ts`: CAS detail recording per turn - `src/agent.ts`: createBuiltinAgent() via createAgent factory - `src/cli.ts`: CLI entry point (`uwf-builtin`) - `workflow-agent-kit`: export resolveStorageRoot - Root tsconfig + publish-all updated - Research doc: `docs/builtin-agent-research.md` ## Config ```yaml agents: builtin: command: uwf-builtin args: [] defaultAgent: builtin ``` Shell tool requires `UWF_BUILTIN_ALLOW_SHELL=1`. ## Tests 5 new tests (LLM parsing, path security, prompt building). All existing tests pass.
xingyue added 1 commit 2026-05-23 07:29:14 +00:00
Built-in role agent that uses workflow config models directly,
with its own tool-calling run loop. No external agent dependency.

- OpenAI-compatible chat completion client with tool_calls support
- P0 toolkit: read_file, write_file, run_command
- Integrates via createAgent factory from workflow-agent-kit
- CAS detail recording for each turn
- Path sandboxing and shell opt-in (UWF_BUILTIN_ALLOW_SHELL)
xingyue force-pushed feat/builtin-agent from 76a5b14957 to deac2336b6 2026-05-23 07:31:10 +00:00 Compare
xiaomo requested changes 2026-05-23 07:34:23 +00:00
Dismissed
xiaomo left a comment
Owner

Review: @uncaged/workflow-agent-builtin

整体架构清晰,与现有 hermes/claude-code agent 包对齐良好,类型安全做得不错。但有几个安全和正确性问题需要修复。

🔴 Must Fix

1. Path sandbox 可被 symlink 绕过 (src/tools/path.ts)
resolvePathInWorkspace 只做 relative() 检查,没有 realpath 解析。LLM 可先 run_command 创建符号链接 workspace/link -> /etc,再 read_file("link/shadow") 读取任意文件。建议 resolve 后加 fs.realpathSync,对真实路径再做一次检查。

2. run_command stdout/stderr 无限缓冲 → OOM
on('data') 回调无限拼接字符串,恶意命令可输出 GB 级数据。应在回调中就做截断检查。

3. run_command timeout 后仅 SIGTERM,无 SIGKILL fallback
进程可忽略 SIGTERM 继续运行。建议 SIGTERM 后 5s 再 SIGKILL。

4. run_command shell=true + 仅 cwd 沙箱 = 虚假安全感
command 本身可以 cd /anywhere && ...。cwd 检查在 shell=true 下形同虚设。建议注释/文档明确说明 UWF_BUILTIN_ALLOW_SHELL=1 是完全无沙箱的 shell 访问。

🟡 Suggestions

5. 测试覆盖不足 — 无 loop.ts 测试(核心多轮逻辑)、无 run_command 测试、path.test.ts 缺边界用例(symlink、绝对路径、空字符串)。建议至少加 loop 的 mock LLM 测试。

6. LLM 客户端无重试 — 429/5xx 直接抛异常,建议加指数退避。

7. maxTurns 耗尽时优雅降级 — 最后一轮仍有 tool_calls 时没发 "请总结" 请求,可能返回空输出。

8. schema 每次 detail 写入都重新注册 — 应缓存。

9. docs/builtin-agent-research.md (779行) — 调研文档建议移到 wiki,不合入代码库。

10. package.json bin 指向 ./src/cli.ts — 发布时应指向 dist/cli.js,否则非 bun 环境无法运行。

11. session Map 无清理createBuiltinAgent 暴露为 API,长期运行可能泄漏。


修复 symlink 绕过和 OOM 风险后可合入,其余可作 follow-up。

## Review: @uncaged/workflow-agent-builtin 整体架构清晰,与现有 hermes/claude-code agent 包对齐良好,类型安全做得不错。但有几个安全和正确性问题需要修复。 ### 🔴 Must Fix **1. Path sandbox 可被 symlink 绕过 (`src/tools/path.ts`)** `resolvePathInWorkspace` 只做 `relative()` 检查,没有 `realpath` 解析。LLM 可先 `run_command` 创建符号链接 `workspace/link -> /etc`,再 `read_file("link/shadow")` 读取任意文件。建议 resolve 后加 `fs.realpathSync`,对真实路径再做一次检查。 **2. `run_command` stdout/stderr 无限缓冲 → OOM** `on('data')` 回调无限拼接字符串,恶意命令可输出 GB 级数据。应在回调中就做截断检查。 **3. `run_command` timeout 后仅 SIGTERM,无 SIGKILL fallback** 进程可忽略 SIGTERM 继续运行。建议 SIGTERM 后 5s 再 SIGKILL。 **4. `run_command` shell=true + 仅 cwd 沙箱 = 虚假安全感** command 本身可以 `cd /anywhere && ...`。cwd 检查在 shell=true 下形同虚设。建议注释/文档明确说明 `UWF_BUILTIN_ALLOW_SHELL=1` 是完全无沙箱的 shell 访问。 ### 🟡 Suggestions **5. 测试覆盖不足** — 无 loop.ts 测试(核心多轮逻辑)、无 run_command 测试、path.test.ts 缺边界用例(symlink、绝对路径、空字符串)。建议至少加 loop 的 mock LLM 测试。 **6. LLM 客户端无重试** — 429/5xx 直接抛异常,建议加指数退避。 **7. `maxTurns` 耗尽时优雅降级** — 最后一轮仍有 tool_calls 时没发 "请总结" 请求,可能返回空输出。 **8. schema 每次 detail 写入都重新注册** — 应缓存。 **9. `docs/builtin-agent-research.md` (779行)** — 调研文档建议移到 wiki,不合入代码库。 **10. `package.json` bin 指向 `./src/cli.ts`** — 发布时应指向 `dist/cli.js`,否则非 bun 环境无法运行。 **11. session Map 无清理** — `createBuiltinAgent` 暴露为 API,长期运行可能泄漏。 --- 修复 symlink 绕过和 OOM 风险后可合入,其余可作 follow-up。
xiaomo reviewed 2026-05-23 07:41:09 +00:00
xiaomo left a comment
Owner

更正:撤回安全相关意见

经主人指出,role agent 本身应有设备完整权限,安全边界由外部沙箱机制保证。因此撤回以下意见:

  • Path sandbox symlink 绕过
  • shell=true cwd 沙箱

仍然建议修复的稳定性问题:

  1. run_command stdout/stderr 无限缓冲 → OOM(这是稳定性问题,不是安全问题)
  2. timeout 后 SIGTERM 无 SIGKILL fallback — 进程可能卡住不退出

其余测试覆盖、LLM 重试、schema 缓存等建议不变,可 follow-up。

如果 OOM 和 SIGKILL 也打算后续再处理,可以直接合入。

## 更正:撤回安全相关意见 经主人指出,role agent 本身应有设备完整权限,安全边界由外部沙箱机制保证。因此撤回以下意见: - ~~Path sandbox symlink 绕过~~ - ~~shell=true cwd 沙箱~~ **仍然建议修复的稳定性问题:** 1. `run_command` stdout/stderr 无限缓冲 → OOM(这是稳定性问题,不是安全问题) 2. timeout 后 SIGTERM 无 SIGKILL fallback — 进程可能卡住不退出 其余测试覆盖、LLM 重试、schema 缓存等建议不变,可 follow-up。 如果 OOM 和 SIGKILL 也打算后续再处理,可以直接合入。
xiaomo reviewed 2026-05-23 07:42:25 +00:00
xiaomo left a comment
Owner

补充建议:去掉 in-workspace 路径限制

Role agent 应有设备完整权限(安全边界由外部沙箱保证),resolvePathInWorkspace 的路径限制是多余的,还会阻碍 agent 读写 workspace 外文件的正当需求。

建议:

  • read_file / write_file 直接用 path.resolve(cwd, inputPath) 即可,不做越界检查
  • run_command 的 cwd 参数同理
  • UWF_BUILTIN_ALLOW_SHELL 门控也可以去掉,shell 默认可用

简化后代码更干净,也符合实际使用场景。

## 补充建议:去掉 in-workspace 路径限制 Role agent 应有设备完整权限(安全边界由外部沙箱保证),`resolvePathInWorkspace` 的路径限制是多余的,还会阻碍 agent 读写 workspace 外文件的正当需求。 建议: - `read_file` / `write_file` 直接用 `path.resolve(cwd, inputPath)` 即可,不做越界检查 - `run_command` 的 cwd 参数同理 - `UWF_BUILTIN_ALLOW_SHELL` 门控也可以去掉,shell 默认可用 简化后代码更干净,也符合实际使用场景。
xingyue added 1 commit 2026-05-23 07:50:35 +00:00
- Replace resolvePathInWorkspace with simple resolvePath (no boundary check)
- Remove UWF_BUILTIN_ALLOW_SHELL env gate from run_command
- Update tests accordingly

Per review: sandbox was false security with shell=true, and path
restrictions are unnecessary for a trusted agent environment.
xiaomo approved these changes 2026-05-23 07:57:40 +00:00
xiaomo left a comment
Owner

LGTM 路径限制和 shell 门控已移除,简洁干净。稳定性改进留 follow-up。

LGTM ✅ 路径限制和 shell 门控已移除,简洁干净。稳定性改进留 follow-up。
xiaomo merged commit 3183b4c879 into main 2026-05-23 07:57:44 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: uncaged/workflow#420