@steerable/agent-harness 0.2.4 → 0.3.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.
@@ -1,3 +1,4 @@
1
+ import type { ContentPart } from "./ContentPart.js";
1
2
  import type { ToolCall } from "./ToolCall.js";
2
3
  import type { ToolResult } from "./ToolResult.js";
3
4
  export interface ChatMessage {
@@ -5,6 +6,10 @@ export interface ChatMessage {
5
6
  chatId?: string;
6
7
  role: "user" | "assistant" | "tool" | "system";
7
8
  content: string;
9
+ /**
10
+ * Structured content (Wave 1). Optional and additive: when present it is authoritative and `content` is its plain-text projection; when absent the message is text-only and `content` is the payload. Producers that emit multimodal messages MUST also fill `content` so text-only consumers keep working.
11
+ */
12
+ parts?: ContentPart[];
8
13
  agentId?: string;
9
14
  toolCalls?: ToolCall[];
10
15
  toolResult?: ToolResult;
@@ -0,0 +1,22 @@
1
+ export interface ContentPart {
2
+ /**
3
+ * Part discriminant. `text` carries `text`; `image` carries either `url` or (`data`, `mediaType`).
4
+ */
5
+ type: "text" | "image";
6
+ /**
7
+ * Text payload; present iff type == "text".
8
+ */
9
+ text?: string;
10
+ /**
11
+ * Image URL; present iff type == "image" and the image is remote.
12
+ */
13
+ url?: string;
14
+ /**
15
+ * Base64 image payload; present iff type == "image" and the image is inline.
16
+ */
17
+ data?: string;
18
+ /**
19
+ * MIME type of the image (e.g. image/png); accompanies `data`, advisory for `url`.
20
+ */
21
+ mediaType?: string;
22
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,3 +1,26 @@
1
+ /**
2
+ * Shell command safety patterns — classify a command before it runs.
3
+ *
4
+ * Full 61-rule set reflowed from deeppath-agent's
5
+ * `src/harness/safety-patterns.ts`; the framework is now the source of truth
6
+ * (agent will import from here in A4). Kept in lockstep with the Python twin
7
+ * `packages/agent-harness/py/src/steerable_agent_harness/safety.py` via the
8
+ * conformance case `tests/conformance/cases/safety/classify_shell_command.yaml`.
9
+ *
10
+ * Rule order matters: `matchedRules` follows BUILTIN_PATTERNS order so both
11
+ * languages return identical lists.
12
+ */
13
+ export interface CommandSafetyConfig {
14
+ disabledPatternIds?: string[];
15
+ hiddenPatternIds?: string[];
16
+ customPatterns?: Array<{
17
+ id: string;
18
+ label: string;
19
+ pattern: string;
20
+ category: string;
21
+ enabled: boolean;
22
+ }>;
23
+ }
1
24
  export type PatternSeverity = "critical" | "warning";
2
25
  export type PatternPlatform = "all" | "unix" | "windows";
3
26
  export interface SafetyPatternDef {
@@ -9,8 +32,22 @@ export interface SafetyPatternDef {
9
32
  severity: PatternSeverity;
10
33
  platform: PatternPlatform;
11
34
  }
35
+ export declare const SAFETY_CATEGORIES: Record<string, string>;
12
36
  export declare const BUILTIN_PATTERNS: SafetyPatternDef[];
13
- export declare function classifyShellCommand(command: string): {
37
+ /**
38
+ * 根据用户配置计算当前生效的正则模式列表
39
+ */
40
+ export declare function getActivePatterns(config?: CommandSafetyConfig | null): RegExp[];
41
+ /**
42
+ * 按分类分组返回内置模式
43
+ */
44
+ export declare function getPatternsByCategory(): Record<string, SafetyPatternDef[]>;
45
+ /**
46
+ * 默认空配置(所有内置模式均启用,无自定义模式)
47
+ */
48
+ export declare const DEFAULT_COMMAND_SAFETY_CONFIG: CommandSafetyConfig;
49
+ export interface ShellCommandClassification {
14
50
  severity: "safe" | PatternSeverity;
15
51
  matchedRules: string[];
16
- };
52
+ }
53
+ export declare function classifyShellCommand(command: string, config?: CommandSafetyConfig | null): ShellCommandClassification;
@@ -1,71 +1,166 @@
1
+ /**
2
+ * Shell command safety patterns — classify a command before it runs.
3
+ *
4
+ * Full 61-rule set reflowed from deeppath-agent's
5
+ * `src/harness/safety-patterns.ts`; the framework is now the source of truth
6
+ * (agent will import from here in A4). Kept in lockstep with the Python twin
7
+ * `packages/agent-harness/py/src/steerable_agent_harness/safety.py` via the
8
+ * conformance case `tests/conformance/cases/safety/classify_shell_command.yaml`.
9
+ *
10
+ * Rule order matters: `matchedRules` follows BUILTIN_PATTERNS order so both
11
+ * languages return identical lists.
12
+ */
13
+ // ─── Categories ──────────────────────────────────────────────────────
14
+ export const SAFETY_CATEGORIES = {
15
+ file_ops: "文件操作",
16
+ system: "系统管理",
17
+ process: "进程管理",
18
+ network: "网络安全",
19
+ package: "包管理",
20
+ vcs: "版本控制",
21
+ container: "容器管理",
22
+ file_write: "文件写入",
23
+ windows: "Windows / PowerShell",
24
+ };
25
+ // ─── Built-in patterns ───────────────────────────────────────────────
26
+ // Merged from deeppath-agent local-actions.ts (web, severity=warning) and
27
+ // local-executor.ts (desktop, severity=critical). Keep aligned with the
28
+ // Python twin.
1
29
  export const BUILTIN_PATTERNS = [
2
- {
3
- id: "rm",
4
- label: "rm 删除",
5
- description: "匹配 rm 命令",
6
- pattern: "\\brm\\s",
7
- category: "file_ops",
8
- severity: "warning",
9
- platform: "unix",
10
- },
11
- {
12
- id: "rm_rf_root",
13
- label: "rm -rf /",
14
- description: "递归删除根目录",
15
- pattern: "rm\\s+-rf\\s+\\/(?:\\s|$)",
16
- category: "file_ops",
17
- severity: "critical",
18
- platform: "unix",
19
- },
20
- {
21
- id: "sudo",
22
- label: "sudo 提权",
23
- description: "以超级用户权限执行",
24
- pattern: "\\bsudo\\s",
25
- category: "system",
26
- severity: "critical",
27
- platform: "unix",
28
- },
29
- {
30
- id: "curl_pipe_sh",
31
- label: "curl | sh",
32
- description: "从网络下载并直接执行脚本",
33
- pattern: "\\bcurl\\s.*\\|\\s*(sh|bash|zsh)",
34
- category: "network",
35
- severity: "warning",
36
- platform: "unix",
37
- },
38
- {
39
- id: "git_push",
40
- label: "git push / reset --hard",
41
- description: "Git 远程推送或硬重置",
42
- pattern: "\\bgit\\s+(push|reset\\s+--hard|clean\\s+-fd)",
43
- category: "vcs",
44
- severity: "warning",
45
- platform: "all",
46
- },
47
- {
48
- id: "win_del_force",
49
- label: "del /f /s /q 强制删除",
50
- description: "强制递归删除整个驱动器",
51
- pattern: "\\bdel\\s+\\/f\\s+\\/s\\s+\\/q\\s+[a-z]:\\\\",
52
- category: "windows",
53
- severity: "critical",
54
- platform: "windows",
55
- },
30
+ // ── file_ops ──
31
+ { id: "rm", label: "rm 删除", description: "匹配 rm 命令", pattern: "\\brm\\s", category: "file_ops", severity: "warning", platform: "unix" },
32
+ { id: "rm_end", label: "rm(行尾)", description: "匹配行尾的 rm", pattern: "\\brm$", category: "file_ops", severity: "warning", platform: "unix" },
33
+ { id: "rm_rf_root", label: "rm -rf /", description: "递归删除根目录", pattern: "rm\\s+-rf\\s+\\/(?:\\s|$)", category: "file_ops", severity: "critical", platform: "unix" },
34
+ { id: "rmdir", label: "rmdir 删除目录", description: "匹配 rmdir 命令", pattern: "\\brmdir\\s", category: "file_ops", severity: "warning", platform: "unix" },
35
+ { id: "mv", label: "mv 移动/重命名", description: "匹配 mv 命令", pattern: "\\bmv\\s.*\\/", category: "file_ops", severity: "warning", platform: "unix" },
36
+ { id: "shred", label: "shred 安全擦除", description: "不可恢复地擦除文件", pattern: "\\bshred\\b", category: "file_ops", severity: "warning", platform: "unix" },
37
+ { id: "truncate", label: "truncate 截断文件", description: "截断文件内容", pattern: "\\btruncate\\b", category: "file_ops", severity: "warning", platform: "unix" },
38
+ // ── system ──
39
+ { id: "sudo", label: "sudo 提权", description: "以超级用户权限执行", pattern: "\\bsudo\\s", category: "system", severity: "critical", platform: "unix" },
40
+ { id: "mkfs", label: "mkfs 格式化磁盘", description: "创建文件系统(格式化)", pattern: "\\bmkfs\\b", category: "system", severity: "critical", platform: "unix" },
41
+ { id: "dd", label: "dd 磁盘写入", description: "底层磁盘数据复制", pattern: "\\bdd\\s", category: "system", severity: "warning", platform: "unix" },
42
+ { id: "dd_if", label: "dd if= 磁盘镜像", description: "使用 dd if= 读写磁盘", pattern: "\\bdd\\s+if=", category: "system", severity: "critical", platform: "unix" },
43
+ { id: "format", label: "format 格式化", description: "格式化磁盘", pattern: "\\bformat\\b", category: "system", severity: "warning", platform: "all" },
44
+ { id: "shutdown", label: "shutdown 关机", description: "关闭系统", pattern: "\\bshutdown\\b", category: "system", severity: "warning", platform: "all" },
45
+ { id: "reboot", label: "reboot 重启", description: "重启系统", pattern: "\\breboot\\b", category: "system", severity: "warning", platform: "all" },
46
+ { id: "chmod", label: "chmod 修改权限", description: "修改文件权限", pattern: "\\bchmod\\s", category: "system", severity: "warning", platform: "unix" },
47
+ { id: "chmod_777_root", label: "chmod -R 777 /", description: "递归赋予根目录所有权限", pattern: "chmod\\s+-R\\s+777\\s+\\/(?:\\s|$)", category: "system", severity: "critical", platform: "unix" },
48
+ { id: "chown", label: "chown 修改所有者", description: "修改文件所有者", pattern: "\\bchown\\s", category: "system", severity: "warning", platform: "unix" },
49
+ { id: "fork_bomb", label: "Fork Bomb", description: ":(){ :|:& };: fork 炸弹", pattern: ":\\(\\)\\s*\\{\\s*:\\|:&\\s*\\};:", category: "system", severity: "critical", platform: "unix" },
50
+ // ── process ──
51
+ { id: "kill", label: "kill 终止进程", description: "向进程发送信号", pattern: "\\bkill\\s", category: "process", severity: "warning", platform: "unix" },
52
+ { id: "killall", label: "killall 终止所有", description: "按名称终止进程", pattern: "\\bkillall\\s", category: "process", severity: "warning", platform: "unix" },
53
+ // ── network ──
54
+ { id: "curl_pipe_sh", label: "curl | sh", description: "从网络下载并直接执行脚本", pattern: "\\bcurl\\s.*\\|\\s*(sh|bash|zsh)", category: "network", severity: "warning", platform: "unix" },
55
+ { id: "wget_pipe_sh", label: "wget | sh", description: "从网络下载并直接执行脚本", pattern: "\\bwget\\s.*\\|\\s*(sh|bash|zsh)", category: "network", severity: "warning", platform: "unix" },
56
+ { id: "redirect_dev", label: "重定向到 /dev/", description: "向设备文件写入数据", pattern: ">\\s*\\/dev\\/", category: "network", severity: "warning", platform: "unix" },
57
+ // ── package ──
58
+ { id: "npm_publish", label: "npm publish", description: "发布/取消发布 npm 包", pattern: "\\bnpm\\s+(publish|unpublish)", category: "package", severity: "warning", platform: "all" },
59
+ { id: "pip_install", label: "pip install", description: "安装 Python 包", pattern: "\\bpip\\s+install\\b", category: "package", severity: "warning", platform: "all" },
60
+ { id: "npm_install", label: "npm install", description: "安装 npm 包", pattern: "\\bnpm\\s+install\\b", category: "package", severity: "warning", platform: "all" },
61
+ { id: "yarn_add", label: "yarn add", description: "添加 yarn 依赖", pattern: "\\byarn\\s+add\\b", category: "package", severity: "warning", platform: "all" },
62
+ { id: "pnpm_add", label: "pnpm add", description: "添加 pnpm 依赖", pattern: "\\bpnpm\\s+add\\b", category: "package", severity: "warning", platform: "all" },
63
+ { id: "uv_add", label: "uv add", description: "添加 uv 依赖", pattern: "\\buv\\s+add\\b", category: "package", severity: "warning", platform: "all" },
64
+ { id: "apt_install", label: "apt install/remove", description: "系统包管理器操作", pattern: "\\bapt(-get)?\\s+(install|remove|purge)", category: "package", severity: "warning", platform: "unix" },
65
+ { id: "brew_install", label: "brew install/uninstall", description: "Homebrew 包管理器操作", pattern: "\\bbrew\\s+(install|uninstall|remove)", category: "package", severity: "warning", platform: "unix" },
66
+ // ── vcs ──
67
+ { id: "git_push", label: "git push / reset --hard", description: "Git 远程推送或硬重置", pattern: "\\bgit\\s+(push|reset\\s+--hard|clean\\s+-fd)", category: "vcs", severity: "warning", platform: "all" },
68
+ // ── container ──
69
+ { id: "docker_rm", label: "docker rm/rmi/prune", description: "删除容器/镜像或清理系统", pattern: "\\bdocker\\s+(rm|rmi|system\\s+prune)", category: "container", severity: "warning", platform: "all" },
70
+ // ── file_write ──
71
+ { id: "redirect_overwrite", label: "> / >> 重定向写入", description: "文件重定向覆盖或追加", pattern: "\\b(>\\s|>>)\\s*[^|]", category: "file_write", severity: "warning", platform: "all" },
72
+ { id: "tee", label: "tee 写入文件", description: "将输出写入文件", pattern: "\\btee\\s", category: "file_write", severity: "warning", platform: "unix" },
73
+ { id: "sed_inplace", label: "sed -i 原地修改", description: "直接修改文件内容", pattern: "\\bsed\\s+-i", category: "file_write", severity: "warning", platform: "unix" },
74
+ // ── windows ──
75
+ { id: "win_del", label: "del 删除", description: "Windows 删除命令", pattern: "\\bdel\\s", category: "windows", severity: "warning", platform: "windows" },
76
+ { id: "win_rd", label: "rd 删除目录", description: "Windows 删除目录", pattern: "\\brd\\s", category: "windows", severity: "warning", platform: "windows" },
77
+ { id: "win_rd_end", label: "rd(行尾)", description: "匹配行尾的 rd", pattern: "\\brd$", category: "windows", severity: "warning", platform: "windows" },
78
+ { id: "win_rdel", label: "rdel", description: "Windows rdel 命令", pattern: "\\brdel\\b", category: "windows", severity: "warning", platform: "windows" },
79
+ { id: "win_del_force", label: "del /f /s /q 强制删除", description: "强制递归删除整个驱动器", pattern: "\\bdel\\s+\\/f\\s+\\/s\\s+\\/q\\s+[a-z]:\\\\", category: "windows", severity: "critical", platform: "windows" },
80
+ { id: "win_rd_force", label: "rd /s /q 强制删除目录", description: "强制递归删除整个驱动器目录", pattern: "\\brd\\s+\\/s\\s+\\/q\\s+[a-z]:\\\\", category: "windows", severity: "critical", platform: "windows" },
81
+ { id: "win_remove_item", label: "Remove-Item", description: "PowerShell 删除项", pattern: "\\bRemove-Item\\b", category: "windows", severity: "warning", platform: "windows" },
82
+ { id: "win_stop_process", label: "Stop-Process", description: "PowerShell 终止进程", pattern: "\\bStop-Process\\b", category: "windows", severity: "warning", platform: "windows" },
83
+ { id: "win_stop_computer", label: "Stop-Computer", description: "PowerShell 关机", pattern: "\\bStop-Computer\\b", category: "windows", severity: "warning", platform: "windows" },
84
+ { id: "win_restart_computer", label: "Restart-Computer", description: "PowerShell 重启", pattern: "\\bRestart-Computer\\b", category: "windows", severity: "warning", platform: "windows" },
85
+ { id: "win_set_execution_policy", label: "Set-ExecutionPolicy", description: "修改脚本执行策略", pattern: "\\bSet-ExecutionPolicy\\b", category: "windows", severity: "warning", platform: "windows" },
86
+ { id: "win_format_volume", label: "Format-Volume", description: "PowerShell 格式化卷", pattern: "\\bFormat-Volume\\b", category: "windows", severity: "warning", platform: "windows" },
87
+ { id: "win_clear_disk", label: "Clear-Disk", description: "PowerShell 清除磁盘", pattern: "\\bClear-Disk\\b", category: "windows", severity: "warning", platform: "windows" },
88
+ { id: "win_wsl", label: "wsl 子系统", description: "调用 WSL 子系统", pattern: "\\bwsl\\s", category: "windows", severity: "warning", platform: "windows" },
89
+ { id: "win_powershell_cmd", label: "powershell -Command", description: "通过 PowerShell 执行命令", pattern: "\\bpowershell\\s.*-[Cc]ommand", category: "windows", severity: "warning", platform: "windows" },
90
+ { id: "win_pwsh", label: "pwsh", description: "PowerShell Core", pattern: "\\bpwsh\\s", category: "windows", severity: "warning", platform: "windows" },
91
+ { id: "win_cmd_c", label: "cmd /c", description: "CMD 执行命令", pattern: "\\bcmd\\s*\\/c\\b", category: "windows", severity: "warning", platform: "windows" },
92
+ { id: "win_reg", label: "reg delete/add", description: "注册表操作", pattern: "\\breg\\s+(delete|add)\\b", category: "windows", severity: "warning", platform: "windows" },
93
+ { id: "win_net", label: "net user/stop/start", description: "网络和用户管理", pattern: "\\bnet\\s+(user|stop|start)\\b", category: "windows", severity: "warning", platform: "windows" },
94
+ { id: "win_sc", label: "sc delete/stop/config", description: "服务管理", pattern: "\\bsc\\s+(delete|stop|config)\\b", category: "windows", severity: "warning", platform: "windows" },
95
+ { id: "win_diskpart", label: "diskpart", description: "磁盘分区工具", pattern: "\\bdiskpart\\b", category: "windows", severity: "warning", platform: "windows" },
96
+ { id: "win_bcdedit", label: "bcdedit", description: "启动配置编辑", pattern: "\\bbcdedit\\b", category: "windows", severity: "warning", platform: "windows" },
97
+ { id: "win_sfc", label: "sfc", description: "系统文件检查器", pattern: "\\bsfc\\b", category: "windows", severity: "warning", platform: "windows" },
98
+ { id: "win_dism", label: "dism", description: "部署映像服务和管理", pattern: "\\bdism\\b", category: "windows", severity: "warning", platform: "windows" },
99
+ // 只匹配 "format <盘符>:" 形式的磁盘格式化(含 format.com),避免误伤
100
+ // PowerShell 的 Format-List / Format-Table 等格式化输出 cmdlet
101
+ // (Format-Volume 由上面的 win_format_volume 单独覆盖)。
102
+ { id: "win_format_cmd", label: "format(Windows)", description: "Windows 格式化磁盘命令", pattern: "\\bformat(\\.com)?\\s+[a-z]:", category: "windows", severity: "critical", platform: "windows" },
56
103
  ];
57
- export function classifyShellCommand(command) {
104
+ // ─── Helpers ─────────────────────────────────────────────────────────
105
+ /**
106
+ * 根据用户配置计算当前生效的正则模式列表
107
+ */
108
+ export function getActivePatterns(config) {
109
+ const disabled = new Set(config?.disabledPatternIds ?? []);
110
+ const patterns = BUILTIN_PATTERNS.filter((p) => !disabled.has(p.id)).map((p) => {
111
+ const flags = p.platform === "windows" ? "i" : undefined;
112
+ return new RegExp(p.pattern, flags);
113
+ });
114
+ if (config?.customPatterns) {
115
+ for (const cp of config.customPatterns) {
116
+ if (!cp.enabled)
117
+ continue;
118
+ try {
119
+ patterns.push(new RegExp(cp.pattern));
120
+ }
121
+ catch {
122
+ // skip invalid regex
123
+ }
124
+ }
125
+ }
126
+ return patterns;
127
+ }
128
+ /**
129
+ * 按分类分组返回内置模式
130
+ */
131
+ export function getPatternsByCategory() {
132
+ const grouped = {};
133
+ for (const p of BUILTIN_PATTERNS) {
134
+ if (!grouped[p.category])
135
+ grouped[p.category] = [];
136
+ grouped[p.category].push(p);
137
+ }
138
+ return grouped;
139
+ }
140
+ /**
141
+ * 默认空配置(所有内置模式均启用,无自定义模式)
142
+ */
143
+ export const DEFAULT_COMMAND_SAFETY_CONFIG = {
144
+ disabledPatternIds: [],
145
+ hiddenPatternIds: [],
146
+ customPatterns: [],
147
+ };
148
+ export function classifyShellCommand(command, config) {
58
149
  const normalized = command.trim();
59
- if (!normalized)
150
+ if (!normalized) {
60
151
  return { severity: "safe", matchedRules: [] };
61
- const matches = BUILTIN_PATTERNS.filter((rule) => {
152
+ }
153
+ const disabled = new Set(config?.disabledPatternIds ?? []);
154
+ const matches = BUILTIN_PATTERNS.filter((rule) => !disabled.has(rule.id)).filter((rule) => {
62
155
  const flags = rule.platform === "windows" ? "i" : undefined;
63
156
  return new RegExp(rule.pattern, flags).test(normalized);
64
157
  });
65
- if (!matches.length)
158
+ if (!matches.length) {
66
159
  return { severity: "safe", matchedRules: [] };
160
+ }
161
+ const severity = matches.some((item) => item.severity === "critical") ? "critical" : "warning";
67
162
  return {
68
- severity: matches.some((m) => m.severity === "critical") ? "critical" : "warning",
69
- matchedRules: matches.map((m) => m.id),
163
+ severity,
164
+ matchedRules: matches.map((item) => item.id),
70
165
  };
71
166
  }
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@steerable/agent-harness",
3
- "version": "0.2.4",
3
+ "version": "0.3.0",
4
4
  "description": "Steerable framework Tier 2 — TypeScript facade over the Python harness (policy, budget, retry, completion, tracing) used for cross-language conformance tests. Production code should depend on the Python harness.",
5
5
  "license": "Apache-2.0",
6
- "homepage": "https://pathlyapp.github.io/steerable-framework/",
6
+ "homepage": "https://steerableframework.com/",
7
7
  "repository": {
8
8
  "type": "git",
9
9
  "url": "git+https://github.com/pathlyapp/steerable-framework.git",
@@ -29,7 +29,7 @@
29
29
  "README.md"
30
30
  ],
31
31
  "dependencies": {
32
- "@steerable/agent-protocol": "0.2.4"
32
+ "@steerable/agent-protocol": "0.3.0"
33
33
  },
34
34
  "devDependencies": {
35
35
  "typescript": "^5.8.3",