work-ally 0.2.0-alpha.1
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/AGENTS.md +110 -0
- package/DASHBOARD.md +160 -0
- package/PRODUCT.md +113 -0
- package/README.md +403 -0
- package/ally.sh +171 -0
- package/bridge/src/approval-rules.ts +360 -0
- package/bridge/src/channel-delivery.ts +207 -0
- package/bridge/src/channel-types.ts +22 -0
- package/bridge/src/channels/fake/adapter.ts +31 -0
- package/bridge/src/channels/feishu/adapter.ts +411 -0
- package/bridge/src/channels/feishu/approvals.ts +6 -0
- package/bridge/src/channels/feishu/formatter.ts +276 -0
- package/bridge/src/channels/feishu/normalize.ts +368 -0
- package/bridge/src/codex-config.ts +52 -0
- package/bridge/src/config.ts +240 -0
- package/bridge/src/fake-runtime-client.ts +505 -0
- package/bridge/src/handoff-service.ts +494 -0
- package/bridge/src/logger.ts +194 -0
- package/bridge/src/memory-digest.ts +186 -0
- package/bridge/src/receiver-approval-autonomy.ts +158 -0
- package/bridge/src/receiver-control-core.ts +140 -0
- package/bridge/src/receiver-control-work-session.ts +218 -0
- package/bridge/src/receiver-control.ts +83 -0
- package/bridge/src/receiver-delivery.ts +136 -0
- package/bridge/src/receiver-helpers.ts +96 -0
- package/bridge/src/receiver-human-gate.ts +333 -0
- package/bridge/src/receiver-inbound-preflight.ts +162 -0
- package/bridge/src/receiver-recovery.ts +236 -0
- package/bridge/src/receiver-runtime-callbacks.ts +367 -0
- package/bridge/src/receiver-runtime-policy.ts +132 -0
- package/bridge/src/receiver-runtime-state.ts +124 -0
- package/bridge/src/receiver-support-actions.ts +189 -0
- package/bridge/src/receiver-thread-start.ts +57 -0
- package/bridge/src/receiver-turn-coordination.ts +94 -0
- package/bridge/src/receiver-turn-execution.ts +257 -0
- package/bridge/src/receiver-turn-failure.ts +143 -0
- package/bridge/src/receiver-turn-result.ts +185 -0
- package/bridge/src/receiver-turn-steer.ts +70 -0
- package/bridge/src/receiver-work-session.ts +76 -0
- package/bridge/src/receiver.ts +329 -0
- package/bridge/src/router.ts +62 -0
- package/bridge/src/runtime-client-agent-messages.ts +150 -0
- package/bridge/src/runtime-client-message-dispatch.ts +176 -0
- package/bridge/src/runtime-client-protocol.ts +411 -0
- package/bridge/src/runtime-client-request-ops.ts +56 -0
- package/bridge/src/runtime-client-run-turn.ts +158 -0
- package/bridge/src/runtime-client-thread-ops.ts +270 -0
- package/bridge/src/runtime-client-transport.ts +309 -0
- package/bridge/src/runtime-client-turn-poll.ts +224 -0
- package/bridge/src/runtime-client-turn-read.ts +185 -0
- package/bridge/src/runtime-client-turn-state.ts +105 -0
- package/bridge/src/runtime-client.ts +344 -0
- package/bridge/src/runtime-user-input.ts +403 -0
- package/bridge/src/scheduler.ts +239 -0
- package/bridge/src/server-handoff-command.ts +364 -0
- package/bridge/src/server-main.ts +80 -0
- package/bridge/src/server-routine-command.ts +60 -0
- package/bridge/src/server-routine-execution.ts +222 -0
- package/bridge/src/server-runtime-app-support.ts +107 -0
- package/bridge/src/server-runtime-app.ts +238 -0
- package/bridge/src/server-thread-sync-command.ts +63 -0
- package/bridge/src/server.ts +17 -0
- package/bridge/src/session-store-delivery.ts +220 -0
- package/bridge/src/session-store-human-gate.ts +380 -0
- package/bridge/src/session-store-inbound-acceptance.ts +66 -0
- package/bridge/src/session-store-meta.ts +134 -0
- package/bridge/src/session-store-turn-ledger.ts +272 -0
- package/bridge/src/session-store.ts +380 -0
- package/bridge/src/system-notify.ts +220 -0
- package/bridge/src/thread-sync.ts +200 -0
- package/bridge/src/translator.ts +494 -0
- package/bridge/src/types.ts +289 -0
- package/bridge/src/utils.ts +104 -0
- package/bridge/src/work-session-store.ts +471 -0
- package/docs/.gitkeep +0 -0
- package/docs/architecture/codex-feishu-bridge-proposal.md +2742 -0
- package/docs/completed/FEATURE-feishu-markdown-and-reply-support.md +327 -0
- package/docs/completed/README.md +21 -0
- package/docs/completed/SPEC-approval-autonomy-and-safe-defaults.md +205 -0
- package/docs/completed/SPEC-approval-batch-and-strict-reply-shortcuts.md +153 -0
- package/docs/completed/SPEC-conversation-noise-reduction-and-busy-input-gate.md +538 -0
- package/docs/completed/SPEC-engineering-sop-skillization.md +190 -0
- package/docs/completed/SPEC-faithful-bridge-core-thinning-v2.md +376 -0
- package/docs/completed/SPEC-faithful-bridge-core-thinning.md +1071 -0
- package/docs/completed/SPEC-group-chat-sender-identity.md +301 -0
- package/docs/completed/SPEC-middleware-exception-visibility.md +227 -0
- package/docs/completed/SPEC-nightly-memory-digest-visibility.md +121 -0
- package/docs/completed/SPEC-project-group-chat-human-centered-conversation-mapping.md +326 -0
- package/docs/completed/SPEC-remove-cli-persona-bootstrap.md +201 -0
- package/docs/developer-workflow.md +49 -0
- package/docs/implementation/SPEC-codex-same-machine-session-handoff-implementation.md +239 -0
- package/docs/implementation/test-coverage-map.md +363 -0
- package/docs/implementation/work-ally-implementation-guide.md +790 -0
- package/docs/issues/README.md +10 -0
- package/docs/issues/pending/ANALYSIS-ally-premature-recovery-notice-and-task-state-semantics-2026-03-18.md +295 -0
- package/docs/issues/resolved/ANALYSIS-approval-waiting-visible-but-approval-artifact-missing-2026-03-16.md +466 -0
- package/docs/issues/resolved/ANALYSIS-blocking-state-visible-without-user-actionable-artifact-2026-03-16.md +261 -0
- package/docs/issues/resolved/ANALYSIS-codex-app-server-transport-disconnect-semantics-2026-03-14.md +606 -0
- package/docs/issues/resolved/ANALYSIS-premature-terminalization-on-fresh-thread-poll-and-object-error-leak-2026-03-16.md +348 -0
- package/docs/issues/resolved/ANALYSIS-runtime-turn-delivery-and-recovery-2026-03-14.md +603 -0
- package/docs/issues/resolved/ANALYSIS-self-test-gap-approval-waiting-visible-but-approval-artifact-missing-2026-03-16.md +166 -0
- package/docs/issues/resolved/ANALYSIS-self-test-gap-blocking-state-visible-without-user-actionable-artifact-2026-03-16.md +186 -0
- package/docs/issues/resolved/ANALYSIS-self-test-gap-premature-terminalization-on-fresh-thread-poll-and-object-error-leak-2026-03-16.md +166 -0
- package/docs/issues/resolved/REPORT-ally-runtime-turn-delivery-3b42fb8-2026-03-15.md +373 -0
- package/docs/manual-acceptance.md +127 -0
- package/docs/ops-runbook.md +44 -0
- package/docs/planning/FEATURE-memory-system.md +748 -0
- package/docs/planning/SPEC-active-turn-steer-and-context-compaction-visibility.md +269 -0
- package/docs/planning/SPEC-approval-rules-inheritance-and-local-validation-lane.md +450 -0
- package/docs/planning/SPEC-assistant-persona-bootstrap.md +199 -0
- package/docs/planning/SPEC-assistant-rename.md +610 -0
- package/docs/planning/SPEC-bridge-app-server-protocol-alignment.md +667 -0
- package/docs/planning/SPEC-claude-runtime-host-for-work-ally.md +434 -0
- package/docs/planning/SPEC-cli-feishu-codex-session-unification.md +236 -0
- package/docs/planning/SPEC-codex-same-machine-session-handoff.md +873 -0
- package/docs/planning/SPEC-feishu-reaction-shortcuts.md +282 -0
- package/docs/planning/SPEC-local-stable-release-boundary.md +166 -0
- package/docs/planning/SPEC-managed-thread-entry-and-surface-mobility.md +862 -0
- package/docs/planning/SPEC-minimal-bridge-semantics-and-user-visible-surface.md +362 -0
- package/docs/planning/SPEC-npm-alpha-distribution-and-install-first-release.md +222 -0
- package/docs/planning/SPEC-remove-websocket-runtime-transport.md +364 -0
- package/docs/planning/SPEC-runtime-abstraction-phase-1.md +424 -0
- package/docs/planning/SPEC-runtime-connection-and-turn-recovery-semantics.md +274 -0
- package/docs/planning/SPEC-session-presence-and-state-visibility.md +397 -0
- package/docs/planning/SPEC-skill-first-capability-packaging.md +338 -0
- package/docs/planning/SPEC-stable-archive-contract.md +456 -0
- package/docs/planning/SPEC-supervised-start-boundary.md +127 -0
- package/docs/planning/SPEC-user-barrier-reduction-and-activation.md +832 -0
- package/docs/planning/ally-next.md +1278 -0
- package/docs/planning/assistant-workbench-spec.md +725 -0
- package/docs/planning/product-workbench.md +283 -0
- package/docs/product-onboarding.md +227 -0
- package/docs/product-spec-standard.md +528 -0
- package/docs/troubleshooting.md +45 -0
- package/docs/user-quickstart.md +46 -0
- package/internal/dispatch.sh +95 -0
- package/internal/lib/common.sh +1450 -0
- package/internal/modules/assistant/manage.sh +1312 -0
- package/internal/modules/bootstrap/setup.sh +144 -0
- package/internal/modules/config/init-env.sh +10 -0
- package/internal/modules/global/manage.sh +154 -0
- package/internal/modules/handoff/manage.sh +54 -0
- package/internal/modules/mcp/manage.sh +83 -0
- package/internal/modules/ops/logs.sh +76 -0
- package/internal/modules/routines/manage.sh +55 -0
- package/internal/modules/runtime/assistant-autosave.sh +26 -0
- package/internal/modules/runtime/restart.sh +6 -0
- package/internal/modules/runtime/start.sh +283 -0
- package/internal/modules/runtime/status.sh +194 -0
- package/internal/modules/runtime/stop.sh +55 -0
- package/internal/modules/runtime/supervisor.sh +216 -0
- package/internal/modules/runtime/update.sh +26 -0
- package/package.json +41 -0
- package/runtime/config/.gitkeep +0 -0
- package/runtime/host/.gitkeep +0 -0
- package/runtime/host/healthcheck-codex-app-server.ts +22 -0
- package/runtime/host/ping-pong-codex-app-server.ts +66 -0
- package/runtime/host/probe-codex-app-server.ts +115 -0
- package/skills/archive-reader/SKILL.md +9 -0
- package/skills/feishu-production-debug/SKILL.md +37 -0
- package/skills/feishu-production-debug/references/feishu-debug-order.md +49 -0
- package/skills/feishu-production-debug/references/platform-permission-baseline.md +23 -0
- package/skills/issue-to-spec-triage/SKILL.md +44 -0
- package/skills/issue-to-spec-triage/references/triage-rules.md +66 -0
- package/skills/memory-digest/SKILL.md +9 -0
- package/skills/post-implementation-closure/SKILL.md +39 -0
- package/skills/post-implementation-closure/references/closure-checklist.md +45 -0
- package/skills/post-implementation-closure/references/doc-drift-map.md +49 -0
- package/skills/product-spec/SKILL.md +244 -0
- package/templates/env.example +5 -0
- package/templates/routines/nightly-memory-digest.yaml +10 -0
- package/templates/workspace/AGENTS.md +26 -0
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
# Stable Archive Contract
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
|
|
5
|
+
- Target project: `work-ally`
|
|
6
|
+
- Audience: implementation engineer / product architect
|
|
7
|
+
- Scope: assistant desk raw archive under `.system/archive/`
|
|
8
|
+
- Status: shipped baseline / contract pending cleanup
|
|
9
|
+
- Goal: freeze the raw materials contract so future digest/compression mechanisms can evolve without rewriting history
|
|
10
|
+
|
|
11
|
+
## Summary
|
|
12
|
+
|
|
13
|
+
这份文档定义 `work-ally` 的稳定原材料协议,也就是 assistant desk 下 `.system/archive/` 的长期合同。
|
|
14
|
+
|
|
15
|
+
当前状态补充:
|
|
16
|
+
|
|
17
|
+
- `.system/archive/YYYY/MM/DD/<channel>--<conversation>.ndjson` 这条主目录结构与事件落盘能力已经进入 shipped baseline
|
|
18
|
+
- 当前仍需继续收口的是:哪些事件字段属于稳定合同、哪些只属于实现细节,以及文档与现有 archive/store 行为的最终核对
|
|
19
|
+
|
|
20
|
+
核心结论:
|
|
21
|
+
|
|
22
|
+
1. `archive` 是 **原材料层**,不是 memory 层,也不是 digest 层。
|
|
23
|
+
2. digest / compression 机制未来可以更换,但 archive 的目录结构与事件骨架应尽早冻结。
|
|
24
|
+
3. archive 必须是:**append-only、可审阅、低解释、弱加工、长期稳定**。
|
|
25
|
+
4. archive 的职责是忠实记录“发生了什么”,而不是替未来机制提前做总结。
|
|
26
|
+
|
|
27
|
+
一句话定义:
|
|
28
|
+
|
|
29
|
+
> archive = assistant 与外界交互过程的稳定原材料账本。
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Why Freeze It Now
|
|
34
|
+
|
|
35
|
+
记忆提炼机制未来很可能变化:
|
|
36
|
+
|
|
37
|
+
- nightly digest 可能改
|
|
38
|
+
- 压缩策略可能改
|
|
39
|
+
- 摘要 prompt 可能改
|
|
40
|
+
- `MISTAKES.md` / `MEMORY.md` 的写法可能改
|
|
41
|
+
|
|
42
|
+
但这些变化不应反过来污染原材料层。
|
|
43
|
+
|
|
44
|
+
如果 archive 契约一直摇摆,会出现三个问题:
|
|
45
|
+
|
|
46
|
+
1. 历史数据不可持续复用
|
|
47
|
+
2. 后续 compression 机制难以兼容旧材料
|
|
48
|
+
3. 用户无法相信这是一份稳定可追溯的工作账本
|
|
49
|
+
|
|
50
|
+
所以当前阶段必须先冻结 archive 合同,再允许上层策略演进。
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Non-goals
|
|
55
|
+
|
|
56
|
+
这份 spec 不定义:
|
|
57
|
+
|
|
58
|
+
- `MEMORY.md` 如何提炼
|
|
59
|
+
- `NOW.md` 如何更新
|
|
60
|
+
- `MISTAKES.md` 如何组织
|
|
61
|
+
- digest prompt 长什么样
|
|
62
|
+
- conversation resume 机制
|
|
63
|
+
|
|
64
|
+
它只定义 raw archive 自身。
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Black-box Definition
|
|
69
|
+
|
|
70
|
+
这里先把“黑匣子”定义拍死。
|
|
71
|
+
|
|
72
|
+
`work-ally` 里的黑匣子,不是摘要,不是压缩结果,也不是长期记忆。
|
|
73
|
+
|
|
74
|
+
它的定义是:
|
|
75
|
+
|
|
76
|
+
> black-box archive = assistant 与外界交互过程的完整、追加式、可追溯事实流水。
|
|
77
|
+
|
|
78
|
+
这个定义里有四个关键词:
|
|
79
|
+
|
|
80
|
+
- **完整**:保留人和 AI 的完整往返正文,不做语义压缩
|
|
81
|
+
- **追加式**:只追加,不回写,不重排
|
|
82
|
+
- **可追溯**:能还原某段时间内某个对话发生过什么
|
|
83
|
+
- **事实流水**:记录发生过的事实,而不是事后的理解与总结
|
|
84
|
+
|
|
85
|
+
因此 archive 不做这些事:
|
|
86
|
+
|
|
87
|
+
- 不把正文提前压缩成摘要
|
|
88
|
+
- 不把长期记忆提前写回原材料
|
|
89
|
+
- 不为了“省空间”删掉真实对话正文
|
|
90
|
+
- 不把未来可能频繁变化的内部调试对象混成主合同
|
|
91
|
+
|
|
92
|
+
一句话:
|
|
93
|
+
|
|
94
|
+
> archive 约束的是结构,不压缩的是内容。
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## What It Stores
|
|
99
|
+
|
|
100
|
+
archive v1 应保存两大类原材料。
|
|
101
|
+
|
|
102
|
+
### 1. 完整消息正文
|
|
103
|
+
|
|
104
|
+
这是黑匣子的主体。
|
|
105
|
+
|
|
106
|
+
应保留:
|
|
107
|
+
|
|
108
|
+
- 用户发来的原始文本
|
|
109
|
+
- assistant 回给用户的原始文本
|
|
110
|
+
- reply-to 相关文本
|
|
111
|
+
- 附件的轻量元信息
|
|
112
|
+
|
|
113
|
+
这里的“完整”指的是:
|
|
114
|
+
|
|
115
|
+
- inbound message 的正文完整保留
|
|
116
|
+
- outbound message 的正文完整保留
|
|
117
|
+
- 不做语义摘要式改写
|
|
118
|
+
|
|
119
|
+
### 2. 必要的过程事件
|
|
120
|
+
|
|
121
|
+
除了消息正文,archive 还应保留必要的过程事实,例如:
|
|
122
|
+
|
|
123
|
+
- approval requested / resolved
|
|
124
|
+
- user input requested / submitted
|
|
125
|
+
- turn failed / interrupted
|
|
126
|
+
- routine started / finished
|
|
127
|
+
- 其他对追溯链路有长期价值的关键系统事件
|
|
128
|
+
|
|
129
|
+
这些事件不是聊天正文,但属于“这次交互实际发生了什么”的一部分。
|
|
130
|
+
|
|
131
|
+
### What it does not store as stable main contract
|
|
132
|
+
|
|
133
|
+
以下内容不应进入 archive 的稳定主合同:
|
|
134
|
+
|
|
135
|
+
- 任意自由形态的 `payload`
|
|
136
|
+
- 渠道 SDK 的整块 `raw` 原包
|
|
137
|
+
- 会随实现重构频繁变化的临时调试结构
|
|
138
|
+
|
|
139
|
+
不是因为这些内容永远没价值,而是因为它们不稳定。
|
|
140
|
+
|
|
141
|
+
如果未来确实需要保留,应以 debug sidecar 或显式附属机制处理,而不是污染稳定 archive 合同。
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Storage Granularity
|
|
146
|
+
|
|
147
|
+
archive 的**物理存储粒度**固定为:
|
|
148
|
+
|
|
149
|
+
> 一个外部 conversation 在某一天内一个文件。
|
|
150
|
+
|
|
151
|
+
这意味着:
|
|
152
|
+
|
|
153
|
+
- 不是“全局一天一个总文件”
|
|
154
|
+
- 不是“一个 thread 一个文件”
|
|
155
|
+
- 而是“一个 `conversation` 在某一天一个 `.ndjson` 文件”
|
|
156
|
+
|
|
157
|
+
原因:
|
|
158
|
+
|
|
159
|
+
- conversation 是比内部 thread 更稳定的外部定位单位
|
|
160
|
+
- 同一个外部 conversation 可能跨多个内部 thread / turn
|
|
161
|
+
- 按 conversation + day 切文件,既方便追溯,也能避免单文件失控膨胀
|
|
162
|
+
|
|
163
|
+
因此 archive 的存储维度固定为:
|
|
164
|
+
|
|
165
|
+
- **主切分维度**:`conversation_id`
|
|
166
|
+
- **时间切分维度**:`YYYY/MM/DD`
|
|
167
|
+
- **内部追踪字段**:`thread_id` / `turn_id` 作为记录内字段保留,但不作为主分片键
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Storage Layout
|
|
172
|
+
|
|
173
|
+
archive 根目录固定为:
|
|
174
|
+
|
|
175
|
+
```text
|
|
176
|
+
<assistant-desk>/.system/archive/
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
日期分层固定为:
|
|
180
|
+
|
|
181
|
+
```text
|
|
182
|
+
.system/archive/YYYY/MM/DD/
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
单个对话文件固定为:
|
|
186
|
+
|
|
187
|
+
```text
|
|
188
|
+
<channel>--<conversation-id>.ndjson
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
因此完整路径模式固定为:
|
|
192
|
+
|
|
193
|
+
```text
|
|
194
|
+
.system/archive/YYYY/MM/DD/<channel>--<conversation-id>.ndjson
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Stability rule
|
|
198
|
+
|
|
199
|
+
以下内容视为 v1 稳定合同:
|
|
200
|
+
|
|
201
|
+
- `YYYY/MM/DD` 日期目录结构
|
|
202
|
+
- 每个 conversation 每天一个 `.ndjson` 文件
|
|
203
|
+
- 文件名由 `<channel>--<conversation-id>` 组成
|
|
204
|
+
- 文件内容为一行一个 JSON object
|
|
205
|
+
|
|
206
|
+
未来如需变更,只能新增版本迁移机制,不能直接悄悄改。
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## File Semantics
|
|
211
|
+
|
|
212
|
+
每个 `.ndjson` 文件表示:
|
|
213
|
+
|
|
214
|
+
> 某一天、某个 channel、某个 conversation 内发生的稳定可追溯事件流。
|
|
215
|
+
|
|
216
|
+
要求:
|
|
217
|
+
|
|
218
|
+
- append-only
|
|
219
|
+
- 按发生顺序追加
|
|
220
|
+
- 不做原地修改
|
|
221
|
+
- 不因上层 digest 结果回写 archive
|
|
222
|
+
|
|
223
|
+
archive 文件是事实流水,不是摘要文档。
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Record Model
|
|
228
|
+
|
|
229
|
+
### 1. Common envelope
|
|
230
|
+
|
|
231
|
+
每条记录都必须包含稳定公共字段:
|
|
232
|
+
|
|
233
|
+
- `schema_version`: 当前固定为 `1`
|
|
234
|
+
- `at`: ISO 8601 时间戳
|
|
235
|
+
- `direction`: `inbound` | `outbound` | `system`
|
|
236
|
+
- `event_type`: 稳定事件类型字符串
|
|
237
|
+
- `channel`: 渠道标识
|
|
238
|
+
- `conversation_id`: 对话标识
|
|
239
|
+
|
|
240
|
+
这六个字段属于 archive 主合同,任何记录都不能缺。
|
|
241
|
+
|
|
242
|
+
### 2. Conversation identity
|
|
243
|
+
|
|
244
|
+
conversation 维度字段必须冗余写在每条记录里,而不是只依赖文件路径。
|
|
245
|
+
|
|
246
|
+
原因:
|
|
247
|
+
|
|
248
|
+
- 单条记录可脱离文件单独处理
|
|
249
|
+
- 后续聚合与重放更稳定
|
|
250
|
+
- 文件移动或抽样时不丢上下文
|
|
251
|
+
|
|
252
|
+
### 3. Event payload rule
|
|
253
|
+
|
|
254
|
+
公共字段之外,允许按 `event_type` 携带有限的事件字段。
|
|
255
|
+
|
|
256
|
+
但不允许:
|
|
257
|
+
|
|
258
|
+
- 任意形状的自由 `payload`
|
|
259
|
+
- 把整块 channel SDK 原始对象作为稳定主字段
|
|
260
|
+
- 把未来会频繁变化的内部调试结构混进主合同
|
|
261
|
+
|
|
262
|
+
也就是说:
|
|
263
|
+
|
|
264
|
+
> archive 可以有事件专属字段,但不能退化成“随便塞一个 payload”。
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Stable Event Types
|
|
269
|
+
|
|
270
|
+
v1 建议固定以下事件类型。
|
|
271
|
+
|
|
272
|
+
### `message_inbound`
|
|
273
|
+
|
|
274
|
+
表示收到一条用户输入。
|
|
275
|
+
|
|
276
|
+
稳定字段:
|
|
277
|
+
|
|
278
|
+
- `message_id`
|
|
279
|
+
- `sender_id`
|
|
280
|
+
- `sender_name`
|
|
281
|
+
- `chat_type`
|
|
282
|
+
- `text`
|
|
283
|
+
- `reply_to_message_id`
|
|
284
|
+
- `root_message_id`
|
|
285
|
+
- `reply_to_text`
|
|
286
|
+
- `attachments`
|
|
287
|
+
|
|
288
|
+
### `message_outbound_runtime`
|
|
289
|
+
|
|
290
|
+
表示 runtime 已产出一条最终或中间结果,并由 bridge 记录。
|
|
291
|
+
|
|
292
|
+
稳定字段:
|
|
293
|
+
|
|
294
|
+
- `turn_id`
|
|
295
|
+
- `thread_id`
|
|
296
|
+
- `status`
|
|
297
|
+
- `reply`
|
|
298
|
+
- `reply_preview`
|
|
299
|
+
- `error`
|
|
300
|
+
|
|
301
|
+
### `message_outbound_channel`
|
|
302
|
+
|
|
303
|
+
表示 bridge 向外部 channel 投递了一条消息。
|
|
304
|
+
|
|
305
|
+
稳定字段:
|
|
306
|
+
|
|
307
|
+
- `envelope_type`
|
|
308
|
+
- `message_id`(如有)
|
|
309
|
+
- `text`
|
|
310
|
+
- `text_preview`
|
|
311
|
+
|
|
312
|
+
对于审批、用户输入请求等特殊外发,允许追加有限稳定字段,但仍属于 `message_outbound_channel` 大类。
|
|
313
|
+
|
|
314
|
+
### `system_event`
|
|
315
|
+
|
|
316
|
+
表示非消息类系统事件。
|
|
317
|
+
|
|
318
|
+
系统事件也不能使用自由 `payload`,必须继续细分稳定 `system_type`,例如:
|
|
319
|
+
|
|
320
|
+
- `runtime_progress`
|
|
321
|
+
- `approval_requested`
|
|
322
|
+
- `approval_resolved`
|
|
323
|
+
- `user_input_requested`
|
|
324
|
+
- `user_input_submitted`
|
|
325
|
+
- `turn_failed`
|
|
326
|
+
- `turn_interrupted`
|
|
327
|
+
- `routine_started`
|
|
328
|
+
- `routine_progress`
|
|
329
|
+
- `routine_finished`
|
|
330
|
+
|
|
331
|
+
`system_event` 的稳定字段:
|
|
332
|
+
|
|
333
|
+
- `system_type`
|
|
334
|
+
- 与该 `system_type` 对应的有限稳定字段
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
## Raw Data Policy
|
|
339
|
+
|
|
340
|
+
### `raw` is not part of the stable contract
|
|
341
|
+
|
|
342
|
+
channel 原始对象、SDK 返回体、事件原文,可能对调试有用。
|
|
343
|
+
|
|
344
|
+
但它们不应成为 archive 稳定主合同的一部分。
|
|
345
|
+
|
|
346
|
+
因此 v1 建议:
|
|
347
|
+
|
|
348
|
+
- 不把 `raw` 作为 archive 主合同字段
|
|
349
|
+
- 如确有调试需要,单独设计 debug 开关或侧带留存机制
|
|
350
|
+
- 任何 `raw` 留存都应被视为非稳定附属能力,不能成为未来 compression 的依赖前提
|
|
351
|
+
|
|
352
|
+
原因:
|
|
353
|
+
|
|
354
|
+
- `raw` 容易膨胀
|
|
355
|
+
- `raw` 的形状受 SDK 和渠道波动影响大
|
|
356
|
+
- 一旦把 `raw` 写进主合同,就很难冻结 archive 协议
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
## Attachments Policy
|
|
361
|
+
|
|
362
|
+
附件字段 `attachments` 允许存在,但只保留稳定、轻量、可长期理解的元信息,例如:
|
|
363
|
+
|
|
364
|
+
- `kind`
|
|
365
|
+
- `name`
|
|
366
|
+
- `token`
|
|
367
|
+
- `path`
|
|
368
|
+
|
|
369
|
+
不在 archive 主合同中承诺:
|
|
370
|
+
|
|
371
|
+
- 附件二进制本体
|
|
372
|
+
- 渠道私有的复杂附件结构
|
|
373
|
+
- 长期不稳定的解析结果
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## Ordering And Mutability
|
|
378
|
+
|
|
379
|
+
### Ordering
|
|
380
|
+
|
|
381
|
+
同一文件中的记录应按追加顺序排列,默认近似代表事件发生顺序。
|
|
382
|
+
|
|
383
|
+
允许出现轻微时间交错,但禁止后写覆盖前写。
|
|
384
|
+
|
|
385
|
+
### Mutability
|
|
386
|
+
|
|
387
|
+
archive 一旦写入,默认不可改。
|
|
388
|
+
|
|
389
|
+
禁止:
|
|
390
|
+
|
|
391
|
+
- digest 回写 archive
|
|
392
|
+
- nightly compact 改写历史记录
|
|
393
|
+
- 为了“看起来更整洁”重排历史
|
|
394
|
+
|
|
395
|
+
如果未来出现修复需求,应采用:
|
|
396
|
+
|
|
397
|
+
- 新增修正记录
|
|
398
|
+
- 或在明确迁移工具下整体迁移版本
|
|
399
|
+
|
|
400
|
+
而不是直接 silent edit。
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
## Read Expectations
|
|
405
|
+
|
|
406
|
+
archive 的典型消费者包括:
|
|
407
|
+
|
|
408
|
+
- nightly digest / future compression
|
|
409
|
+
- 人工排障
|
|
410
|
+
- 历史审计
|
|
411
|
+
- 未来的记忆提炼机制
|
|
412
|
+
|
|
413
|
+
如果目标是“看完整聊天链路”而不是“核对底层事实”,优先应使用 `conversations/` 视图层,而不是直接扫描 raw archive。
|
|
414
|
+
|
|
415
|
+
archive 默认不是:
|
|
416
|
+
|
|
417
|
+
- assistant 启动热路径必读材料
|
|
418
|
+
- 用户日常编辑文件
|
|
419
|
+
- 长期记忆正文
|
|
420
|
+
|
|
421
|
+
原因很直接:
|
|
422
|
+
|
|
423
|
+
- raw archive 必然包含一定过程噪音
|
|
424
|
+
- 它追求的是稳定与完整,不是最优阅读体验
|
|
425
|
+
- 适合阅读的问题,应交给上层 view layer 处理,而不是强迫 raw layer 同时兼顾“好读”和“稳定”
|
|
426
|
+
|
|
427
|
+
因此产品分层明确为:
|
|
428
|
+
|
|
429
|
+
- `archive`:稳定原材料层
|
|
430
|
+
- `conversations/`:可读视图层
|
|
431
|
+
- `SOUL.md` / `NOW.md` / `MISTAKES.md` / `MEMORY.md`:热路径与沉淀层
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
## Acceptance Criteria
|
|
436
|
+
|
|
437
|
+
archive contract 进入可实施状态,至少满足:
|
|
438
|
+
|
|
439
|
+
1. 路径结构固定为 `.system/archive/YYYY/MM/DD/<channel>--<conversation-id>.ndjson`
|
|
440
|
+
2. 每条记录都有稳定公共头:`schema_version` / `at` / `direction` / `event_type` / `channel` / `conversation_id`
|
|
441
|
+
3. 不再使用自由形态 `payload` 作为稳定主字段
|
|
442
|
+
4. `raw` 不再属于 archive 稳定主合同
|
|
443
|
+
5. 事件类型集合被显式命名并收敛
|
|
444
|
+
6. archive 保持 append-only,不被 digest 或回写流程修改
|
|
445
|
+
7. 上层 memory / compression 机制可以演进,但不需要重定义 archive
|
|
446
|
+
|
|
447
|
+
---
|
|
448
|
+
|
|
449
|
+
## Implementation Notes
|
|
450
|
+
|
|
451
|
+
基于当前实现,下面两点需要在实现阶段重点修正:
|
|
452
|
+
|
|
453
|
+
1. 当前 archive 记录里存在 `raw` 字段,应从稳定主合同移除或降级为非稳定调试能力
|
|
454
|
+
2. 当前 `system` 事件使用自由 `payload`,应改成稳定 `system_type` + 限定字段模型
|
|
455
|
+
|
|
456
|
+
如果这两点不处理,archive 还不能算真正冻结。
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# SPEC: 受管 AI 环境下的后台启动边界
|
|
2
|
+
|
|
3
|
+
状态:Draft / Ready for implementation
|
|
4
|
+
更新时间:2026-03-14
|
|
5
|
+
|
|
6
|
+
## 背景
|
|
7
|
+
|
|
8
|
+
当前 `work-ally` 支持在普通终端中通过 `ally start` / `ally restart` 拉起后台 `supervisor`、`bridge`、`runtime-host` 与 `assistant-autosave`。
|
|
9
|
+
|
|
10
|
+
但在真实使用中出现了一个高价值问题:
|
|
11
|
+
|
|
12
|
+
- 维护者或另一个 AI 在受管执行环境里代用户执行 `ally start`
|
|
13
|
+
- 命令当下返回成功
|
|
14
|
+
- 日志里也能看到 `ws_started`、`work-ally started`
|
|
15
|
+
- 但宿主执行环境结束后,后台进程很快被一起回收
|
|
16
|
+
- 飞书用户与开发者后台随后表现为“像是启动过,但其实已经没在跑”
|
|
17
|
+
|
|
18
|
+
这会造成一种比直接失败更糟糕的体验:**伪成功**。
|
|
19
|
+
|
|
20
|
+
## 问题定义
|
|
21
|
+
|
|
22
|
+
当前缺口不是“后台服务没法启动”,而是:
|
|
23
|
+
|
|
24
|
+
1. 产品没有明确区分“用户自己的持久终端”与“AI/受管执行环境”
|
|
25
|
+
2. `ally start` 在不可靠宿主环境里仍然尝试后台化,并给出成功反馈
|
|
26
|
+
3. `ally status` 虽已有 stale 检测,但对首次使用者仍然太晚
|
|
27
|
+
|
|
28
|
+
## 目标
|
|
29
|
+
|
|
30
|
+
1. 禁止在受管 AI 执行环境里默认后台启动并返回伪成功
|
|
31
|
+
2. 把“后台常驻必须由用户自己的终端承担”收成明确产品边界
|
|
32
|
+
3. 对用户给出短、准、可执行的错误提示
|
|
33
|
+
4. 不破坏前台模式和现有正常终端启动路径
|
|
34
|
+
|
|
35
|
+
## 非目标
|
|
36
|
+
|
|
37
|
+
- 不实现桌面守护进程安装器
|
|
38
|
+
- 不在本次解决跨登录会话常驻
|
|
39
|
+
- 不把中间层做成系统级 launch agent
|
|
40
|
+
- 不阻止普通 shell / iTerm / Terminal 中的正常后台启动
|
|
41
|
+
|
|
42
|
+
## 核心判断
|
|
43
|
+
|
|
44
|
+
### 1. 受管 AI 执行环境不应被视为可靠后台宿主
|
|
45
|
+
|
|
46
|
+
如果当前进程运行在明显的受管 AI 执行环境中,例如存在 `CODEX_THREAD_ID` / `CODEX_CI=1` 这类标记,则默认不应把后台服务的长期存活建立在该宿主上。
|
|
47
|
+
|
|
48
|
+
### 2. 失败要早于“看起来成功”
|
|
49
|
+
|
|
50
|
+
与其让用户几分钟后在飞书或状态页看到 stale,不如在 `ally start` 当下就直接拒绝,并说明:
|
|
51
|
+
|
|
52
|
+
- 当前环境不适合后台启动
|
|
53
|
+
- 请回到你自己的终端执行
|
|
54
|
+
|
|
55
|
+
### 3. foreground 例外保留
|
|
56
|
+
|
|
57
|
+
若显式使用 `WORK_ALLY_FOREGROUND=1`,说明调用方知道自己在前台接管服务生命周期,此时不应拦截。
|
|
58
|
+
|
|
59
|
+
## 方案
|
|
60
|
+
|
|
61
|
+
### 1. 增加受管环境检测
|
|
62
|
+
|
|
63
|
+
在 shell 层增加一个最小检测函数,例如:
|
|
64
|
+
|
|
65
|
+
- 命中 `CODEX_THREAD_ID`
|
|
66
|
+
- 或 `CODEX_CI=1`
|
|
67
|
+
|
|
68
|
+
命中后视为“受管 AI 执行环境”。
|
|
69
|
+
|
|
70
|
+
### 2. 后台启动保护
|
|
71
|
+
|
|
72
|
+
在 `internal/modules/runtime/start.sh` 中:
|
|
73
|
+
|
|
74
|
+
- 若 `WORK_ALLY_FOREGROUND != 1`
|
|
75
|
+
- 且当前命中受管 AI 执行环境
|
|
76
|
+
- 则直接失败,不进入后台启动流程
|
|
77
|
+
|
|
78
|
+
建议提示语义:
|
|
79
|
+
|
|
80
|
+
- 当前环境不适合托管长期后台服务
|
|
81
|
+
- 请在你自己的终端里执行 `ally start`
|
|
82
|
+
- 若只想临时前台联调,可显式使用前台模式
|
|
83
|
+
|
|
84
|
+
### 3. `restart` 继承同样保护
|
|
85
|
+
|
|
86
|
+
`restart` 通过 `stop.sh + start.sh` 实现,因此无需额外重复实现;只要 `start.sh` 生效即可。
|
|
87
|
+
|
|
88
|
+
### 4. 文档同步
|
|
89
|
+
|
|
90
|
+
至少同步:
|
|
91
|
+
|
|
92
|
+
- `docs/user-quickstart.md`
|
|
93
|
+
- `docs/troubleshooting.md`
|
|
94
|
+
- `docs/manual-acceptance.md`
|
|
95
|
+
|
|
96
|
+
文档要讲清楚:
|
|
97
|
+
|
|
98
|
+
- AI 可以帮你改代码、查问题
|
|
99
|
+
- 但真正需要长期常驻的 assistant,最好由用户自己的终端执行 `ally start`
|
|
100
|
+
- 若在受管执行环境中尝试后台启动,产品会直接拒绝,避免伪成功
|
|
101
|
+
|
|
102
|
+
## 验收标准
|
|
103
|
+
|
|
104
|
+
1. 在普通终端中执行 `ally start`,现有后台启动路径不受影响
|
|
105
|
+
2. 在受管 AI 执行环境中执行 `ally start`,后台模式会直接失败
|
|
106
|
+
3. 失败文案明确提示“请在你自己的终端执行”
|
|
107
|
+
4. `WORK_ALLY_FOREGROUND=1 ally start` 仍可用于前台运行 / 联调
|
|
108
|
+
5. shell 回归覆盖上述分支
|
|
109
|
+
6. quickstart 与 troubleshooting 明确写出这一边界
|
|
110
|
+
|
|
111
|
+
## 风险与取舍
|
|
112
|
+
|
|
113
|
+
### 风险 1:环境识别是启发式的
|
|
114
|
+
|
|
115
|
+
是的,但这比继续允许伪成功更可控。V1 只抓最明确的 Codex 受管标记,不做泛化过度识别。
|
|
116
|
+
|
|
117
|
+
### 风险 2:会让 AI 代启动能力受限
|
|
118
|
+
|
|
119
|
+
这是刻意收边界。能改代码、不代表适合作为长期后台进程宿主。
|
|
120
|
+
|
|
121
|
+
## 结论
|
|
122
|
+
|
|
123
|
+
本期把这件事定义为产品边界,而不是用户自己总结经验:
|
|
124
|
+
|
|
125
|
+
- 受管 AI 环境不默认承担后台常驻
|
|
126
|
+
- `ally start` 在该环境下直接拒绝后台模式
|
|
127
|
+
- 用户回到自己的终端启动,才是可信路径
|