sentinel-agentos 0.1.2 → 0.2.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.
- package/README.md +878 -7
- package/dist/cli.js +104 -2
- package/dist/cli.js.map +1 -1
- package/package.json +8 -3
- package/scripts/sentinel-light.js +233 -0
package/README.md
CHANGED
|
@@ -261,10 +261,12 @@ Total: 156 | Failures: 2 | High-Risk: 3
|
|
|
261
261
|
## 📦 安装 · Installation
|
|
262
262
|
|
|
263
263
|
```bash
|
|
264
|
-
npm install
|
|
264
|
+
npm install sentinel-agentos
|
|
265
265
|
```
|
|
266
266
|
|
|
267
|
-
|
|
267
|
+
即可使用所有功能。
|
|
268
|
+
|
|
269
|
+
如果从源码开发:
|
|
268
270
|
|
|
269
271
|
```bash
|
|
270
272
|
git clone git@github.com:jishuanjimingtian/Sentinel AgentOS.git
|
|
@@ -278,7 +280,52 @@ npm run build # 编译到 dist/
|
|
|
278
280
|
|
|
279
281
|
## 🚀 使用说明 · Usage
|
|
280
282
|
|
|
281
|
-
###
|
|
283
|
+
### 三种接入方式 · Three Integration Modes
|
|
284
|
+
|
|
285
|
+
Sentinel AgentOS 支持三种接入方式,从轻到重按需选择。
|
|
286
|
+
|
|
287
|
+
| 方式 | 适用场景 | 代码量 | 说明 |
|
|
288
|
+
|------|---------|--------|------|
|
|
289
|
+
| **CLI** | 快速测试 / CI/CD | 1 行命令 | 直接命令行检验工具调用 |
|
|
290
|
+
| **SDK** | 嵌入 Agent 框架 | 5 行代码 | `import { AgentOS }` 在进程内调用 |
|
|
291
|
+
| **HTTP API** | 跨语言 / 远程服务 | HTTP 请求 | 独立 HTTP 服务,任何语言都能调 |
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
### 方式一:CLI(命令行)
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
# 安装
|
|
299
|
+
npm install -g sentinel-agentos
|
|
300
|
+
|
|
301
|
+
# 校验参数
|
|
302
|
+
sentinel-agentos validate exec command="rm -rf /"
|
|
303
|
+
sentinel-agentos validate write_file path=src/main.ts content="console.log(1)"
|
|
304
|
+
|
|
305
|
+
# 风险评分
|
|
306
|
+
sentinel-agentos risk exec command="sudo reboot"
|
|
307
|
+
sentinel-agentos risk exec command="npm test"
|
|
308
|
+
|
|
309
|
+
# 查看审计日志
|
|
310
|
+
sentinel-agentos audit --limit 10
|
|
311
|
+
|
|
312
|
+
# 查看状态报告
|
|
313
|
+
sentinel-agentos status
|
|
314
|
+
|
|
315
|
+
# 启动 HTTP 服务
|
|
316
|
+
sentinel-agentos server --port 3300 --token ***
|
|
317
|
+
|
|
318
|
+
# 查看帮助
|
|
319
|
+
sentinel-agentos help
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
**支持的命令**:`validate` / `risk` / `audit` / `stats` / `profile` / `status` / `server` / `memory` / `help`
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
### 方式二:SDK(代码嵌入)
|
|
327
|
+
|
|
328
|
+
#### 2.1 基础用法 · Basic
|
|
282
329
|
|
|
283
330
|
```typescript
|
|
284
331
|
import { AgentOS } from 'sentinel-agentos';
|
|
@@ -400,6 +447,163 @@ sandbox.validate('rm', { path: 'src/main.ts' });
|
|
|
400
447
|
await sandbox.execute('exec', { command: 'npm test', cwd: process.cwd() });
|
|
401
448
|
```
|
|
402
449
|
|
|
450
|
+
#### 2.2 中间件(一行接入) · Middleware (one-liner)
|
|
451
|
+
|
|
452
|
+
```typescript
|
|
453
|
+
import { wrapAgent } from 'sentinel-agentos';
|
|
454
|
+
|
|
455
|
+
// 一行接入——包裹你的 Agent 工具调用
|
|
456
|
+
const sentinel = wrapAgent({ workspaceRoot: process.cwd() });
|
|
457
|
+
|
|
458
|
+
// 每次工具调用前后调用即可
|
|
459
|
+
const { allowed, reason } = sentinel.preCheck('exec', { command: 'rm -rf /' });
|
|
460
|
+
// → { allowed: false, reason: 'Risk 9.18 → DENY' }
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
#### 2.3 OpenClaw 插件
|
|
464
|
+
|
|
465
|
+
如果你在用 OpenClaw Agent 框架,直接以插件形式集成:
|
|
466
|
+
|
|
467
|
+
```typescript
|
|
468
|
+
import { sentinelPlugin } from 'sentinel-agentos';
|
|
469
|
+
|
|
470
|
+
// 注册为 OpenClaw 插件,自动 hook 所有工具调用
|
|
471
|
+
const plugin = sentinelPlugin({
|
|
472
|
+
workspaceRoot: process.cwd(),
|
|
473
|
+
preRegisteredRules: true,
|
|
474
|
+
});
|
|
475
|
+
// → onBeforeTool → 校验 + 风险评分
|
|
476
|
+
// → onAfterTool → 验证 + 审计
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
481
|
+
### 方式三:HTTP API(远程调用,跨语言通用)
|
|
482
|
+
|
|
483
|
+
Sentinel AgentOS 可启动为独立 HTTP 服务,任何语言(Python/Go/Rust/Java...)都能调用。
|
|
484
|
+
|
|
485
|
+
#### 3.1 启动服务
|
|
486
|
+
|
|
487
|
+
```bash
|
|
488
|
+
# CLI 一行启动
|
|
489
|
+
npx sentinel-agentos server --port 3300 --token ***
|
|
490
|
+
|
|
491
|
+
# 或代码中启动
|
|
492
|
+
import { createServer } from 'sentinel-agentos';
|
|
493
|
+
createServer({ port: 3300, apiToken: '***' }).start();
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
启动后健康检查(免 token):
|
|
497
|
+
```bash
|
|
498
|
+
curl http://localhost:3300/health
|
|
499
|
+
# → {"ok":true,"uptime":12.3}
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
#### 3.2 鉴权
|
|
503
|
+
|
|
504
|
+
除 `/health` 外所有端点需要 `Authorization: Bearer <token>` header。否则返回 `401`。
|
|
505
|
+
|
|
506
|
+
#### 3.3 API 端点参考 · API Reference
|
|
507
|
+
|
|
508
|
+
**基础端点:**
|
|
509
|
+
|
|
510
|
+
| 端点 | 方法 | 鉴权 | 说明 |
|
|
511
|
+
|------|:--:|:--:|------|
|
|
512
|
+
| `/health` | GET | ❌ | 服务健康检查 |
|
|
513
|
+
| `/pipeline/pre` | POST | ✅ | 执行前校验(Schema + Risk + Snapshot) |
|
|
514
|
+
| `/pipeline/post` | POST | ✅ | 执行后验证(Verify + Audit + Feedback) |
|
|
515
|
+
| `/pipeline/report` | GET | ✅ | 质量状态报告(文本) |
|
|
516
|
+
| `/pipeline/profile` | GET | ✅ | 质量画像(JSON) |
|
|
517
|
+
|
|
518
|
+
**Guard / Memory / Feedback / Audit 端点:**
|
|
519
|
+
|
|
520
|
+
| 端点 | 方法 | 说明 |
|
|
521
|
+
|------|:--:|------|
|
|
522
|
+
| `/guard/schema` | POST | 注册 Schema 校验规则 |
|
|
523
|
+
| `/memory/preference` | POST | 设置用户偏好 `{"key":"language","value":"zh-CN"}` |
|
|
524
|
+
| `/memory/fact` | POST | 添加事实 `{"fact":"用户在上海"}` |
|
|
525
|
+
| `/memory/context` | GET | 获取当前记忆上下文 |
|
|
526
|
+
| `/feedback` | POST | 记录隐性反馈 `{"signal":"user_explicit_approval"}` |
|
|
527
|
+
| `/audit` | GET | 查询审计日志(支持 `?limit=&sessionId=&toolName=&status=`) |
|
|
528
|
+
|
|
529
|
+
**反馈信号类型:**
|
|
530
|
+
|
|
531
|
+
| 信号 | 强度 | 说明 |
|
|
532
|
+
|------|------|------|
|
|
533
|
+
| `user_explicit_approval` | +0.6 | 用户明确说"做得好" |
|
|
534
|
+
| `user_immediate_continue` | +0.3 | 用户立即继续对话 |
|
|
535
|
+
| `user_used_result` | +0.7 | 用户使用了 Agent 的结果 |
|
|
536
|
+
| `user_shared_output` | +0.8 | 用户分享了 Agent 输出 |
|
|
537
|
+
| `user_modified_output` | -0.5 | 用户修改了 Agent 输出 |
|
|
538
|
+
| `user_deleted_code` | -0.8 | 用户删除了 Agent 创建的代码 |
|
|
539
|
+
| `user_interrupted` | -0.6 | 用户打断了 Agent |
|
|
540
|
+
| `user_repeated_instruction` | -0.3 | 用户重复了相同指令 |
|
|
541
|
+
|
|
542
|
+
#### 3.4 完整调用示例
|
|
543
|
+
|
|
544
|
+
```bash
|
|
545
|
+
# 1. Pre-exec — 校验 + 风险评分
|
|
546
|
+
curl -s -H "Authorization: Bearer $TOKEN" \
|
|
547
|
+
-X POST http://localhost:3300/pipeline/pre \
|
|
548
|
+
-H 'Content-Type: application/json' \
|
|
549
|
+
-d '{"toolName":"exec","parameters":{"command":"npm test"}}'
|
|
550
|
+
# → {"preExec":{"schemaCheck":{"pass":true},"riskScore":{"score":0.19,"action":"auto"}},"snapshot":{...}}
|
|
551
|
+
|
|
552
|
+
# 2. Post-exec — 验证 + 审计
|
|
553
|
+
# (传入 pre 返回的 snapshot)
|
|
554
|
+
curl -s -H "Authorization: Bearer $TOKEN" \
|
|
555
|
+
-X POST http://localhost:3300/pipeline/post \
|
|
556
|
+
-H 'Content-Type: application/json' \
|
|
557
|
+
-d '{"toolName":"exec","toolParameters":{"command":"npm test"},"toolResult":"all passed","snapshot":{...},"startTime":1718123456000,"endTime":1718123457000,"retryCount":0,"wasSelfCorrected":false,"hadTimeout":false,"userAccepted":true,"userProvidedEdit":false,"resultWasUsed":true}'
|
|
558
|
+
|
|
559
|
+
# 3. 查看报告
|
|
560
|
+
curl -s -H "Authorization: Bearer $TOKEN" http://localhost:3300/pipeline/report
|
|
561
|
+
|
|
562
|
+
# 4. 查询审计
|
|
563
|
+
curl -s -H "Authorization: Bearer $TOKEN" "http://localhost:3300/audit?limit=10&toolName=exec"
|
|
564
|
+
|
|
565
|
+
# 5. 记录反馈
|
|
566
|
+
curl -s -H "Authorization: Bearer $TOKEN" \
|
|
567
|
+
-X POST http://localhost:3300/feedback \
|
|
568
|
+
-H 'Content-Type: application/json' \
|
|
569
|
+
-d '{"signal":"user_immediate_continue","sessionId":"session_1"}'
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
#### 3.5 跨语言(Python 示例)
|
|
573
|
+
|
|
574
|
+
```python
|
|
575
|
+
import requests
|
|
576
|
+
|
|
577
|
+
BASE = "http://localhost:3300"
|
|
578
|
+
HEADERS = {"Authorization": "Bearer ***"}
|
|
579
|
+
|
|
580
|
+
# Pre-exec
|
|
581
|
+
resp = requests.post(f"{BASE}/pipeline/pre", json={
|
|
582
|
+
"toolName": "exec", "parameters": {"command": "npm test"}
|
|
583
|
+
}, headers=HEADERS)
|
|
584
|
+
data = resp.json()
|
|
585
|
+
print(f"Risk: {data['preExec']['riskScore']['score']} → {data['preExec']['riskScore']['action']}")
|
|
586
|
+
|
|
587
|
+
# Post-exec (pass snapshot from pre)
|
|
588
|
+
snapshot = data["snapshot"]
|
|
589
|
+
resp2 = requests.post(f"{BASE}/pipeline/post", json={
|
|
590
|
+
"toolName": "exec",
|
|
591
|
+
"toolParameters": {"command": "npm test"},
|
|
592
|
+
"toolResult": "all passed",
|
|
593
|
+
"snapshot": snapshot,
|
|
594
|
+
"startTime": 1718123456000, "endTime": 1718123457000,
|
|
595
|
+
"retryCount": 0, "wasSelfCorrected": False,
|
|
596
|
+
"hadTimeout": False, "userAccepted": True,
|
|
597
|
+
"userProvidedEdit": False, "resultWasUsed": True
|
|
598
|
+
}, headers=HEADERS)
|
|
599
|
+
print(f"Verify: {resp2.json()['postExec']['verifyPassed']}")
|
|
600
|
+
|
|
601
|
+
# Report
|
|
602
|
+
print(requests.get(f"{BASE}/pipeline/report", headers=HEADERS).text)
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
---
|
|
606
|
+
|
|
403
607
|
### API 层 · SDK API
|
|
404
608
|
|
|
405
609
|
```typescript
|
|
@@ -562,10 +766,10 @@ v1.0 已完成 100% 设计文档覆盖率、99 个测试全通过、TypeScript
|
|
|
562
766
|
</details>
|
|
563
767
|
|
|
564
768
|
<details>
|
|
565
|
-
<summary><b>Q: npm
|
|
769
|
+
<summary><b>Q: npm 包已经发布了吗? · Is npm package published?</b></summary>
|
|
566
770
|
|
|
567
|
-
|
|
568
|
-
*
|
|
771
|
+
已发布。`npm install sentinel-agentos` 即可使用。当前版本 v0.1.x。
|
|
772
|
+
*Published. Just `npm install sentinel-agentos`. Current version v0.1.x.*
|
|
569
773
|
</details>
|
|
570
774
|
|
|
571
775
|
<details>
|
|
@@ -589,6 +793,36 @@ const entries = api.auditQuery({ minScore: 3.0 }); // 高风险操作 · High-ri
|
|
|
589
793
|
```
|
|
590
794
|
</details>
|
|
591
795
|
|
|
796
|
+
<details>
|
|
797
|
+
<summary><b>Q: Sentinel AgentOS 需要 API Key 吗? · Does it need an API Key?</b></summary>
|
|
798
|
+
|
|
799
|
+
不需要。Sentinel AgentOS 的 Guard / Memory / Evaluator 层都是纯确定性代码,不调用任何外部 AI API。唯一的鉴权是 HTTP API 模式下可选的 `--token` 参数。
|
|
800
|
+
*No. All Guard/Memory/Evaluator layers are pure deterministic code with zero external API calls. The only authentication is the optional `--token` for HTTP API mode.*
|
|
801
|
+
</details>
|
|
802
|
+
|
|
803
|
+
<details>
|
|
804
|
+
<summary><b>Q: HTTP API Token 怎么设置? · How to set HTTP API token?</b></summary>
|
|
805
|
+
|
|
806
|
+
三种方式:
|
|
807
|
+
1. 命令行参数:`npx sentinel-agentos server --port 3300 --token my-secret`
|
|
808
|
+
2. 代码中配置:`createServer({ port: 3300, apiToken: 'my-secret' })`
|
|
809
|
+
3. 环境变量:`AGENTOS_TOKEN=*** npx sentinel-agentos server`
|
|
810
|
+
|
|
811
|
+
不设置 Token 则不加鉴权(仅适合本地开发环境)。
|
|
812
|
+
*Three ways: CLI flag, code config, or AGENTOS_TOKEN env var. No token = no auth (local dev only).*
|
|
813
|
+
</details>
|
|
814
|
+
|
|
815
|
+
<details>
|
|
816
|
+
<summary><b>Q: Token 泄漏了怎么办? · What if token leaks?</b></summary>
|
|
817
|
+
|
|
818
|
+
重启服务,换一个新 Token 即可:
|
|
819
|
+
1. 生成新 Token:`openssl rand -hex 32`
|
|
820
|
+
2. 重启 sentinel-agentos server 使用新 Token
|
|
821
|
+
3. 更新所有客户端调用
|
|
822
|
+
Sentinel AgentOS 的 Token 是服务端本地验证的,无需到任何平台撤销。
|
|
823
|
+
*Restart server with a new token. No external platform involved — tokens are validated locally.*
|
|
824
|
+
</details>
|
|
825
|
+
|
|
592
826
|
---
|
|
593
827
|
|
|
594
828
|
## 🗺️ 路线图 · Roadmap
|
|
@@ -600,11 +834,648 @@ const entries = api.auditQuery({ minScore: 3.0 }); // 高风险操作 · High-ri
|
|
|
600
834
|
| v0.3 | Memory 层(3 层)· *Memory layer (3 layers)* | ✅ |
|
|
601
835
|
| v0.4 | Evaluator 层(评估 + 反馈 + 画像)· *Evaluator* | ✅ |
|
|
602
836
|
| v1.0 | 沙箱 + API + x- 扩展 + 校验补齐 · *Sandbox + API + x-ext* | ✅ |
|
|
603
|
-
| v1.1 | npm 发布 · *npm publish* |
|
|
837
|
+
| v1.1 | npm 发布 + 三种接入方式 · *npm publish + 3 modes* | ✅ |
|
|
604
838
|
| v2.0 | Docker 沙箱、Dashboard、SaaS · *Docker sandbox, Dashboard, SaaS* | 📋 |
|
|
605
839
|
|
|
606
840
|
---
|
|
607
841
|
|
|
842
|
+
## 🔑 Token 与鉴权说明
|
|
843
|
+
|
|
844
|
+
Sentinel AgentOS 本身**不依赖外部 AI API**,所有 Guard / Memory / Evaluator 都是纯确定性代码。唯一的鉴权需求来自 **HTTP API 模式**下的 `server` 命令。
|
|
845
|
+
|
|
846
|
+
### HTTP API Token 鉴权
|
|
847
|
+
|
|
848
|
+
启动 HTTP 服务后,除 `/health` 外所有端点都需要 Bearer Token 鉴权。
|
|
849
|
+
|
|
850
|
+
#### 启动时设置 Token
|
|
851
|
+
|
|
852
|
+
```bash
|
|
853
|
+
# 方式一:命令行参数
|
|
854
|
+
npx sentinel-agentos server --port 3300 --token my-secret-token-123
|
|
855
|
+
|
|
856
|
+
# 方式二:代码中配置
|
|
857
|
+
import { createServer } from 'sentinel-agentos';
|
|
858
|
+
const server = createServer({ port: 3300, apiToken: 'my-secret-token-123' });
|
|
859
|
+
await server.start();
|
|
860
|
+
```
|
|
861
|
+
|
|
862
|
+
#### 客户端调用
|
|
863
|
+
|
|
864
|
+
```bash
|
|
865
|
+
# 所有 API(/health 除外)都需要 Authorization header
|
|
866
|
+
curl -H "Authorization: Bearer my-secret-token-123" \
|
|
867
|
+
http://localhost:3300/pipeline/profile
|
|
868
|
+
|
|
869
|
+
# Token 不匹配 → 401 Unauthorized
|
|
870
|
+
curl http://localhost:3300/pipeline/profile
|
|
871
|
+
# → {"error":"Unauthorized: invalid or missing API token"}
|
|
872
|
+
```
|
|
873
|
+
|
|
874
|
+
#### Token 未设置时
|
|
875
|
+
|
|
876
|
+
如果不传 `--token` 或 `apiToken`,服务**不加鉴权**,所有端点可自由访问。适用于本地开发环境,生产环境**强烈建议设置 Token**。
|
|
877
|
+
|
|
878
|
+
```bash
|
|
879
|
+
# 无鉴权模式(仅限本地开发)
|
|
880
|
+
npx sentinel-agentos server --port 3300
|
|
881
|
+
# 所有端点无需 Authorization header
|
|
882
|
+
```
|
|
883
|
+
|
|
884
|
+
#### Token 最佳实践
|
|
885
|
+
|
|
886
|
+
| 环境 | Token 策略 | 示例 |
|
|
887
|
+
|------|----------|------|
|
|
888
|
+
| 本地开发 | 可不用 Token | `npx sentinel-agentos server --port 3300` |
|
|
889
|
+
| 本机测试 | 简短 Token | `--token dev-123` |
|
|
890
|
+
| 生产环境 | 强随机 Token | `--token $(openssl rand -hex 32)` |
|
|
891
|
+
| Docker / CI | 环境变量注入 | `--token $AGENTOS_API_TOKEN` |
|
|
892
|
+
| 跨语言调用 | HTTP header | `Authorization: Bearer <token>` |
|
|
893
|
+
|
|
894
|
+
### 环境变量配置
|
|
895
|
+
|
|
896
|
+
除 Token 外,Sentinel AgentOS 没有其他必填环境变量。可选的环境变量:
|
|
897
|
+
|
|
898
|
+
| 环境变量 | 说明 | 默认值 |
|
|
899
|
+
|---------|------|--------|
|
|
900
|
+
| `HOME` / `USERPROFILE` | 持久化存储根目录 | 系统默认 |
|
|
901
|
+
| `AGENTOS_WORKSPACE` | workspace 根目录 | `process.cwd()` |
|
|
902
|
+
| `AGENTOS_TOKEN` | API Token(备选方式) | — |
|
|
903
|
+
|
|
904
|
+
---
|
|
905
|
+
|
|
906
|
+
## 📋 完整接口使用说明
|
|
907
|
+
|
|
908
|
+
> 本章汇总 Sentinel AgentOS 所有接口——CLI、SDK、HTTP API、中间件、沙箱——作为完整参考。
|
|
909
|
+
|
|
910
|
+
### 命令一览
|
|
911
|
+
|
|
912
|
+
| 分类 | 接口/命令 | 说明 |
|
|
913
|
+
|------|---------|------|
|
|
914
|
+
| CLI | `validate` | 参数格式校验(Schema Gate) |
|
|
915
|
+
| CLI | `risk` | 风险评分(Risk Gate) |
|
|
916
|
+
| CLI | `audit` | 查询审计日志 |
|
|
917
|
+
| CLI | `stats` | 审计统计(JSON) |
|
|
918
|
+
| CLI | `profile` | Agent 质量画像(JSON) |
|
|
919
|
+
| CLI | `status` | 质量状态报告(人类可读) |
|
|
920
|
+
| CLI | `server` | 启动 HTTP API 服务 |
|
|
921
|
+
| CLI | `memory` | 查看注入上下文 |
|
|
922
|
+
| CLI | `help` | 帮助信息 |
|
|
923
|
+
| SDK | `AgentOS` | 主类,完整流水线 |
|
|
924
|
+
| SDK | `AgentOSAPI` | SDK 协议层(25+ 方法) |
|
|
925
|
+
| SDK | `SchemaGate` / `RiskGate` 等 | 独立组件 |
|
|
926
|
+
| SDK | `wrapAgent` | 一行接入中间件 |
|
|
927
|
+
| SDK | `sentinelPlugin` | OpenClaw 插件 |
|
|
928
|
+
| SDK | `SandboxExecutor` | 沙箱执行器 |
|
|
929
|
+
| HTTP | `POST /pipeline/pre` | 执行前校验 |
|
|
930
|
+
| HTTP | `POST /pipeline/post` | 执行后验证 |
|
|
931
|
+
| HTTP | `GET /pipeline/report` | 状态报告 |
|
|
932
|
+
| HTTP | `GET /pipeline/profile` | 质量画像 |
|
|
933
|
+
| HTTP | `POST /guard/schema` | 注册 Schema 规则 |
|
|
934
|
+
| HTTP | `GET /guard/schema` | 查看 Schema 规则 |
|
|
935
|
+
| HTTP | `POST /memory/preference` | 设置偏好 |
|
|
936
|
+
| HTTP | `POST /memory/fact` | 添加事实 |
|
|
937
|
+
| HTTP | `POST /memory/rule` | 学习规则 |
|
|
938
|
+
| HTTP | `GET /memory/context` | 获取注入上下文 |
|
|
939
|
+
| HTTP | `GET /audit` | 查询审计日志 |
|
|
940
|
+
| HTTP | `POST /feedback` | 记录反馈 |
|
|
941
|
+
| HTTP | `POST /session/end` | 结束 session |
|
|
942
|
+
| HTTP | `GET /health` | 健康检查(免 Token) |
|
|
943
|
+
|
|
944
|
+
---
|
|
945
|
+
|
|
946
|
+
### CLI 接口
|
|
947
|
+
|
|
948
|
+
```
|
|
949
|
+
sentinel-agentos <command> [args...]
|
|
950
|
+
```
|
|
951
|
+
|
|
952
|
+
#### `validate` — 参数格式校验
|
|
953
|
+
|
|
954
|
+
```bash
|
|
955
|
+
# 新语法(推荐)
|
|
956
|
+
sentinel-agentos validate <tool> [key=value...]
|
|
957
|
+
|
|
958
|
+
# 校验 exec 命令
|
|
959
|
+
sentinel-agentos validate exec command="rm -rf /"
|
|
960
|
+
# → {"pass":true,"errors":[]}
|
|
961
|
+
|
|
962
|
+
# 校验 write_file(会被 pathDeny 拦截)
|
|
963
|
+
sentinel-agentos validate write_file path=.env content=hello
|
|
964
|
+
# → {"pass":false,"errors":[{"field":"path","message":"path matches deny pattern"}]}
|
|
965
|
+
|
|
966
|
+
# 旧语法(--tool + --params JSON)
|
|
967
|
+
sentinel-agentos validate --tool exec --params '{"command":"npm test"}'
|
|
968
|
+
```
|
|
969
|
+
|
|
970
|
+
| 参数 | 说明 |
|
|
971
|
+
|------|------|
|
|
972
|
+
| `<tool>` | 工具名称(如 `exec`, `write_file`, `delete_file`) |
|
|
973
|
+
| `key=value` | 参数键值对,支持 `key="带空格的值"`,自动检测类型 |
|
|
974
|
+
|
|
975
|
+
#### `risk` — 风险评分
|
|
976
|
+
|
|
977
|
+
```bash
|
|
978
|
+
sentinel-agentos risk exec command="sudo reboot"
|
|
979
|
+
# → {"score":8.5,"action":"deny","dimensions":{"impact":3,"reversibility":0.2,...}}
|
|
980
|
+
|
|
981
|
+
sentinel-agentos risk exec command="npm test"
|
|
982
|
+
# → {"score":0.19,"action":"auto",...}
|
|
983
|
+
```
|
|
984
|
+
|
|
985
|
+
| 风险等级 | 分数 | 动作 |
|
|
986
|
+
|---------|------|------|
|
|
987
|
+
| 🟢 Auto | ≤ 0.5 | 自动放行 |
|
|
988
|
+
| 🔵 Notify | ≤ 1.0 | 执行后通知 |
|
|
989
|
+
| 🟡 Confirm | ≤ 3.0 | 暂停等待确认 |
|
|
990
|
+
| 🔴 Deny | > 8.0 | 直接拒绝 |
|
|
991
|
+
|
|
992
|
+
#### `audit` — 查询审计日志
|
|
993
|
+
|
|
994
|
+
```bash
|
|
995
|
+
sentinel-agentos audit --limit 10
|
|
996
|
+
# → [{id, sessionId, toolName, verifyStatus, riskScore, ...}, ...]
|
|
997
|
+
|
|
998
|
+
sentinel-agentos audit --limit 5
|
|
999
|
+
```
|
|
1000
|
+
|
|
1001
|
+
#### `stats` / `profile` / `status` — 统计与画像
|
|
1002
|
+
|
|
1003
|
+
```bash
|
|
1004
|
+
# 审计统计(JSON)
|
|
1005
|
+
sentinel-agentos stats
|
|
1006
|
+
# → {"totalOperations":156,"verifyFailures":2,"highRiskOps":3,...}
|
|
1007
|
+
|
|
1008
|
+
# Agent 质量画像(JSON)
|
|
1009
|
+
sentinel-agentos profile
|
|
1010
|
+
# → {"overallScore":85,"breakdown":{...},"trends":{...},"warnings":[...]}
|
|
1011
|
+
|
|
1012
|
+
# 质量状态报告(人类可读)
|
|
1013
|
+
sentinel-agentos status
|
|
1014
|
+
# → 文本报告
|
|
1015
|
+
```
|
|
1016
|
+
|
|
1017
|
+
#### `server` — 启动 HTTP API 服务
|
|
1018
|
+
|
|
1019
|
+
```bash
|
|
1020
|
+
sentinel-agentos server --port 3300 --token ***
|
|
1021
|
+
# → 🛡️ Sentinel AgentOS HTTP server → http://127.0.0.1:3300
|
|
1022
|
+
|
|
1023
|
+
# 可选项
|
|
1024
|
+
sentinel-agentos server --port 8080 --host 0.0.0.0 --token ***
|
|
1025
|
+
```
|
|
1026
|
+
|
|
1027
|
+
| 参数 | 默认值 | 说明 |
|
|
1028
|
+
|------|--------|------|
|
|
1029
|
+
| `--port <N>` | `3300` | 服务端口 |
|
|
1030
|
+
| `--host <IP>` | `127.0.0.1` | 绑定地址 |
|
|
1031
|
+
| `--token <str>` | — | API 鉴权 Token(不设则无鉴权) |
|
|
1032
|
+
|
|
1033
|
+
#### `memory` — 查看记忆上下文
|
|
1034
|
+
|
|
1035
|
+
```bash
|
|
1036
|
+
sentinel-agentos memory
|
|
1037
|
+
# → 当前 semantic + episodic 注入的上下文文本
|
|
1038
|
+
```
|
|
1039
|
+
|
|
1040
|
+
---
|
|
1041
|
+
|
|
1042
|
+
### SDK 接口
|
|
1043
|
+
|
|
1044
|
+
#### `AgentOS` — 主类
|
|
1045
|
+
|
|
1046
|
+
```typescript
|
|
1047
|
+
import { AgentOS } from 'sentinel-agentos';
|
|
1048
|
+
|
|
1049
|
+
const aos = new AgentOS({
|
|
1050
|
+
workspaceRoot: process.cwd(), // 工作区根目录
|
|
1051
|
+
maxWorkingTokens: 50000, // 工作记忆 token 上限
|
|
1052
|
+
maxEpisodicSizeKb: 500, // 情景记忆大小上限 (KB)
|
|
1053
|
+
guardConfig: { // Guard 配置
|
|
1054
|
+
riskGate: {
|
|
1055
|
+
autoApprove: 0.5,
|
|
1056
|
+
notify: 1.0,
|
|
1057
|
+
confirm: 3.0,
|
|
1058
|
+
deny: 8.0,
|
|
1059
|
+
},
|
|
1060
|
+
},
|
|
1061
|
+
});
|
|
1062
|
+
```
|
|
1063
|
+
|
|
1064
|
+
**构造函数参数 `AgentOSConfig`**:
|
|
1065
|
+
|
|
1066
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
1067
|
+
|------|------|--------|------|
|
|
1068
|
+
| `workspaceRoot` | string | `process.cwd()` | 工作区根目录,持久化存储位置 |
|
|
1069
|
+
| `maxWorkingTokens` | number | `50000` | 工作记忆最大 token 数 |
|
|
1070
|
+
| `maxEpisodicSizeKb` | number | `500` | 情景记忆最大大小 (KB) |
|
|
1071
|
+
| `guardConfig.riskGate` | object | 见上 | 风险评分阈值覆盖 |
|
|
1072
|
+
| `evaluatorConfig.implicitFeedbackEnabled` | boolean | — | 隐性反馈开关 |
|
|
1073
|
+
|
|
1074
|
+
**核心方法**:
|
|
1075
|
+
|
|
1076
|
+
| 方法 | 返回 | 说明 |
|
|
1077
|
+
|------|------|------|
|
|
1078
|
+
| `executePipeline({...})` | `{preExec, snapshot, profile}` | 执行前校验流水线(Schema + Risk + Snapshot) |
|
|
1079
|
+
| `completeExecution({...})` | `{runtime, postExec, auditEntry, profile}` | 执行后验证流水线(Verify + Audit) |
|
|
1080
|
+
| `recordFeedback(signal, sessionId)` | `void` | 记录隐性用户反馈 |
|
|
1081
|
+
| `injectContext()` | `string` | 注入记忆上下文(session 启动时调用) |
|
|
1082
|
+
| `endSession(sessionId)` | `void` | 结束 session(清空 Working Memory) |
|
|
1083
|
+
| `getProfile(sessionId?)` | `AgentProfile` | 获取 Agent 质量画像 |
|
|
1084
|
+
| `getAuditStats()` | 审计统计 | 获取审计统计 |
|
|
1085
|
+
| `statusReport()` | `string` | 获取人类可读的状态报告 |
|
|
1086
|
+
|
|
1087
|
+
**访问子组件**:
|
|
1088
|
+
|
|
1089
|
+
```typescript
|
|
1090
|
+
// Guard 层
|
|
1091
|
+
aos.guard.schema // SchemaGate — 注册/查询校验规则
|
|
1092
|
+
aos.guard.risk // RiskGate — 风险评分引擎
|
|
1093
|
+
aos.guard.snapshot // SnapshotGate — 执行前快照
|
|
1094
|
+
aos.guard.verify // VerifyGate — 执行后验证
|
|
1095
|
+
aos.guard.audit // AuditLog — 审计日志
|
|
1096
|
+
|
|
1097
|
+
// Memory 层
|
|
1098
|
+
aos.memory.working // WorkingMemory — 当前会话工作记忆
|
|
1099
|
+
aos.memory.episodic // EpisodicMemory — 跨会话事件时间线
|
|
1100
|
+
aos.memory.semantic // SemanticMemoryStore — 永久知识
|
|
1101
|
+
|
|
1102
|
+
// Evaluator 层
|
|
1103
|
+
aos.evaluator.preExec // PreExecEvaluator — 执行前评估
|
|
1104
|
+
aos.evaluator.runtime // RuntimeEvaluator — 执行中评估
|
|
1105
|
+
aos.evaluator.postExec // PostExecEvaluator — 执行后评估
|
|
1106
|
+
aos.evaluator.feedback // ImplicitFeedbackEngine — 隐性反馈
|
|
1107
|
+
aos.evaluator.profiler // AgentProfiler — 质量画像
|
|
1108
|
+
```
|
|
1109
|
+
|
|
1110
|
+
#### `AgentOSAPI` — SDK 协议层
|
|
1111
|
+
|
|
1112
|
+
```typescript
|
|
1113
|
+
import { AgentOS, AgentOSAPI } from 'sentinel-agentos';
|
|
1114
|
+
|
|
1115
|
+
const api = new AgentOSAPI(new AgentOS());
|
|
1116
|
+
|
|
1117
|
+
// Guard
|
|
1118
|
+
api.guardRegisterRule({ tool: 'exec', required: ['command'] });
|
|
1119
|
+
api.guardRegisterRules([...]);
|
|
1120
|
+
api.guardEvaluateRisk('exec', { command: 'rm -rf /' });
|
|
1121
|
+
api.guardSetRiskThresholds({ autoApprove: 0.5, deny: 6.0 });
|
|
1122
|
+
|
|
1123
|
+
// Pipeline
|
|
1124
|
+
const result = await api.pipelineExecute({
|
|
1125
|
+
sessionId: 's1', agentId: 'a1',
|
|
1126
|
+
toolName: 'write_file',
|
|
1127
|
+
toolParameters: { path: 'src/main.ts', content: 'hello' },
|
|
1128
|
+
});
|
|
1129
|
+
const complete = api.pipelineComplete({...});
|
|
1130
|
+
|
|
1131
|
+
// Memory
|
|
1132
|
+
api.memorySetPreference('language', 'zh-CN');
|
|
1133
|
+
api.memoryGetPreference('language'); // → 'zh-CN'
|
|
1134
|
+
api.memoryLearnRule('提交前 npm test', 'session_1');
|
|
1135
|
+
api.memoryDefineTerm('PEP', 'Python Enhancement Proposal');
|
|
1136
|
+
api.memorySetProjectContext('my-app', { description: '...', techStack: ['React', 'Node'] });
|
|
1137
|
+
api.memoryInjectContext(); // → 启动注入文本
|
|
1138
|
+
api.memoryAddMessage('user', 'Hello');
|
|
1139
|
+
api.memoryRecordEvent('decision', 'Chose approach A', ['architecture'], []);
|
|
1140
|
+
|
|
1141
|
+
// Audit
|
|
1142
|
+
api.auditQuery({ toolName: 'exec', limit: 10 });
|
|
1143
|
+
api.auditQuery({ minScore: 3.0 }); // 高风险操作
|
|
1144
|
+
api.auditStats();
|
|
1145
|
+
|
|
1146
|
+
// Feedback
|
|
1147
|
+
api.recordFeedback('user_explicit_approval', 's1');
|
|
1148
|
+
api.getSatisfaction(); // → 82 (0-100)
|
|
1149
|
+
api.getSatisfaction('s1', 24); // 最近 24 小时
|
|
1150
|
+
api.feedbackStats();
|
|
1151
|
+
|
|
1152
|
+
// Profile
|
|
1153
|
+
api.getProfile();
|
|
1154
|
+
api.getProfile('s1');
|
|
1155
|
+
api.getStatusReport();
|
|
1156
|
+
api.getSessionOverview();
|
|
1157
|
+
|
|
1158
|
+
// Session
|
|
1159
|
+
api.endSession('s1');
|
|
1160
|
+
```
|
|
1161
|
+
|
|
1162
|
+
**AgentOSAPI 完整方法清单(25 个)**:
|
|
1163
|
+
|
|
1164
|
+
| 方法 | 说明 |
|
|
1165
|
+
|------|------|
|
|
1166
|
+
| `guardRegisterRule(rule)` | 注册单条 Schema 规则 |
|
|
1167
|
+
| `guardRegisterRules(rules)` | 批量注册 Schema 规则 |
|
|
1168
|
+
| `guardHasRule(toolName)` | 检查工具是否有规则 |
|
|
1169
|
+
| `guardGetRules()` | 获取所有已注册规则 |
|
|
1170
|
+
| `guardEvaluateRisk(tool, params)` | 评估风险评分 |
|
|
1171
|
+
| `guardSetRiskThresholds(thresholds)` | 设置风险阈值 |
|
|
1172
|
+
| `pipelineExecute(params)` | 执行前校验流水线 |
|
|
1173
|
+
| `pipelineComplete(params)` | 执行后验证流水线 |
|
|
1174
|
+
| `memoryInjectContext()` | 注入记忆上下文 |
|
|
1175
|
+
| `memoryAddMessage(role, content)` | 添加工作记忆消息 |
|
|
1176
|
+
| `memorySetTask(task)` | 设置当前任务 |
|
|
1177
|
+
| `memoryCacheResult(tool, result)` | 缓存工具结果 |
|
|
1178
|
+
| `memoryRecordEvent(type, content, tags, entities)` | 记录情景事件 |
|
|
1179
|
+
| `memorySetPreference(key, value)` | 设置用户偏好 |
|
|
1180
|
+
| `memoryGetPreference(key)` | 获取用户偏好 |
|
|
1181
|
+
| `memoryLearnRule(rule, source)` | 学习规则 |
|
|
1182
|
+
| `memoryDefineTerm(term, meaning)` | 定义术语 |
|
|
1183
|
+
| `memorySetProjectContext(name, context)` | 设置项目上下文 |
|
|
1184
|
+
| `auditQuery(filter)` | 查询审计日志 |
|
|
1185
|
+
| `auditStats()` | 审计统计 |
|
|
1186
|
+
| `recordFeedback(signal, sessionId)` | 记录反馈 |
|
|
1187
|
+
| `getSatisfaction(sessionId?, hours?)` | 获取满意度 |
|
|
1188
|
+
| `feedbackStats()` | 反馈统计 |
|
|
1189
|
+
| `getProfile(sessionId?)` | 获取质量画像 |
|
|
1190
|
+
| `getStatusReport()` | 获取状态报告 |
|
|
1191
|
+
| `getSessionOverview()` | 获取 session 概况 |
|
|
1192
|
+
| `endSession(sessionId)` | 结束 session |
|
|
1193
|
+
|
|
1194
|
+
---
|
|
1195
|
+
|
|
1196
|
+
### HTTP API 接口
|
|
1197
|
+
|
|
1198
|
+
基础 URL:`http://localhost:3300`(默认)
|
|
1199
|
+
|
|
1200
|
+
#### Request/Response 通用格式
|
|
1201
|
+
|
|
1202
|
+
- **Content-Type**:`application/json`
|
|
1203
|
+
- **鉴权**:除 `/health` 外,`Authorization: Bearer <token>`
|
|
1204
|
+
- **成功**:`200 OK`,JSON body
|
|
1205
|
+
- **鉴权失败**:`401 Unauthorized`
|
|
1206
|
+
- **参数错误**:`400 Bad Request`,`{"error":"..."}`
|
|
1207
|
+
- **服务错误**:`500 Internal Server Error`
|
|
1208
|
+
|
|
1209
|
+
#### 端点详情
|
|
1210
|
+
|
|
1211
|
+
##### `GET /health` — 健康检查(免 Token)
|
|
1212
|
+
|
|
1213
|
+
```bash
|
|
1214
|
+
curl http://localhost:3300/health
|
|
1215
|
+
# → {"ok":true,"uptime":12.3}
|
|
1216
|
+
```
|
|
1217
|
+
|
|
1218
|
+
##### `POST /pipeline/pre` — 执行前校验
|
|
1219
|
+
|
|
1220
|
+
```bash
|
|
1221
|
+
curl -X POST http://localhost:3300/pipeline/pre \
|
|
1222
|
+
-H "Authorization: Bearer ***" \
|
|
1223
|
+
-H "Content-Type: application/json" \
|
|
1224
|
+
-d '{
|
|
1225
|
+
"sessionId": "s1",
|
|
1226
|
+
"agentId": "main",
|
|
1227
|
+
"toolName": "exec",
|
|
1228
|
+
"parameters": {"command": "npm test"},
|
|
1229
|
+
"affectedFiles": []
|
|
1230
|
+
}'
|
|
1231
|
+
```
|
|
1232
|
+
|
|
1233
|
+
| 字段 | 类型 | 必填 | 说明 |
|
|
1234
|
+
|------|------|------|------|
|
|
1235
|
+
| `toolName` | string | ✅ | 工具名 |
|
|
1236
|
+
| `sessionId` | string | ❌ | 默认 `"http_session"` |
|
|
1237
|
+
| `agentId` | string | ❌ | 默认 `"http_agent"` |
|
|
1238
|
+
| `parameters` | object | ❌ | 工具参数,默认 `{}` |
|
|
1239
|
+
| `affectedFiles` | string[] | ❌ | 受影响的文件列表 |
|
|
1240
|
+
|
|
1241
|
+
**返回**:
|
|
1242
|
+
|
|
1243
|
+
```json
|
|
1244
|
+
{
|
|
1245
|
+
"preExec": {
|
|
1246
|
+
"schemaCheck": { "pass": true, "errors": [] },
|
|
1247
|
+
"riskScore": { "score": 0.19, "action": "auto", "dimensions": {...} },
|
|
1248
|
+
"paramQuality": { "score": 85, "observations": [] },
|
|
1249
|
+
"contextUtilization": { "score": 70, "patterns": [] }
|
|
1250
|
+
},
|
|
1251
|
+
"snapshot": { "id": "...", "fileHashes": {...}, "gitHead": "...", "gitDirty": false },
|
|
1252
|
+
"profile": { "overallScore": 85, ... }
|
|
1253
|
+
}
|
|
1254
|
+
```
|
|
1255
|
+
|
|
1256
|
+
##### `POST /pipeline/post` — 执行后验证
|
|
1257
|
+
|
|
1258
|
+
```bash
|
|
1259
|
+
curl -X POST http://localhost:3300/pipeline/post \
|
|
1260
|
+
-H "Authorization: Bearer ***" \
|
|
1261
|
+
-H "Content-Type: application/json" \
|
|
1262
|
+
-d '{
|
|
1263
|
+
"toolName": "exec",
|
|
1264
|
+
"toolParameters": {"command": "npm test"},
|
|
1265
|
+
"toolResult": "all passed",
|
|
1266
|
+
"snapshot": {...},
|
|
1267
|
+
"startTime": 1718123456000,
|
|
1268
|
+
"endTime": 1718123457000,
|
|
1269
|
+
"retryCount": 0,
|
|
1270
|
+
"wasSelfCorrected": false,
|
|
1271
|
+
"hadTimeout": false,
|
|
1272
|
+
"userAccepted": true,
|
|
1273
|
+
"userProvidedEdit": false,
|
|
1274
|
+
"resultWasUsed": true
|
|
1275
|
+
}'
|
|
1276
|
+
```
|
|
1277
|
+
|
|
1278
|
+
| 字段 | 类型 | 必填 | 说明 |
|
|
1279
|
+
|------|------|------|------|
|
|
1280
|
+
| `toolName` | string | ✅ | 工具名 |
|
|
1281
|
+
| `sessionId` | string | ❌ | session 标识 |
|
|
1282
|
+
| `agentId` | string | ❌ | agent 标识 |
|
|
1283
|
+
| `toolParameters` | object | ❌ | 执行时的参数 |
|
|
1284
|
+
| `toolResult` | any | ❌ | 工具返回结果 |
|
|
1285
|
+
| `snapshot` | object | ❌ | 从 `/pipeline/pre` 获取的 snapshot |
|
|
1286
|
+
| `startTime` | number | ❌ | 执行开始时间戳 ms |
|
|
1287
|
+
| `endTime` | number | ❌ | 执行结束时间戳 ms |
|
|
1288
|
+
| `retryCount` | number | ❌ | 重试次数,默认 0 |
|
|
1289
|
+
| `wasSelfCorrected` | boolean | ❌ | Agent 是否自我纠正 |
|
|
1290
|
+
| `hadTimeout` | boolean | ❌ | 是否超时 |
|
|
1291
|
+
| `userAccepted` | boolean | ❌ | 用户是否接受了结果 |
|
|
1292
|
+
| `userProvidedEdit` | boolean | ❌ | 用户是否修改了结果 |
|
|
1293
|
+
| `resultWasUsed` | boolean | ❌ | 用户是否使用了结果 |
|
|
1294
|
+
|
|
1295
|
+
##### `GET /pipeline/report` / `GET /pipeline/profile`
|
|
1296
|
+
|
|
1297
|
+
```bash
|
|
1298
|
+
curl -H "Authorization: Bearer ***" http://localhost:3300/pipeline/report
|
|
1299
|
+
# → {"report":"=== AgentOS Status Report ===\n..."}
|
|
1300
|
+
|
|
1301
|
+
curl -H "Authorization: Bearer ***" http://localhost:3300/pipeline/profile
|
|
1302
|
+
curl -H "Authorization: Bearer ***" "http://localhost:3300/pipeline/profile?sessionId=s1"
|
|
1303
|
+
```
|
|
1304
|
+
|
|
1305
|
+
##### `POST /guard/schema` / `GET /guard/schema`
|
|
1306
|
+
|
|
1307
|
+
```bash
|
|
1308
|
+
# 注册规则
|
|
1309
|
+
curl -X POST http://localhost:3300/guard/schema \
|
|
1310
|
+
-H "Authorization: Bearer ***" \
|
|
1311
|
+
-H "Content-Type: application/json" \
|
|
1312
|
+
-d '{"tool":"delete_file","required":["path"],"forbidden":[]}'
|
|
1313
|
+
# → {"ok":true,"tool":"delete_file"}
|
|
1314
|
+
|
|
1315
|
+
# 查看规则
|
|
1316
|
+
curl -H "Authorization: Bearer ***" "http://localhost:3300/guard/schema?tool=delete_file"
|
|
1317
|
+
```
|
|
1318
|
+
|
|
1319
|
+
##### Memory 端点(4 个)
|
|
1320
|
+
|
|
1321
|
+
```bash
|
|
1322
|
+
# 设置偏好
|
|
1323
|
+
curl -X POST http://localhost:3300/memory/preference \
|
|
1324
|
+
-H "Authorization: Bearer ***" -H "Content-Type: application/json" \
|
|
1325
|
+
-d '{"key":"language","value":"zh-CN"}'
|
|
1326
|
+
|
|
1327
|
+
# 添加事实
|
|
1328
|
+
curl -X POST http://localhost:3300/memory/fact \
|
|
1329
|
+
-H "Authorization: Bearer ***" -H "Content-Type: application/json" \
|
|
1330
|
+
-d '{"fact":"用户在北京"}'
|
|
1331
|
+
|
|
1332
|
+
# 学习规则
|
|
1333
|
+
curl -X POST http://localhost:3300/memory/rule \
|
|
1334
|
+
-H "Authorization: Bearer ***" -H "Content-Type: application/json" \
|
|
1335
|
+
-d '{"rule":"提交前运行 npm test","source":"session_1"}'
|
|
1336
|
+
|
|
1337
|
+
# 获取注入上下文
|
|
1338
|
+
curl -H "Authorization: Bearer ***" http://localhost:3300/memory/context
|
|
1339
|
+
```
|
|
1340
|
+
|
|
1341
|
+
##### `GET /audit` — 审计查询
|
|
1342
|
+
|
|
1343
|
+
```bash
|
|
1344
|
+
curl -H "Authorization: Bearer ***" "http://localhost:3300/audit?limit=10"
|
|
1345
|
+
curl -H "Authorization: Bearer ***" "http://localhost:3300/audit?toolName=exec&status=FAIL"
|
|
1346
|
+
```
|
|
1347
|
+
|
|
1348
|
+
| 查询参数 | 说明 |
|
|
1349
|
+
|---------|------|
|
|
1350
|
+
| `limit` | 返回条数(默认 20) |
|
|
1351
|
+
| `toolName` | 按工具名过滤 |
|
|
1352
|
+
| `status` | 按校验状态过滤:`PASS` / `WARN` / `FAIL` |
|
|
1353
|
+
|
|
1354
|
+
##### `POST /feedback` — 记录隐性反馈
|
|
1355
|
+
|
|
1356
|
+
```bash
|
|
1357
|
+
curl -X POST http://localhost:3300/feedback \
|
|
1358
|
+
-H "Authorization: Bearer ***" -H "Content-Type: application/json" \
|
|
1359
|
+
-d '{"signal":"user_explicit_approval","sessionId":"s1"}'
|
|
1360
|
+
```
|
|
1361
|
+
|
|
1362
|
+
**支持的 signal 值**:
|
|
1363
|
+
|
|
1364
|
+
| Signal | 强度 | 说明 |
|
|
1365
|
+
|--------|------|------|
|
|
1366
|
+
| `user_explicit_approval` | +0.6 | 用户明确说"做得好" |
|
|
1367
|
+
| `user_immediate_continue` | +0.3 | 用户立即继续对话 |
|
|
1368
|
+
| `user_used_result` | +0.7 | 用户使用了 Agent 的结果 |
|
|
1369
|
+
| `user_shared_output` | +0.8 | 用户分享了 Agent 输出 |
|
|
1370
|
+
| `user_modified_output` | -0.5 | 用户修改了 Agent 输出 |
|
|
1371
|
+
| `user_deleted_code` | -0.8 | 用户删除了 Agent 创建的代码 |
|
|
1372
|
+
| `user_interrupted` | -0.6 | 用户打断了 Agent |
|
|
1373
|
+
| `user_repeated_instruction` | -0.3 | 用户重复了相同指令 |
|
|
1374
|
+
|
|
1375
|
+
##### `POST /session/end` — 结束 Session
|
|
1376
|
+
|
|
1377
|
+
```bash
|
|
1378
|
+
curl -X POST http://localhost:3300/session/end \
|
|
1379
|
+
-H "Authorization: Bearer ***" -H "Content-Type: application/json" \
|
|
1380
|
+
-d '{"sessionId":"s1"}'
|
|
1381
|
+
# → {"ok":true}
|
|
1382
|
+
```
|
|
1383
|
+
|
|
1384
|
+
---
|
|
1385
|
+
|
|
1386
|
+
### 中间件 / 插件接口
|
|
1387
|
+
|
|
1388
|
+
#### `wrapAgent` — 一行接入中间件
|
|
1389
|
+
|
|
1390
|
+
```typescript
|
|
1391
|
+
import { wrapAgent } from 'sentinel-agentos';
|
|
1392
|
+
|
|
1393
|
+
const sentinel = wrapAgent({ workspaceRoot: process.cwd() });
|
|
1394
|
+
|
|
1395
|
+
// 每个工具调用前后调用
|
|
1396
|
+
const { allowed, reason } = sentinel.preCheck('exec', { command: 'rm -rf /' });
|
|
1397
|
+
// → { allowed: false, reason: 'Risk 9.18 → DENY' }
|
|
1398
|
+
|
|
1399
|
+
const { allowed } = sentinel.preCheck('exec', { command: 'npm test' });
|
|
1400
|
+
// → { allowed: true }
|
|
1401
|
+
|
|
1402
|
+
// 执行后验证
|
|
1403
|
+
sentinel.postCheck('exec', { command: 'npm test' }, 'all passed');
|
|
1404
|
+
```
|
|
1405
|
+
|
|
1406
|
+
**`wrapAgent` 参数**:
|
|
1407
|
+
|
|
1408
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
1409
|
+
|------|------|--------|------|
|
|
1410
|
+
| `workspaceRoot` | string | `process.cwd()` | 工作区根目录 |
|
|
1411
|
+
| `maxWorkingTokens` | number | `50000` | 工作记忆 token 上限 |
|
|
1412
|
+
| `preRegisteredRules` | boolean | `false` | 是否使用内置默认规则 |
|
|
1413
|
+
|
|
1414
|
+
#### `sentinelPlugin` — OpenClaw 插件
|
|
1415
|
+
|
|
1416
|
+
```typescript
|
|
1417
|
+
import { sentinelPlugin } from 'sentinel-agentos';
|
|
1418
|
+
|
|
1419
|
+
const plugin = sentinelPlugin({
|
|
1420
|
+
workspaceRoot: process.cwd(),
|
|
1421
|
+
preRegisteredRules: true,
|
|
1422
|
+
});
|
|
1423
|
+
// → onBeforeTool → Schema + Risk 校验
|
|
1424
|
+
// → onAfterTool → Verify + Audit 记录
|
|
1425
|
+
```
|
|
1426
|
+
|
|
1427
|
+
---
|
|
1428
|
+
|
|
1429
|
+
### Sandbox 沙箱接口
|
|
1430
|
+
|
|
1431
|
+
```typescript
|
|
1432
|
+
import { SandboxExecutor } from 'sentinel-agentos';
|
|
1433
|
+
|
|
1434
|
+
const sandbox = new SandboxExecutor({
|
|
1435
|
+
mode: 'sandbox', // 'direct' | 'sandbox' | 'dry-run'
|
|
1436
|
+
workspaceRoot: process.cwd(),
|
|
1437
|
+
timeoutMs: 30000, // 命令超时 30s
|
|
1438
|
+
networkAccess: 'whitelist', // 'none' | 'localhost' | 'whitelist'
|
|
1439
|
+
networkWhitelist: ['api.github.com', 'registry.npmjs.org'],
|
|
1440
|
+
writablePaths: ['src/', 'tests/', 'dist/'],
|
|
1441
|
+
readonlyPaths: ['node_modules/', '.git/'],
|
|
1442
|
+
allowedTools: ['read_file', 'write_file', 'edit', 'exec'],
|
|
1443
|
+
forbiddenTools: ['rm', 'unlink', 'delete_file'],
|
|
1444
|
+
});
|
|
1445
|
+
|
|
1446
|
+
// 预检
|
|
1447
|
+
const check = sandbox.validate('exec', { command: 'curl evil.com' });
|
|
1448
|
+
// → { success: false, sandboxRejectReason: 'Network not in whitelist' }
|
|
1449
|
+
|
|
1450
|
+
// 执行
|
|
1451
|
+
const result = await sandbox.execute('exec', { command: 'npm test' });
|
|
1452
|
+
// → { success: true, result: {...} }
|
|
1453
|
+
```
|
|
1454
|
+
|
|
1455
|
+
**`SandboxExecutor` 构造参数**:
|
|
1456
|
+
|
|
1457
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
1458
|
+
|------|------|--------|------|
|
|
1459
|
+
| `mode` | `'direct' | 'sandbox' | 'dry-run'` | `'sandbox'` | 执行模式 |
|
|
1460
|
+
| `workspaceRoot` | string | `process.cwd()` | 工作区根目录 |
|
|
1461
|
+
| `timeoutMs` | number | `30000` | 命令超时毫秒 |
|
|
1462
|
+
| `networkAccess` | `'none' | 'localhost' | 'whitelist'` | `'localhost'` | 网络策略 |
|
|
1463
|
+
| `networkWhitelist` | string[] | `[]` | 网络白名单域名 |
|
|
1464
|
+
| `writablePaths` | string[] | `[]` | 可写路径 |
|
|
1465
|
+
| `readonlyPaths` | string[] | `[]` | 只读路径 |
|
|
1466
|
+
| `allowedTools` | string[] | `[]` | 允许的工具 |
|
|
1467
|
+
| `forbiddenTools` | string[] | `[]` | 禁止的工具 |
|
|
1468
|
+
|
|
1469
|
+
**执行模式说明**:
|
|
1470
|
+
|
|
1471
|
+
| 模式 | 说明 |
|
|
1472
|
+
|------|------|
|
|
1473
|
+
| `direct` | 直接执行,无限制 |
|
|
1474
|
+
| `sandbox` | 沙箱模式,受限的文件系统和网络访问 |
|
|
1475
|
+
| `dry-run` | 试运行,不实际执行,只校验权限 |
|
|
1476
|
+
|
|
1477
|
+
---
|
|
1478
|
+
|
|
608
1479
|
## 📂 源码结构 · Source Layout
|
|
609
1480
|
|
|
610
1481
|
```
|
package/dist/cli.js
CHANGED
|
@@ -59,17 +59,22 @@ Usage:
|
|
|
59
59
|
sentinel-agentos stats
|
|
60
60
|
sentinel-agentos profile
|
|
61
61
|
sentinel-agentos status
|
|
62
|
-
sentinel-agentos server [--port N] [--token
|
|
62
|
+
sentinel-agentos server [--port N] [--token ***
|
|
63
|
+
sentinel-agentos init (一键安装 Guard Skill 到 OpenClaw workspace)
|
|
63
64
|
sentinel-agentos memory
|
|
64
65
|
sentinel-agentos help
|
|
65
66
|
|
|
67
|
+
Quick start:
|
|
68
|
+
sentinel-agentos init # 安装 Sentinel Guard Skill → 自动启用全部功能
|
|
69
|
+
sentinel-agentos status # 查看质量报告
|
|
70
|
+
|
|
66
71
|
Examples:
|
|
67
72
|
sentinel-agentos validate exec command="rm -rf /"
|
|
68
73
|
sentinel-agentos validate write_file path=src/main.ts content="console.log(1)"
|
|
69
74
|
sentinel-agentos risk exec command="sudo reboot"
|
|
70
75
|
sentinel-agentos audit --limit 10
|
|
71
76
|
sentinel-agentos status
|
|
72
|
-
sentinel-agentos server --port 3300 --token
|
|
77
|
+
sentinel-agentos server --port 3300 --token ***
|
|
73
78
|
`);
|
|
74
79
|
}
|
|
75
80
|
function fatal(msg) {
|
|
@@ -234,6 +239,103 @@ async function main() {
|
|
|
234
239
|
console.log(context || '(no memory context yet)');
|
|
235
240
|
break;
|
|
236
241
|
}
|
|
242
|
+
case 'init': {
|
|
243
|
+
const fs = await Promise.resolve().then(() => __importStar(require('fs')));
|
|
244
|
+
const path = await Promise.resolve().then(() => __importStar(require('path')));
|
|
245
|
+
// Find OpenClaw workspace (from env or common locations)
|
|
246
|
+
const home = process.env.USERPROFILE || process.env.HOME || '~';
|
|
247
|
+
const workspaceDir = process.env.OPENCLAW_WORKSPACE || path.join(home, '.openclaw', 'workspace');
|
|
248
|
+
if (!fs.existsSync(workspaceDir)) {
|
|
249
|
+
fatal(`Workspace not found: ${workspaceDir}. Set OPENCLAW_WORKSPACE or run from workspace root.`);
|
|
250
|
+
}
|
|
251
|
+
const skillDir = path.join(workspaceDir, 'skills', 'sentinel-guard');
|
|
252
|
+
const scriptsDir = path.join(skillDir, 'scripts');
|
|
253
|
+
if (fs.existsSync(skillDir)) {
|
|
254
|
+
console.log('⚠ Sentinel Guard skill already installed at:');
|
|
255
|
+
console.log(' ' + skillDir);
|
|
256
|
+
console.log('\nRun sentinel-agentos status to check current state.');
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
// Create skill directory
|
|
260
|
+
fs.mkdirSync(skillDir, { recursive: true });
|
|
261
|
+
fs.mkdirSync(scriptsDir, { recursive: true });
|
|
262
|
+
// Source light guard from dist/scripts
|
|
263
|
+
const guardSrc = path.join(__dirname, '..', 'scripts', 'sentinel-light.js');
|
|
264
|
+
let guardContent;
|
|
265
|
+
if (fs.existsSync(guardSrc)) {
|
|
266
|
+
guardContent = fs.readFileSync(guardSrc, 'utf-8');
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
// Fallback: use the one from src (dev mode)
|
|
270
|
+
const fallback = path.join(__dirname, '..', '..', 'scripts', 'sentinel-light.js');
|
|
271
|
+
if (fs.existsSync(fallback)) {
|
|
272
|
+
guardContent = fs.readFileSync(fallback, 'utf-8');
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
fatal('Guard script not found. Reinstall sentinel-agentos.');
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
// Write guard script
|
|
279
|
+
fs.writeFileSync(path.join(skillDir, 'sentinel-guard.js'), guardContent);
|
|
280
|
+
// Write SKILL.md
|
|
281
|
+
const skillMd = `---
|
|
282
|
+
name: sentinel-guard
|
|
283
|
+
description: "Sentinel AgentOS Guard — 确定性代码审查守卫,拦截危险命令和敏感文件操作。"
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
# Sentinel AgentOS Guard
|
|
287
|
+
|
|
288
|
+
拦截危险操作和敏感文件修改,基于确定性规则而非 LLM。
|
|
289
|
+
|
|
290
|
+
## 使用
|
|
291
|
+
|
|
292
|
+
\`\`\`javascript
|
|
293
|
+
const guard = require('./sentinel-guard');
|
|
294
|
+
const check = guard.preCheck('exec', { command: 'rm -rf /' });
|
|
295
|
+
if (!check.passed) return { blocked: true, reason: check.reason };
|
|
296
|
+
\`\`\`
|
|
297
|
+
|
|
298
|
+
## 三层防护
|
|
299
|
+
|
|
300
|
+
- 🛡️ 命令黑名单:rm -rf /、sudo rm、mkfs、fork bomb 等
|
|
301
|
+
- 🔒 Schema Gate:拦截 .env、*.key、*.pem 等敏感文件
|
|
302
|
+
- ⚠️ Risk Gate:git push --force、npm publish 需确认
|
|
303
|
+
|
|
304
|
+
## 快速测试
|
|
305
|
+
|
|
306
|
+
\`\`\`bash
|
|
307
|
+
node scripts/test-suite.js
|
|
308
|
+
\`\`\`
|
|
309
|
+
`;
|
|
310
|
+
fs.writeFileSync(path.join(skillDir, 'SKILL.md'), skillMd);
|
|
311
|
+
// Write test suite
|
|
312
|
+
const testContent = `#!/usr/bin/env node
|
|
313
|
+
const guard = require('../sentinel-guard');
|
|
314
|
+
['exec rm -rf /', 'write .env', 'exec npm test'].forEach(t => {
|
|
315
|
+
const s = t.split(' ');
|
|
316
|
+
const r = guard.preCheck(s[0], s[0] === 'exec' ? {command: s.slice(1).join(' ')} : {path: s[1], content:'x'});
|
|
317
|
+
console.log(r.block ? '🚫 ' + r.reason : '✅ ' + t);
|
|
318
|
+
});
|
|
319
|
+
`;
|
|
320
|
+
fs.writeFileSync(path.join(scriptsDir, 'test-suite.js'), testContent);
|
|
321
|
+
// Add .sentinel-audit to .gitignore if exists
|
|
322
|
+
const gitignore = path.join(workspaceDir, '.gitignore');
|
|
323
|
+
if (fs.existsSync(gitignore)) {
|
|
324
|
+
const giContent = fs.readFileSync(gitignore, 'utf-8');
|
|
325
|
+
if (!giContent.includes('.sentinel-audit')) {
|
|
326
|
+
fs.appendFileSync(gitignore, '\n# Sentinel AgentOS audit logs\n.sentinel-audit/\n');
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
console.log('✅ Sentinel AgentOS Guard 安装完成!\n');
|
|
330
|
+
console.log('📂 Skill: ' + skillDir);
|
|
331
|
+
console.log('🛡️ Guard: ' + path.join(skillDir, 'sentinel-guard.js'));
|
|
332
|
+
console.log('');
|
|
333
|
+
console.log('下一步:');
|
|
334
|
+
console.log(' 1. Agent 重启后自动加载 Guard');
|
|
335
|
+
console.log(' 2. 运行 sentinel-agentos status 查看状态');
|
|
336
|
+
console.log(' 3. 或在代码中 require: const guard = require("./sentinel-guard")');
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
237
339
|
default:
|
|
238
340
|
fatal(`Unknown command: ${cmd}. Run 'sentinel-agentos help' for usage.`);
|
|
239
341
|
}
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;AAEA;;;;;;;;;;;;GAYG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,iCAAiC;AAEjC,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,CAAC
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sentinel-agentos",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Sentinel AgentOS — 确定性 Guard 层 + 分层记忆 + 自动评估,让任何 Agent 变得可靠、可审计、可改进",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"files": [
|
|
27
27
|
"dist/",
|
|
28
|
+
"scripts/sentinel-light.js",
|
|
28
29
|
"README.md",
|
|
29
30
|
"LICENSE"
|
|
30
31
|
],
|
|
@@ -49,16 +50,20 @@
|
|
|
49
50
|
"@typescript-eslint/parser": "^7.0.0",
|
|
50
51
|
"eslint": "^8.0.0",
|
|
51
52
|
"eslint-config-prettier": "^9.0.0",
|
|
53
|
+
"fluent-ffmpeg": "^2.1.3",
|
|
52
54
|
"jest": "^29.0.0",
|
|
53
55
|
"prettier": "^3.0.0",
|
|
54
56
|
"ts-jest": "^29.0.0",
|
|
55
|
-
"typescript": "^5.4.0"
|
|
57
|
+
"typescript": "^5.4.0",
|
|
58
|
+
"videoshow": "^0.1.12"
|
|
56
59
|
},
|
|
57
60
|
"engines": {
|
|
58
61
|
"node": ">=18"
|
|
59
62
|
},
|
|
60
63
|
"dependencies": {
|
|
61
64
|
"cors": "^2.8.6",
|
|
62
|
-
"express": "^5.2.1"
|
|
65
|
+
"express": "^5.2.1",
|
|
66
|
+
"puppeteer": "^25.1.0",
|
|
67
|
+
"ws": "^8.21.0"
|
|
63
68
|
}
|
|
64
69
|
}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sentinel AgentOS Full Guard — 全功能版
|
|
3
|
+
*
|
|
4
|
+
* preCheck: 轻量拦截(4.4μs)
|
|
5
|
+
* postCheck: 完整审计 + 三层记忆 + 三阶段评估 + 隐性反馈
|
|
6
|
+
*
|
|
7
|
+
* 模块初始化时自动注入语义记忆上下文到 session。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const { AgentOS } = require('sentinel-agentos');
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
|
|
14
|
+
const AUDIT_DIR = path.join(__dirname, '..', '.sentinel-audit');
|
|
15
|
+
|
|
16
|
+
// 全局单例
|
|
17
|
+
if (!global.__sentinel_aos) {
|
|
18
|
+
const aos = new AgentOS({
|
|
19
|
+
workspaceRoot: process.cwd(),
|
|
20
|
+
maxWorkingTokens: 50000,
|
|
21
|
+
maxEpisodicSizeKb: 500,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// 注册全套 Schema 规则
|
|
25
|
+
aos.guard.schema.registerRules([
|
|
26
|
+
{ tool: 'exec', required: ['command'] },
|
|
27
|
+
{
|
|
28
|
+
tool: 'write', required: ['path', 'content'],
|
|
29
|
+
pathDeny: { path: ['.env', '*.key', '*.pem', '.git/**', '**/credentials/**'] },
|
|
30
|
+
maxSize: { content: 1048576 }, secrets: ['content'],
|
|
31
|
+
},
|
|
32
|
+
{ tool: 'read', required: ['path'], pathDeny: { path: ['.env', '*.key'] } },
|
|
33
|
+
{ tool: 'edit', required: ['path'], pathDeny: { path: ['.env', '*.key', '.git/**'] } },
|
|
34
|
+
{
|
|
35
|
+
tool: 'delete', required: ['path'],
|
|
36
|
+
pathDeny: { path: ['.env', '*.key', '*.pem', '.git/**', 'node_modules/**', 'package.json'] },
|
|
37
|
+
},
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
// 从磁盘恢复审计
|
|
41
|
+
const auditFile = path.join(AUDIT_DIR, 'audit.jsonl');
|
|
42
|
+
if (fs.existsSync(auditFile)) {
|
|
43
|
+
try {
|
|
44
|
+
fs.readFileSync(auditFile, 'utf-8').trim().split('\n').filter(Boolean).forEach(line => {
|
|
45
|
+
aos.guard.audit.entries.push(JSON.parse(line));
|
|
46
|
+
});
|
|
47
|
+
} catch {}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// 注入默认语义记忆
|
|
51
|
+
aos.memory.semantic.setPreference('user-name', '老板');
|
|
52
|
+
aos.memory.semantic.setPreference('language', 'zh-CN');
|
|
53
|
+
aos.memory.semantic.setPreference('direct-communication', true);
|
|
54
|
+
aos.memory.semantic.addFact('老板是中国用户,偏好直接、不说废话');
|
|
55
|
+
aos.memory.semantic.addFact('项目 coderev 是 AI 代码审查 CLI 工具');
|
|
56
|
+
aos.memory.semantic.addFact('项目 sentinel-agentos 是 AI Agent 操作系统');
|
|
57
|
+
aos.memory.semantic.learnRule('高风险操作前必须 preCheck', 'sentinel_init');
|
|
58
|
+
aos.memory.semantic.learnRule('操作完成后必须 postCheck 审计', 'sentinel_init');
|
|
59
|
+
aos.memory.semantic.learnRule('npm publish 前必须确认版本号', 'sentinel_init');
|
|
60
|
+
|
|
61
|
+
// 记录首次启动事件
|
|
62
|
+
aos.memory.episodic.record('milestone',
|
|
63
|
+
'Sentinel AgentOS 全功能启用:Guard + Memory + Evaluator',
|
|
64
|
+
['init', 'milestone'], ['sentinel-agentos']);
|
|
65
|
+
|
|
66
|
+
global.__sentinel_aos = aos;
|
|
67
|
+
global.__sentinel_session_id = 1;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const aos = global.__sentinel_aos;
|
|
71
|
+
let opCounter = 0;
|
|
72
|
+
|
|
73
|
+
// ── 确定性规则(零 LLM)──
|
|
74
|
+
const DANGEROUS = [
|
|
75
|
+
[/rm\s+-rf\s+\//, 'rm -rf / — 删除整个系统'],
|
|
76
|
+
[/rm\s+-rf\s+~/, 'rm -rf ~ — 删除用户目录'],
|
|
77
|
+
[/sudo\s+rm/, 'sudo rm — 超级用户删除'],
|
|
78
|
+
[/mkfs\./, 'mkfs — 格式化磁盘'],
|
|
79
|
+
[/dd\s+if=/, 'dd — 可能覆盖分区'],
|
|
80
|
+
[/fork\s*bomb|:\(\)/, 'fork bomb — 系统崩溃'],
|
|
81
|
+
[/chmod\s+777\s+-R\s*\//, 'chmod 777 -R / — 权限全开'],
|
|
82
|
+
[/del\s+\/F\s+\/S\s+[A-Z]:\\/, 'del /F /S — 全盘删除'],
|
|
83
|
+
[/>\s*\/dev\/sd[a-z]/, '写入磁盘设备'],
|
|
84
|
+
];
|
|
85
|
+
const WARNING = [
|
|
86
|
+
[/git\s+push\s+--force/, 'git push --force — 强制覆盖'],
|
|
87
|
+
[/git\s+reset\s+--hard/, 'git reset --hard — 不可逆'],
|
|
88
|
+
[/npm\s+publish\b/, 'npm publish — 发布公共包'],
|
|
89
|
+
[/npm\s+unpublish\b/, 'npm unpublish — 从 npm 删除'],
|
|
90
|
+
[/DROP\s+(TABLE|DATABASE)/i, 'DROP — 删除数据库'],
|
|
91
|
+
[/TRUNCATE\s+(TABLE\s+)?/i, 'TRUNCATE — 清空表'],
|
|
92
|
+
];
|
|
93
|
+
const SENSITIVE = [
|
|
94
|
+
'.env', '.env.*', '*.key', '*.pem', '*.p12', '*.pfx', '*.jks', '*.keystore',
|
|
95
|
+
'.git/**', '**/credentials/**', '**/secrets/**', '**/SECRETS/**',
|
|
96
|
+
'package.json', 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'Cargo.lock',
|
|
97
|
+
];
|
|
98
|
+
const PROTECTED = [
|
|
99
|
+
'package.json', 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml',
|
|
100
|
+
'.gitignore', '.gitattributes', 'Cargo.toml', 'Cargo.lock', 'tsconfig.json',
|
|
101
|
+
'AGENTS.md', 'SOUL.md', 'MEMORY.md', 'USER.md',
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
function globMatch(pattern, p) {
|
|
105
|
+
p = (p || '').replace(/\\/g, '/');
|
|
106
|
+
if (!pattern.includes('*')) return p === pattern || p.endsWith('/' + pattern);
|
|
107
|
+
const re = '^' + pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*\*\//g, '(.*/)?').replace(/\*/g, '[^/]*') + '$';
|
|
108
|
+
return new RegExp(re).test(p);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
module.exports = {
|
|
112
|
+
// ── 执行前拦截 ──
|
|
113
|
+
preCheck(toolName, params) {
|
|
114
|
+
if (toolName === 'exec' && params.command) {
|
|
115
|
+
const cmd = String(params.command);
|
|
116
|
+
for (const [re, desc] of DANGEROUS) {
|
|
117
|
+
if (re.test(cmd)) return { passed: false, block: true, risk: 'DENY', reason: `🚫 危险命令: ${desc}` };
|
|
118
|
+
}
|
|
119
|
+
for (const [re, desc] of WARNING) {
|
|
120
|
+
if (re.test(cmd)) return { passed: false, block: true, risk: 'CONFIRM', reason: `⚠️ 需要确认: ${desc}`, needsConfirmation: true };
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const p = params.path || params.file;
|
|
124
|
+
if (p && ['write', 'edit', 'delete', 'read'].includes(toolName)) {
|
|
125
|
+
for (const ptn of SENSITIVE) {
|
|
126
|
+
if (globMatch(ptn, p)) return { passed: false, block: true, risk: 'DENY', reason: `🚫 敏感文件: "${p}" → "${ptn}"` };
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (toolName === 'delete' && p) {
|
|
130
|
+
for (const pf of PROTECTED) {
|
|
131
|
+
if (String(p) === pf || String(p).endsWith('/' + pf) || String(p).endsWith('\\' + pf))
|
|
132
|
+
return { passed: false, block: true, risk: 'DENY', reason: `🚫 保护文件: "${pf}"` };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return { passed: true, risk: 'auto' };
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
// ── 执行后完整审计 ──
|
|
139
|
+
postCheck(toolName, params, result) {
|
|
140
|
+
const sid = `s${global.__sentinel_session_id}_op${++opCounter}`;
|
|
141
|
+
|
|
142
|
+
// 记录到 Working Memory
|
|
143
|
+
aos.memory.working.addMessage('tool', `${toolName}: ${JSON.stringify(params || {}).slice(0, 200)}`);
|
|
144
|
+
|
|
145
|
+
// AgentOS 完整流水线
|
|
146
|
+
const { preExec, snapshot } = aos.executePipeline({
|
|
147
|
+
sessionId: sid, agentId: 'openclaw', toolName, parameters: params || {},
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const t = Date.now();
|
|
151
|
+
try {
|
|
152
|
+
const ret = aos.completeExecution({
|
|
153
|
+
sessionId: sid, agentId: 'openclaw', toolName,
|
|
154
|
+
toolParameters: params || {}, toolResult: result ?? null,
|
|
155
|
+
snapshot, startTime: t - 500, endTime: t,
|
|
156
|
+
retryCount: 0, wasSelfCorrected: false, hadTimeout: false,
|
|
157
|
+
userAccepted: true, userProvidedEdit: false, resultWasUsed: true,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// 记录情景记忆
|
|
161
|
+
if (toolName === 'exec' && params.command) {
|
|
162
|
+
aos.memory.episodic.record('tool_call', params.command, ['exec'], []);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// 持久化审计
|
|
166
|
+
try {
|
|
167
|
+
if (!fs.existsSync(AUDIT_DIR)) fs.mkdirSync(AUDIT_DIR, { recursive: true });
|
|
168
|
+
fs.appendFileSync(path.join(AUDIT_DIR, 'audit.jsonl'),
|
|
169
|
+
JSON.stringify(ret.auditEntry) + '\n');
|
|
170
|
+
} catch {}
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
auditId: ret.auditEntry.id,
|
|
174
|
+
verify: ret.postExec.verifyPassed ? 'PASS' : 'FAIL',
|
|
175
|
+
risk: ret.runtime.adaptiveScore,
|
|
176
|
+
profile: ret.profile.overallScore,
|
|
177
|
+
};
|
|
178
|
+
} catch (err) {
|
|
179
|
+
// Audit 降级:即使 AgentOS 抛错,也记录轻量审计
|
|
180
|
+
try {
|
|
181
|
+
if (!fs.existsSync(AUDIT_DIR)) fs.mkdirSync(AUDIT_DIR, { recursive: true });
|
|
182
|
+
fs.appendFileSync(path.join(AUDIT_DIR, 'audit.jsonl'),
|
|
183
|
+
JSON.stringify({ ts: new Date().toISOString(), tool: toolName, error: err.message }) + '\n');
|
|
184
|
+
} catch {}
|
|
185
|
+
return { auditId: null, verify: 'ERROR', error: err.message };
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
// ── 查看审计 ──
|
|
190
|
+
audit(limit = 10) {
|
|
191
|
+
return aos.guard.audit.query({ limit });
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
// ── 完整状态报告 ──
|
|
195
|
+
status() {
|
|
196
|
+
return aos.statusReport();
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
// ── 注入 Memory 上下文(session 启动时调用)─
|
|
200
|
+
injectContext() {
|
|
201
|
+
return aos.injectContext();
|
|
202
|
+
},
|
|
203
|
+
|
|
204
|
+
// ── 记录反馈 ──
|
|
205
|
+
feedback(signal) {
|
|
206
|
+
aos.recordFeedback(signal, `s${global.__sentinel_session_id}`);
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
// ── 结束 Session ──
|
|
210
|
+
endSession() {
|
|
211
|
+
const sid = `s${global.__sentinel_session_id}`;
|
|
212
|
+
aos.endSession(sid);
|
|
213
|
+
global.__sentinel_session_id++;
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
// ── 获取完整状态快照 ──
|
|
217
|
+
fullStatus() {
|
|
218
|
+
return {
|
|
219
|
+
sessionId: `s${global.__sentinel_session_id}`,
|
|
220
|
+
opCount: opCounter,
|
|
221
|
+
audit: aos.guard.audit.stats(),
|
|
222
|
+
profile: aos.getProfile(),
|
|
223
|
+
satisfaction: aos.evaluator.feedback.getSatisfactionScore(),
|
|
224
|
+
workingMemory: {
|
|
225
|
+
messages: aos.memory.working.recentMessages.length,
|
|
226
|
+
budget: aos.memory.working.budget,
|
|
227
|
+
},
|
|
228
|
+
episodicEvents: aos.memory.episodic.count,
|
|
229
|
+
semanticRules: aos.memory.semantic.getAllRules().length,
|
|
230
|
+
preferences: aos.memory.semantic.getPreference('language'),
|
|
231
|
+
};
|
|
232
|
+
},
|
|
233
|
+
};
|