magic-agent 1.0.1 → 1.0.3
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/CLIENT-CONTRACT.md +298 -0
- package/README.md +35 -0
- package/client-ui/assets/OFL-Caveat.txt +93 -0
- package/client-ui/assets/caveat.woff2 +0 -0
- package/client-ui/index.html +246 -0
- package/client-ui/pc/app.css +5110 -0
- package/client-ui/pc/assets/damiao-mascot.png +0 -0
- package/client-ui/pc/assets/icon.png +0 -0
- package/client-ui/pc/index.html +154 -0
- package/client-ui/pc/js/00-base.js +52 -0
- package/client-ui/pc/js/03-chat-message.js +880 -0
- package/client-ui/pc/js/04-task-list.js +430 -0
- package/client-ui/pc/js/05-task-list-render.js +812 -0
- package/client-ui/pc/js/06-ask-answer.js +204 -0
- package/client-ui/pc/js/07-chat-stream-render.js +493 -0
- package/client-ui/pc/js/08-ask-event-map.js +171 -0
- package/client-ui/pc/js/09-stream-apply.js +367 -0
- package/client-ui/pc/js/10-markdown.js +430 -0
- package/client-ui/pc/js/18-askbox.js +262 -0
- package/client-ui/pc/js/19-attachments.js +679 -0
- package/client-ui/pc/js/29-msg-variants.js +462 -0
- package/client-ui/pc/js/90-glue.js +212 -0
- package/client-ui/pc/js/91-workbench-stubs.js +134 -0
- package/client-ui/pc/js/92-composer.js +406 -0
- package/client-ui/pc/js/93-rail.js +362 -0
- package/client-ui/pc/vendor/highlight.min.js +1262 -0
- package/client-ui/pc/vendor/marked.min.js +6 -0
- package/client-ui/pc/vendor/purify.min.js +3 -0
- package/client-ui/shared/conversation.css +256 -0
- package/client-ui/shared/conversation.js +1225 -0
- package/client-ui/shared/transport-http.js +123 -0
- package/client-ui-mobile/assets/OFL-Caveat.txt +93 -0
- package/client-ui-mobile/assets/caveat.woff2 +0 -0
- package/client-ui-mobile/index.html +173 -0
- package/internal/agent/custom_models.go +151 -5
- package/internal/agent/custom_models_test.go +130 -7
- package/internal/agent/env.go +10 -2
- package/internal/agent/env_test.go +37 -0
- package/internal/agent/repair_models_test.go +194 -0
- package/internal/cli/ask.go +22 -18
- package/internal/cli/login.go +61 -4
- package/internal/cli/login_test.go +99 -0
- package/internal/cli/repair.go +60 -0
- package/internal/cli/repair_test.go +51 -0
- package/internal/cli/root.go +21 -0
- package/internal/cli/session.go +8 -1
- package/npm/dist/darwin-arm64/magic-agent +0 -0
- package/npm/dist/darwin-x64/magic-agent +0 -0
- package/npm/dist/linux-arm64/magic-agent +0 -0
- package/npm/dist/linux-x64/magic-agent +0 -0
- package/npm/dist/win32-x64/magic-agent.exe +0 -0
- package/package.json +4 -1
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
# 客户端契约(magic-agent ↔ magic-client ↔ 业务项目)
|
|
2
|
+
|
|
3
|
+
这一页是**唯一**该被引用的契约说明。它回答两个问题:core 开放了哪些面、插件承诺了哪些面。
|
|
4
|
+
实现位置写在每一节里;改契约必须同时改这里。
|
|
5
|
+
|
|
6
|
+
版本规则:**只增字段不升版本**;一旦字段改名、语义变化或被删除,必须升 `contractVersion`。
|
|
7
|
+
客户端(桌面 / 移动)与插件启动时都比对该字段,不匹配就**明确报错**,不带着不匹配的能力跑起来 ——
|
|
8
|
+
这类漂移在界面上表现为空白,是最难定位的一类问题。
|
|
9
|
+
|
|
10
|
+
## 一、core 开放的面(`magic-agent`)
|
|
11
|
+
|
|
12
|
+
| 面 | 命令 / 通道 | 状态 | 实现 |
|
|
13
|
+
| --- | --- | --- | --- |
|
|
14
|
+
| 引擎调用 | `-e <engine> -p "<prompt>"`(含超时、重试、退出码) | 稳定 | `internal/cli/ask.go` |
|
|
15
|
+
| 探测与能力 | `--engines [--no-models]`:`ok` / `bin` / `install` / `version` / `models` / `capabilities` … | 稳定 | `internal/cli/root.go` |
|
|
16
|
+
| 契约 envelope | `--contract`:`{contractVersion, features, engines[]}`,`engines[]` 与 `--engines` **同构** | v1 | `internal/cli/root.go` + `internal/agent/capability.go` |
|
|
17
|
+
| 事件流 | `--stream --events`:NDJSON,每行带 `v` / `seq`,首行 `ready` | v1 | `internal/cli/events.go` |
|
|
18
|
+
| 控制回传 | `--stream --control`:stdin 收 NDJSON 命令(`ping` / `interrupt` / `stop` / `answer`) | v1 | `internal/cli/control.go` |
|
|
19
|
+
| 会话追加 | `--stream --keep-alive` + `--append <id>`;`--sessions` / `--stop <id>` | 稳定 | `internal/cli/session.go` |
|
|
20
|
+
|
|
21
|
+
### 1.1 事件流形状
|
|
22
|
+
|
|
23
|
+
未开 `--events` 时是历史形状(逐字节不变):
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{"type":"thinking","text":"…"}
|
|
27
|
+
{"type":"text","text":"…"}
|
|
28
|
+
{"type":"tool_use","text":"<args JSON>","name":"Bash","id":"toolu_x"}
|
|
29
|
+
{"type":"tool_result","text":"<output>","id":"toolu_x"}
|
|
30
|
+
{"type":"turn_end","text":"<该轮正文>","session_id":"…"}
|
|
31
|
+
{"type":"ask","text":"<一行摘要>","ask":{…}}
|
|
32
|
+
{"type":"result","engine":"…","model":"…","session_id":"…","text":"<全文>","thinking":"…","tools":[…]}
|
|
33
|
+
{"type":"error","engine":"…","reason":"<根因>","error":"<完整错误链>"}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
开 `--events` 后**字段集不变**,每行多 `v` / `seq`(`seq` 从 1 单调 +1),
|
|
37
|
+
并额外产出四类 core 自己的事件:`ready`(首行,带 `engine` / `model`)、
|
|
38
|
+
`pong`、`interrupted`、`stopped`、`answered`、`control_error`。
|
|
39
|
+
|
|
40
|
+
两条不变量(有测试钉住):**每轮一定以 `result` 或 `error` 收尾**;
|
|
41
|
+
`--events` 与 `--stream` 的字段集只差 `v` / `seq`。
|
|
42
|
+
|
|
43
|
+
### 1.2 控制命令
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{"op":"ping"} → {"type":"pong"}
|
|
47
|
+
{"op":"interrupt","reason":"…"} → 打断当前轮;本轮真的结束再发 {"type":"interrupted"}
|
|
48
|
+
{"op":"stop"} → 收工(关常驻会话)→ {"type":"stopped"}
|
|
49
|
+
{"op":"answer","text":"…"} → 作为下一轮 user 消息注入常驻会话 → {"type":"answered"}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`answer` 只在常驻会话生效时可用,且**必须**走这条路:headless 下模型提问后会立刻自行拒绝,
|
|
53
|
+
唯一能把答案喂给模型的通道就是下一轮 user 消息。不可用时回 `control_error`,不静默丢。
|
|
54
|
+
|
|
55
|
+
⚠️ 开了 `--control` 的进程,**stdin 归控制通道**,提示词必须由 `-p` / 位置参数 / `--file` 给。
|
|
56
|
+
|
|
57
|
+
### 1.3 两级能力
|
|
58
|
+
|
|
59
|
+
| 集合 | 位置 | 回答的问题 |
|
|
60
|
+
| --- | --- | --- |
|
|
61
|
+
| `features[]` | `--contract` 顶层 | 这台 core 支不支持某条**通道**(`feature.session.events` / `feature.session.control`) |
|
|
62
|
+
| `engines[].capabilities[]` | 每个引擎 | 这个**引擎**能做什么(`session.stream` / `attachment.native` / `engine.install` …) |
|
|
63
|
+
|
|
64
|
+
静态与运行态严格分开:`capabilities` / `features` 是静态声明,`ok` / `streaming` / `models` /
|
|
65
|
+
`version` 是运行态。客户端按前者定界面形态,按后者定控件可用与降级提示。
|
|
66
|
+
|
|
67
|
+
## 二、插件承诺的面(`magic-client`)
|
|
68
|
+
|
|
69
|
+
| 面 | 路径 | 状态 |
|
|
70
|
+
| --- | --- | --- |
|
|
71
|
+
| 契约与引擎清单 | `GET /desk/contract` · `GET /desk/engines[?models=1]` | 已实现 |
|
|
72
|
+
| 应用配置 | `GET /desk/profile` | 已实现 |
|
|
73
|
+
| 模块清单 | `GET /desk/modules`(从 profile 派生:id / 入口 / 声明的表) | 已实现 |
|
|
74
|
+
| 会话登记表 | `GET /desk/sessions`(core 的 `--sessions`,跨进程持久) | 已实现 |
|
|
75
|
+
| 项目业务接口 | `ANY /api/*` → 原样转发到 profile 的 `backend.url` | 已实现 |
|
|
76
|
+
| 发起一轮 | `POST /desk/ask`(SSE 中继 core 的 NDJSON,前置 `event: open`,收尾 `event: end`) | 已实现 |
|
|
77
|
+
| 控制与回审批 | `POST /desk/ask/{id}/control`(与 core 的 `--control` 同协议,插件不解释 op) | 已实现 |
|
|
78
|
+
| 运行中列表 | `GET /desk/asks`(**本进程**正在跑的轮次;与 sessions 的区别见下) | 已实现 |
|
|
79
|
+
| 静态资源 | `GET /`(`--ui-dir` + profile 的 `ui.entry`) | 已实现 |
|
|
80
|
+
| 鉴权 | `X-Magic-Token` 头或 `?token=`;默认只绑 `127.0.0.1`;`--lan` 时绑 `0.0.0.0` 且令牌强制 ≥24 字符(见 2.4) | 已实现 |
|
|
81
|
+
|
|
82
|
+
### 2.1 扩展接口(业务项目对着写)
|
|
83
|
+
|
|
84
|
+
| 接口 | 状态 | 由什么承担 |
|
|
85
|
+
| --- | --- | --- |
|
|
86
|
+
| 模块注册 | 已实现 | profile 的 `modules[]` + `GET /desk/modules`;前端按需加载 `modules[].entry`,模块通过 `window.magicModules[<id>] = { id, title, render(host) }` 注册实现 |
|
|
87
|
+
| 数据存储 | 已实现(转发) | `ANY /api/*` → 项目自己的后端。**插件不建存储**:真相在项目侧 |
|
|
88
|
+
| 视图与导航 | 已实现(最小) | 基础版 UI 的列表页展示模块,点开可进入对话;完整路由待接 |
|
|
89
|
+
| 设置分段 | 已实现(转发) | 走 `/api/*`;项目自己的设置实现(magic-test 的 `config-store.cjs`)照旧 |
|
|
90
|
+
| 动作命令 | 已实现(转发) | 走 `/api/*`;项目侧注册动作,前端从对话里调 |
|
|
91
|
+
| 产物写入 | 已实现(转发) | 走 `/api/*`(magic-test 的 `/api/media/*` 就是) |
|
|
92
|
+
| HTTP 路由 | 已实现 | 同上:模块的路由都在项目后端的 `/api/*` 下 |
|
|
93
|
+
| 主题覆盖 | 已实现 | profile 的 `ui.themeVars`,插件注入页面根元素 |
|
|
94
|
+
| 事件订阅 | 已实现(只读) | 模块直接订阅 `POST /desk/ask` 的 SSE。**不允许改写对话流** |
|
|
95
|
+
|
|
96
|
+
两条写死的约定:**事件只读**(模块不能改写对话流,否则基础版行为会随模块漂移);
|
|
97
|
+
**业务不进基础版数据**(模块的数据表由模块自己声明,插件只转发请求,不做领域假设)。
|
|
98
|
+
|
|
99
|
+
### 2.2 模块运行时契约
|
|
100
|
+
|
|
101
|
+
模块是普通脚本(不是 ESM),由基础版 UI 动态加载后调用它注册的 `render(host)`。
|
|
102
|
+
它能拿到的全部东西就是 `window.magic` 与一个空的宿主节点:
|
|
103
|
+
|
|
104
|
+
| 项 | 说明 |
|
|
105
|
+
| --- | --- |
|
|
106
|
+
| `window.magic.api(path, opts)` | 已带令牌的 `fetch` 包装,返回 `Response`。模块**不自己拼令牌** |
|
|
107
|
+
| `window.magic.on(type, fn)` | 订阅会话事件(**只读**;`type` 传 `'*'` 收全部)。模块内部异常被隔离,不会打断对话流 |
|
|
108
|
+
| `window.magic.profile` | 本应用的 profile |
|
|
109
|
+
| `window.magic.version` | 运行时契约版本(当前 `1`) |
|
|
110
|
+
| `window.magicModules[id]` | 模块注册自己:`{ id, title, render(host) }` |
|
|
111
|
+
|
|
112
|
+
三条纪律:模块**只调 `/api/*` 与 `/desk/*`**(不许另找数据源);只往宿主节点里塞 DOM;
|
|
113
|
+
要注入样式就带自己的前缀作用域(如 `rq-`),不许改基础版 UI 的节点与令牌。
|
|
114
|
+
|
|
115
|
+
还有一条契约要求:**`render(host)` 要在首屏数据到位后再 resolve**。界面上看不出来差别
|
|
116
|
+
(DOM 稍后自己更新),但不满足它时测试台只会看到「读取中…」,等于这条自动化检查失效 ——
|
|
117
|
+
`media.js` 第一版就栽在这里(`load()` 忘了 return promise)。
|
|
118
|
+
|
|
119
|
+
模块在进界面之前先过 `tools/module-harness.mjs`:它用最小 DOM 桩加真实形状的假数据,
|
|
120
|
+
验「注册成功、渲染不抛异常、渲染结果含预期文案、只调允许的接口」。
|
|
121
|
+
第一个实战模块(需求看板)就是靠它抓到问题的 —— 界面上「渲染时抛异常」只表现为一片空白。
|
|
122
|
+
|
|
123
|
+
### 2.3 `/api/*` 转发规则
|
|
124
|
+
|
|
125
|
+
| 规则 | 说明 |
|
|
126
|
+
| --- | --- |
|
|
127
|
+
| 路径 / 方法 / 查询串 / 请求体 | 原样转发 |
|
|
128
|
+
| 响应 | 原样回来;`FlushInterval=-1`,SSE 逐条到达不被缓冲 |
|
|
129
|
+
| 凭据 | `backend.token` 由**服务端**注入(`Authorization: Bearer`,可用 `tokenHeader` 改),不进浏览器 |
|
|
130
|
+
| 插件令牌 | `X-Magic-Token` **不带去后端** —— 那是两套凭据,混传会让后端误以为要校验它 |
|
|
131
|
+
| 未配置后端 | `501` + 一条点名 `backend.url` 的说明,不静默 404 |
|
|
132
|
+
| 地址非法 | **启动即失败**(比运行时 502 好查) |
|
|
133
|
+
|
|
134
|
+
### 2.5 局域网接入(`--lan`)
|
|
135
|
+
|
|
136
|
+
默认只绑 `127.0.0.1`:本地端口对同机所有进程可见,不出鉴权不敢往外露。
|
|
137
|
+
手机 / 平板要连就得绑局域网,而这一开,**令牌就是唯一的门锁** —— 所以两者是配套的:
|
|
138
|
+
|
|
139
|
+
| 行为 | 说明 |
|
|
140
|
+
| --- | --- |
|
|
141
|
+
| `--lan` | 绑 `0.0.0.0`,启动时把本机**所有**可用局域网地址连令牌一起打印(一台机器常有多个网卡) |
|
|
142
|
+
| 令牌下限 | 24 字符;弱令牌**拒绝启动**(自动生成的默认令牌是 32 位十六进制,够用) |
|
|
143
|
+
| 无令牌访问 | `401` —— 不因为是内网就放行 |
|
|
144
|
+
| 不带 `--lan` | 局域网地址**连不上**(默认就是安全的) |
|
|
145
|
+
|
|
146
|
+
扫码配对在 v1 就是「扫这段 URL」(URL 自带令牌)。带 TTL 的配对码交换属于 L2(跨网)的活,
|
|
147
|
+
需要服务端与令牌存储,**未做**。
|
|
148
|
+
|
|
149
|
+
### 2.4 `POST /desk/ask` 的请求体
|
|
150
|
+
|
|
151
|
+
| 字段 | 说明 |
|
|
152
|
+
| --- | --- |
|
|
153
|
+
| `engine` | 必填;profile 的 `engines` 白名单之外的会被 403 |
|
|
154
|
+
| `prompt` | 必填 |
|
|
155
|
+
| `model` / `workspace` | 可选,透传给 core 的 `-m` / `-w` |
|
|
156
|
+
| `permission` | 可选,四档授权模型(`manual` \| `accept-edits` \| `auto` \| `full`),透传给 core 的 `--permission`。**空 = 不传**,由 core 用它自己的默认档(`agent.DefaultPermissionTier`)—— 刻意没有默认预设,见下 |
|
|
157
|
+
| `session` | 可选,续接一个已有会话(传 `/desk/sessions` 里的 id)→ core 的 `--session` |
|
|
158
|
+
| `idle` | 可选,常驻会话空闲收工时长;默认 `0` = 本轮结束就收工 |
|
|
159
|
+
|
|
160
|
+
关于 `permission` 的两条语义,客户端必须照做:
|
|
161
|
+
|
|
162
|
+
1. **没选就原样不传,不要替 core 补默认值。** core 只在**显式传过** `--permission` 时
|
|
163
|
+
才校验该引擎支不支持(`internal/cli/ask.go::resolvePermissionTier`),替用户预设
|
|
164
|
+
会把「显式指定」与「沿用默认」混成一种,还会让不支持的引擎凭空报错。
|
|
165
|
+
2. **档位定义以 `internal/agent/permission.go` 为唯一真相**,前端不要另排一套顺序或文案。
|
|
166
|
+
当前仅 `claude` / `codebuddy` / `codebuddy-ai` 接线,可从 `/desk/engines` 的
|
|
167
|
+
`capabilities` 里读 `permission`;读不到时前端应把选择器**禁用**而不是传过去。
|
|
168
|
+
`full` 等同 `--dangerously-skip-permissions`,两端界面都应把它显式标成危险档。
|
|
169
|
+
|
|
170
|
+
`asks` 是**本进程内存里**的运行中轮次,`sessions` 是 core 的持久登记表 —— 两者不是一回事,
|
|
171
|
+
界面上的「运行中 N」用前者,「最近会话」用后者。
|
|
172
|
+
|
|
173
|
+
### 2.2 扩展接口(业务项目对着写)
|
|
174
|
+
|
|
175
|
+
| 接口 | 状态 | 说明 |
|
|
176
|
+
| --- | --- | --- |
|
|
177
|
+
| 模块注册 | 部分 | profile 的 `modules[]` 已声明;前端按视图激活时机动态加载待接 |
|
|
178
|
+
| 视图与导航 | 待接 | 路由与左栏导航项由模块注册 |
|
|
179
|
+
| 数据存储 | 待接 | 模块声明自己的表(`dataTables`),插件提供迁移与读写 |
|
|
180
|
+
| 设置分段 | 待接 | 复用段式存储(对应 magic-test 的 `config-store.cjs`) |
|
|
181
|
+
| 动作命令 | 待接 | 把业务动作注册成命令,可在对话里触发 |
|
|
182
|
+
| 产物写入 | 待接 | 往统一产物索引写图片与文件 |
|
|
183
|
+
| 事件订阅 | 待接 | 只读订阅会话事件;**不允许改写对话流** |
|
|
184
|
+
| HTTP 路由 | 待接 | 模块注册 `/api/*` 下的路由 |
|
|
185
|
+
| 主题覆盖 | 待接 | 覆盖主题令牌与图标 |
|
|
186
|
+
|
|
187
|
+
两条写死的约定:**事件只读**(模块不能改写对话流,否则基础版行为会随模块漂移);
|
|
188
|
+
**业务不进基础版数据**(模块的数据表由模块自己声明,插件不做领域假设)。
|
|
189
|
+
|
|
190
|
+
## 三、公共对话 UI 组件(对接方直接用它)
|
|
191
|
+
|
|
192
|
+
插件只提供**基础对话 UI**:消息流 + 输入框 + 引擎/模型/授权三项选择。会话列表、
|
|
193
|
+
工作区、业务视图等**不在这里** —— 那些由对接方按自己的界面实现,再把选中的会话交给组件。
|
|
194
|
+
|
|
195
|
+
**magic-agent 自己不跑任何服务。** 组件也不连后端:数据从哪来由宿主注入一个
|
|
196
|
+
`transport` 决定(掌天瓶走 IPC → CLI,别的对接方可能走 HTTP)。所以这里的对接方式是
|
|
197
|
+
「宿主实现 transport + 把组件挂进自己的界面」,不存在「先起一个服务再连它」。
|
|
198
|
+
|
|
199
|
+
### 3.1 两份宿主,一份实现
|
|
200
|
+
|
|
201
|
+
| 文件 | 角色 |
|
|
202
|
+
| --- | --- |
|
|
203
|
+
| `client-ui/shared/conversation.js` | **组件本体**(渲染 + 流式 + 控制 + 三项选择器)。PC 与移动端共用,是唯一来源 |
|
|
204
|
+
| `client-ui/shared/conversation.css` | 组件样式。结构尺寸共用;颜色走 3.3 的变量契约,由宿主供值 |
|
|
205
|
+
| `client-ui/shared/transport-http.js` | 传输层的**可选参考实现**(HTTP 版,打 `/desk/*`)。组件不依赖它 |
|
|
206
|
+
| `client-ui/index.html` | PC 宿主:oklch 令牌 + 一条顶栏 + 挂组件 |
|
|
207
|
+
| `client-ui-mobile/index.html` | 移动端宿主:AA 安卓端那套十六进制令牌 + 移动形态顶栏 + 挂组件 |
|
|
208
|
+
|
|
209
|
+
移动端打包时(magic-test 的 `tools/build-mobile-www.cjs`)会把 `client-ui/shared/`
|
|
210
|
+
一并复制进 `www/shared/` —— 页面按同级 `shared/` 引用它,缺了这个复制对话区会是空白。
|
|
211
|
+
|
|
212
|
+
### 3.2 组件 API
|
|
213
|
+
|
|
214
|
+
```js
|
|
215
|
+
const conv = MagicConversation.create({
|
|
216
|
+
el, // 必填:把对话区 + 输入区挂进去的容器
|
|
217
|
+
transport, // 必填:见下(组件不自己连后端)
|
|
218
|
+
session, // 可选:传了就从这段会话开始(会走 transport.readSession)
|
|
219
|
+
engine, model, permission, // 可选初始值(空 = 不传,core 用它自己的默认)
|
|
220
|
+
engines, // 可选:给了就用这份清单,不给则调 transport.listEngines()
|
|
221
|
+
titleEl, // 可选:宿主显示会话标题的元素
|
|
222
|
+
onEvent, // 可选:每个 core 事件透传一份(只读,不许改写对话流)
|
|
223
|
+
onBusy, // 可选:一轮开始/结束
|
|
224
|
+
});
|
|
225
|
+
conv.send('…');
|
|
226
|
+
conv.interrupt(); conv.stop(); conv.answer('…');
|
|
227
|
+
conv.setSession(sid, s); conv.newSession();
|
|
228
|
+
conv.setEngine(n); conv.setModel(n); conv.setPermission(v); conv.setEngines(list);
|
|
229
|
+
conv.refreshEngines(); conv.loadHistory(sid, after?); conv.destroy();
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### 3.2.1 transport 契约(宿主实现,四个方法)
|
|
233
|
+
|
|
234
|
+
```js
|
|
235
|
+
{
|
|
236
|
+
listEngines() // → Promise<[{engine, ok, models, capabilities}]>
|
|
237
|
+
ask(payload, {onOpen, onEvent, onEnd})// payload: {engine, model?, permission?, session?, prompt}
|
|
238
|
+
// onOpen(runID) 给控制通道的落点
|
|
239
|
+
// onEnd(exitCode) **必须**被调一次,否则界面会一直卡在 busy
|
|
240
|
+
control({id, op, text?}) // op: interrupt | stop | answer → Promise
|
|
241
|
+
readSession(id, {after?}) // → Promise<{events, lastSeq?, snapshotRequired?}>
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
掌天瓶那一侧的 transport 走 IPC → CLI;`transport-http.js` 是走 `/desk/*` 的现成实现。
|
|
246
|
+
|
|
247
|
+
### 3.3 主题:颜色变量契约
|
|
248
|
+
|
|
249
|
+
宿主必须给出下面这组变量的值(组件样式只用不定义)。两套现成的值可抄:
|
|
250
|
+
PC 用 `index.html` 里的 oklch 组,移动端用 `client-ui-mobile/index.html` 里的
|
|
251
|
+
AA 十六进制组 —— 换掉这组值就换掉整套调性,组件代码一行不用动。
|
|
252
|
+
|
|
253
|
+
```
|
|
254
|
+
基础 --canvas --ink --ink-soft --muted --faint --border --subtle --raised
|
|
255
|
+
--primary-action --on-primary-action --app-shadow
|
|
256
|
+
对话 --bubble --bubble-text --code --status-neutral --status-neutral-text --activity
|
|
257
|
+
md --md-body --md-muted --md-border --md-code-bg --link --prompt --shimmer --panel --panel-border
|
|
258
|
+
语义 --accent --warning --success --error-surface --error-border --error-text --error-icon
|
|
259
|
+
--running --transitioning --active
|
|
260
|
+
几何 --r-card --r --r-full --font --mono
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Profile 的 `ui.themeVars` 是同一套变量的运行时覆盖。
|
|
264
|
+
|
|
265
|
+
### 3.4 会话数据:走 CLI,不走服务
|
|
266
|
+
|
|
267
|
+
magic-agent 把会话的查询与修改都做成 CLI 命令,调用方 exec 即可(magic-test 的
|
|
268
|
+
`desktop/agent-cli.cjs` 已经这么调):
|
|
269
|
+
|
|
270
|
+
| 操作 | 命令 |
|
|
271
|
+
| --- | --- |
|
|
272
|
+
| 列出会话 | `magic-agent --sessions` |
|
|
273
|
+
| **读会话历史** | `magic-agent --session-log <session_id\|run_id>` → `{session, events}` |
|
|
274
|
+
| 增量续读 | 追加 `--after <seq>` → 另带 `count / after / lastSeq / snapshotRequired` |
|
|
275
|
+
| 停止会话 | `magic-agent --stop <session_id\|run_id>` |
|
|
276
|
+
| 追加消息 | `magic-agent --append <session_id\|run_id> -p "…"` |
|
|
277
|
+
| 跑一轮(流式 + 控制) | `magic-agent --stream --events --control -e <engine> -p "…"`,控制命令从 stdin 进 |
|
|
278
|
+
|
|
279
|
+
`--session-log` 的输出形状与插件同名的 HTTP 接口**逐字段对齐**,两条路可互换。
|
|
280
|
+
边界语义:`after == lastSeq` 是**追平**(正常空增量,`snapshotRequired=false`);
|
|
281
|
+
`after > lastSeq` 才要求重拉全量。
|
|
282
|
+
|
|
283
|
+
### 3.5 两条不变量
|
|
284
|
+
|
|
285
|
+
- **事件只读**:组件不接受对接方改写对话流,否则基础版行为会随对接方漂移。
|
|
286
|
+
- **授权档位以 `internal/agent/permission.go` 为唯一真相**;`full` 等同
|
|
287
|
+
`--dangerously-skip-permissions`,两端界面都必须把它显式标成危险档。
|
|
288
|
+
|
|
289
|
+
## 四、三层的责任边界
|
|
290
|
+
|
|
291
|
+
| 层 | 负责 | 明确不做 |
|
|
292
|
+
| --- | --- | --- |
|
|
293
|
+
| core | CLI 集成:调用、探测与能力、事件流、控制回传、会话追加、契约 | 不做界面、不做 HTTP 服务、不打包前端资源 |
|
|
294
|
+
| 插件 | 契约校验、事件中继、基础版 UI、扩展接口、本地服务与壳 | 不自己调引擎、不解析引擎输出、不写业务视图 |
|
|
295
|
+
| 业务项目 | 一份 profile + 业务模块 | 不复制通用件、不改基础版 UI 源码 |
|
|
296
|
+
|
|
297
|
+
可验证的三条:装插件前后主二进制 hash / 体积 / `--engines` 输出一致;插件不 `import` core 的内部包;
|
|
298
|
+
插件缺失时 core 一切照旧。
|
package/README.md
CHANGED
|
@@ -376,6 +376,41 @@ EOF
|
|
|
376
376
|
| Linux x64 / arm64 | `npm/dist/linux-x64` / `linux-arm64` |
|
|
377
377
|
| Windows x64 | `npm/dist/win32-x64` |
|
|
378
378
|
|
|
379
|
+
## 集成 H5 对话组件(其他工程)
|
|
380
|
+
|
|
381
|
+
npm 包自带可复用的前端组件,`npm install magic-agent` 后在 `node_modules/magic-agent/` 下:
|
|
382
|
+
|
|
383
|
+
| 路径 | 内容 |
|
|
384
|
+
|------|------|
|
|
385
|
+
| `client-ui-mobile/index.html` | 移动端 H5 宿主页(顶栏 + AA 安卓端配色,含暗/亮双主题) |
|
|
386
|
+
| `client-ui/index.html` | PC 宿主页(oklch 配色);`client-ui/pc/` 是带工作台的完整版 |
|
|
387
|
+
| `client-ui/shared/` | 公共对话组件:`MagicConversation.create()` + HTTP 传输参考件 |
|
|
388
|
+
| `CLIENT-CONTRACT.md` | 契约说明(`/desk/*` 接口、事件流、控制命令、模块机制) |
|
|
389
|
+
|
|
390
|
+
核心设计:**组件不连后端**,宿主注入 `transport`;现成的 `transport-http.js` 打
|
|
391
|
+
magic-client 的 `/desk/*` 接口。三种集成姿势:
|
|
392
|
+
|
|
393
|
+
**① 直接当静态页托管**(最快):先把包里的两块拼成一个可服务目录(`index.html`
|
|
394
|
+
按**同级** `shared/` 相对路径引用,这个关系不能拆散)——
|
|
395
|
+
|
|
396
|
+
```bash
|
|
397
|
+
cp -r node_modules/magic-agent/client-ui-mobile magic-h5
|
|
398
|
+
cp -r node_modules/magic-agent/client-ui/shared magic-h5/shared
|
|
399
|
+
magic-client serve --ui-dir magic-h5
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
手机访问启动时打印的 `http://<局域网IP>/?token=...`。嵌进自己的服务同理:按上面的
|
|
403
|
+
布局静态托管,令牌走 `?token=`。
|
|
404
|
+
|
|
405
|
+
**② 拷进自己的构建**(App/工程内嵌):把 `client-ui-mobile/` 内容与 `client-ui/shared/`
|
|
406
|
+
复制进 `www/`(Vite/Capacitor 同理,`require.resolve('magic-agent/client-ui-mobile/index.html')`
|
|
407
|
+
定位源路径),再注入 `window.MAGIC_BASE` / `window.MAGIC_TOKEN` 指向 magic-client 地址。
|
|
408
|
+
|
|
409
|
+
**③ 自定义 transport**(不走 magic-client):实现四个方法即可挂组件——
|
|
410
|
+
`listEngines()` / `ask(payload, {onEvent, onEnd})` / `control(payload)` / `readSession(sid, opts)`,
|
|
411
|
+
数据从 IPC→CLI 或自有后端来都行(参考 `client-ui/shared/transport-http.js` 与
|
|
412
|
+
`CLIENT-CONTRACT.md` 的事件流形状)。
|
|
413
|
+
|
|
379
414
|
## 更多文档
|
|
380
415
|
|
|
381
416
|
| 文档 | 内容 |
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
Copyright 2014 The Caveat Project Authors (https://github.com/googlefonts/caveat)
|
|
2
|
+
|
|
3
|
+
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
|
4
|
+
This license is copied below, and is also available with a FAQ at:
|
|
5
|
+
http://scripts.sil.org/OFL
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
-----------------------------------------------------------
|
|
9
|
+
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
|
10
|
+
-----------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
PREAMBLE
|
|
13
|
+
The goals of the Open Font License (OFL) are to stimulate worldwide
|
|
14
|
+
development of collaborative font projects, to support the font creation
|
|
15
|
+
efforts of academic and linguistic communities, and to provide a free and
|
|
16
|
+
open framework in which fonts may be shared and improved in partnership
|
|
17
|
+
with others.
|
|
18
|
+
|
|
19
|
+
The OFL allows the licensed fonts to be used, studied, modified and
|
|
20
|
+
redistributed freely as long as they are not sold by themselves. The
|
|
21
|
+
fonts, including any derivative works, can be bundled, embedded,
|
|
22
|
+
redistributed and/or sold with any software provided that any reserved
|
|
23
|
+
names are not used by derivative works. The fonts and derivatives,
|
|
24
|
+
however, cannot be released under any other type of license. The
|
|
25
|
+
requirement for fonts to remain under this license does not apply
|
|
26
|
+
to any document created using the fonts or their derivatives.
|
|
27
|
+
|
|
28
|
+
DEFINITIONS
|
|
29
|
+
"Font Software" refers to the set of files released by the Copyright
|
|
30
|
+
Holder(s) under this license and clearly marked as such. This may
|
|
31
|
+
include source files, build scripts and documentation.
|
|
32
|
+
|
|
33
|
+
"Reserved Font Name" refers to any names specified as such after the
|
|
34
|
+
copyright statement(s).
|
|
35
|
+
|
|
36
|
+
"Original Version" refers to the collection of Font Software components as
|
|
37
|
+
distributed by the Copyright Holder(s).
|
|
38
|
+
|
|
39
|
+
"Modified Version" refers to any derivative made by adding to, deleting,
|
|
40
|
+
or substituting -- in part or in whole -- any of the components of the
|
|
41
|
+
Original Version, by changing formats or by porting the Font Software to a
|
|
42
|
+
new environment.
|
|
43
|
+
|
|
44
|
+
"Author" refers to any designer, engineer, programmer, technical
|
|
45
|
+
writer or other person who contributed to the Font Software.
|
|
46
|
+
|
|
47
|
+
PERMISSION & CONDITIONS
|
|
48
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
49
|
+
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
|
50
|
+
redistribute, and sell modified and unmodified copies of the Font
|
|
51
|
+
Software, subject to the following conditions:
|
|
52
|
+
|
|
53
|
+
1) Neither the Font Software nor any of its individual components,
|
|
54
|
+
in Original or Modified Versions, may be sold by itself.
|
|
55
|
+
|
|
56
|
+
2) Original or Modified Versions of the Font Software may be bundled,
|
|
57
|
+
redistributed and/or sold with any software, provided that each copy
|
|
58
|
+
contains the above copyright notice and this license. These can be
|
|
59
|
+
included either as stand-alone text files, human-readable headers or
|
|
60
|
+
in the appropriate machine-readable metadata fields within text or
|
|
61
|
+
binary files as long as those fields can be easily viewed by the user.
|
|
62
|
+
|
|
63
|
+
3) No Modified Version of the Font Software may use the Reserved Font
|
|
64
|
+
Name(s) unless explicit written permission is granted by the corresponding
|
|
65
|
+
Copyright Holder. This restriction only applies to the primary font name as
|
|
66
|
+
presented to the users.
|
|
67
|
+
|
|
68
|
+
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
|
69
|
+
Software shall not be used to promote, endorse or advertise any
|
|
70
|
+
Modified Version, except to acknowledge the contribution(s) of the
|
|
71
|
+
Copyright Holder(s) and the Author(s) or with their explicit written
|
|
72
|
+
permission.
|
|
73
|
+
|
|
74
|
+
5) The Font Software, modified or unmodified, in part or in whole,
|
|
75
|
+
must be distributed entirely under this license, and must not be
|
|
76
|
+
distributed under any other license. The requirement for fonts to
|
|
77
|
+
remain under this license does not apply to any document created
|
|
78
|
+
using the Font Software.
|
|
79
|
+
|
|
80
|
+
TERMINATION
|
|
81
|
+
This license becomes null and void if any of the above conditions are
|
|
82
|
+
not met.
|
|
83
|
+
|
|
84
|
+
DISCLAIMER
|
|
85
|
+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
86
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
|
87
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
|
88
|
+
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
|
89
|
+
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
90
|
+
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
|
91
|
+
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
92
|
+
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
|
93
|
+
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
Binary file
|