@amalgm/chat 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/AGENTS.md +98 -0
- package/PURPOSE.md +143 -112
- package/README.md +82 -54
- package/dist/acp/index.d.ts +7 -0
- package/dist/acp/index.d.ts.map +1 -0
- package/dist/acp/index.js +7 -0
- package/dist/acp/index.js.map +1 -0
- package/dist/acp/projection.d.ts +30 -0
- package/dist/acp/projection.d.ts.map +1 -0
- package/dist/acp/projection.js +147 -0
- package/dist/acp/projection.js.map +1 -0
- package/dist/api/conversations.d.ts +66 -0
- package/dist/api/conversations.d.ts.map +1 -0
- package/dist/api/conversations.js +202 -0
- package/dist/api/conversations.js.map +1 -0
- package/dist/api/index.d.ts +3 -3
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +1 -2
- package/dist/api/index.js.map +1 -1
- package/dist/conversations/index.d.ts +3 -0
- package/dist/conversations/index.d.ts.map +1 -0
- package/dist/conversations/index.js +3 -0
- package/dist/conversations/index.js.map +1 -0
- package/dist/conversations/transcript.d.ts +13 -0
- package/dist/conversations/transcript.d.ts.map +1 -0
- package/dist/conversations/transcript.js +171 -0
- package/dist/conversations/transcript.js.map +1 -0
- package/dist/conversations/types.d.ts +147 -0
- package/dist/conversations/types.d.ts.map +1 -0
- package/dist/conversations/types.js +9 -0
- package/dist/conversations/types.js.map +1 -0
- package/dist/events/constructors.d.ts +9 -15
- package/dist/events/constructors.d.ts.map +1 -1
- package/dist/events/constructors.js +6 -12
- package/dist/events/constructors.js.map +1 -1
- package/dist/events/index.d.ts +2 -3
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +2 -3
- package/dist/events/index.js.map +1 -1
- package/dist/events/schema.d.ts +2 -5
- package/dist/events/schema.d.ts.map +1 -1
- package/dist/events/schema.js +2 -5
- package/dist/events/schema.js.map +1 -1
- package/dist/execution/contract.d.ts +51 -0
- package/dist/execution/contract.d.ts.map +1 -0
- package/dist/execution/contract.js +127 -0
- package/dist/execution/contract.js.map +1 -0
- package/dist/execution/index.d.ts +6 -0
- package/dist/execution/index.d.ts.map +1 -0
- package/dist/execution/index.js +4 -0
- package/dist/execution/index.js.map +1 -0
- package/dist/execution/revision.d.ts +5 -0
- package/dist/execution/revision.d.ts.map +1 -0
- package/dist/execution/revision.js +17 -0
- package/dist/execution/revision.js.map +1 -0
- package/dist/execution/store.d.ts +26 -0
- package/dist/execution/store.d.ts.map +1 -0
- package/dist/execution/store.js +38 -0
- package/dist/execution/store.js.map +1 -0
- package/dist/index.d.ts +8 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -25
- package/dist/index.js.map +1 -1
- package/dist/input/index.d.ts +3 -0
- package/dist/input/index.d.ts.map +1 -0
- package/dist/input/index.js +2 -0
- package/dist/input/index.js.map +1 -0
- package/dist/input/prompt.d.ts +17 -0
- package/dist/input/prompt.d.ts.map +1 -0
- package/dist/input/prompt.js +104 -0
- package/dist/input/prompt.js.map +1 -0
- package/dist/normalizers/claude.d.ts +6 -9
- package/dist/normalizers/claude.d.ts.map +1 -1
- package/dist/normalizers/claude.js +5 -8
- package/dist/normalizers/claude.js.map +1 -1
- package/dist/normalizers/codex.d.ts +5 -8
- package/dist/normalizers/codex.d.ts.map +1 -1
- package/dist/normalizers/codex.js +4 -7
- package/dist/normalizers/codex.js.map +1 -1
- package/dist/normalizers/cursor.d.ts +1 -2
- package/dist/normalizers/cursor.d.ts.map +1 -1
- package/dist/normalizers/cursor.js +2 -3
- package/dist/normalizers/cursor.js.map +1 -1
- package/dist/normalizers/index.d.ts +3 -5
- package/dist/normalizers/index.d.ts.map +1 -1
- package/dist/normalizers/index.js +3 -5
- package/dist/normalizers/index.js.map +1 -1
- package/dist/normalizers/opencode.d.ts +2 -4
- package/dist/normalizers/opencode.d.ts.map +1 -1
- package/dist/normalizers/opencode.js +2 -4
- package/dist/normalizers/opencode.js.map +1 -1
- package/dist/normalizers/pi.d.ts +3 -4
- package/dist/normalizers/pi.d.ts.map +1 -1
- package/dist/normalizers/pi.js +3 -4
- package/dist/normalizers/pi.js.map +1 -1
- package/dist/sessions/chat.d.ts +176 -0
- package/dist/sessions/chat.d.ts.map +1 -0
- package/dist/sessions/chat.js +701 -0
- package/dist/sessions/chat.js.map +1 -0
- package/dist/sessions/index.d.ts +3 -0
- package/dist/sessions/index.d.ts.map +1 -0
- package/dist/sessions/index.js +2 -0
- package/dist/sessions/index.js.map +1 -0
- package/dist/transcript/index.d.ts +1 -1
- package/dist/transcript/index.js +1 -1
- package/dist/transcript/message-reducer.d.ts +1 -1
- package/dist/transcript/message-reducer.js +1 -1
- package/dist/transcript/part-accumulator.d.ts +1 -1
- package/dist/transcript/part-accumulator.js +1 -1
- package/dist/transcript/tool-display.d.ts +1 -1
- package/dist/transcript/tool-display.js +1 -1
- package/dist/transcript/tool-shape.d.ts +1 -1
- package/dist/transcript/tool-shape.js +1 -1
- package/dist/usage/finalize.d.ts +7 -9
- package/dist/usage/finalize.d.ts.map +1 -1
- package/dist/usage/finalize.js +11 -13
- package/dist/usage/finalize.js.map +1 -1
- package/dist/usage/index.d.ts +2 -3
- package/dist/usage/index.d.ts.map +1 -1
- package/dist/usage/index.js +2 -3
- package/dist/usage/index.js.map +1 -1
- package/dist/usage/model-catalog.d.ts +2 -3
- package/dist/usage/model-catalog.d.ts.map +1 -1
- package/dist/usage/model-catalog.js +10 -3
- package/dist/usage/model-catalog.js.map +1 -1
- package/dist/usage/normalize.d.ts +5 -7
- package/dist/usage/normalize.d.ts.map +1 -1
- package/dist/usage/normalize.js +3 -5
- package/dist/usage/normalize.js.map +1 -1
- package/dist/usage/ports.d.ts +14 -24
- package/dist/usage/ports.d.ts.map +1 -1
- package/dist/usage/ports.js +9 -17
- package/dist/usage/ports.js.map +1 -1
- package/dist/usage/steps.d.ts +70 -0
- package/dist/usage/steps.d.ts.map +1 -0
- package/dist/usage/steps.js +152 -0
- package/dist/usage/steps.js.map +1 -0
- package/dist/usage/tokens.d.ts +4 -7
- package/dist/usage/tokens.d.ts.map +1 -1
- package/dist/usage/tokens.js +4 -7
- package/dist/usage/tokens.js.map +1 -1
- package/docs/contracts/acp-and-step-usage.md +51 -0
- package/docs/contracts/conversation-persistence.md +47 -0
- package/docs/contracts/input-and-execution.md +177 -0
- package/docs/contracts/platform-authorization.md +17 -0
- package/host/adapters/acp-capabilities.js +30 -0
- package/host/adapters/acp-client.js +156 -0
- package/host/adapters/acp.js +284 -0
- package/host/adapters/claude.js +235 -0
- package/host/adapters/codex.js +733 -0
- package/host/adapters/cursor.js +347 -0
- package/host/adapters/input-capabilities.js +89 -0
- package/host/adapters/opencode.js +486 -0
- package/host/adapters/pi.js +519 -0
- package/host/adapters/prompt.js +212 -0
- package/host/auth.js +257 -0
- package/host/credentials/store.js +209 -0
- package/host/http.d.ts +32 -0
- package/host/http.js +238 -0
- package/host/index.d.ts +84 -0
- package/host/index.js +59 -0
- package/host/lib/runtime-paths.js +44 -0
- package/host/model-resolution.js +313 -0
- package/host/native-contract.js +185 -0
- package/host/native-runtime.js +194 -0
- package/host/permissions.js +27 -0
- package/host/platform-egress.js +114 -0
- package/host/recorder.js +61 -0
- package/host/sqlite/index.d.ts +69 -0
- package/host/sqlite/index.js +704 -0
- package/host/tooling/mcp-bundle.js +214 -0
- package/host/tooling/mcp-relay.js +83 -0
- package/host/tooling/native-binaries.js +667 -0
- package/host/tooling/native-config.js +460 -0
- package/host/tooling/package-import.js +111 -0
- package/host/tooling/runtime-home.js +26 -0
- package/host/tooling/system-instructions.js +69 -0
- package/host/tooling/system-prompt.js +35 -0
- package/package.json +44 -24
- package/skills/chat/SKILL.md +97 -0
- package/skills/chat/agents/openai.yaml +4 -0
- package/skills/chat/references/contracts.md +131 -0
- package/dist/api/chat-payloads.d.ts +0 -10
- package/dist/api/chat-payloads.d.ts.map +0 -1
- package/dist/api/chat-payloads.js +0 -57
- package/dist/api/chat-payloads.js.map +0 -1
- package/dist/contract/chat-input.d.ts +0 -144
- package/dist/contract/chat-input.d.ts.map +0 -1
- package/dist/contract/chat-input.js +0 -261
- package/dist/contract/chat-input.js.map +0 -1
- package/dist/contract/create.d.ts +0 -191
- package/dist/contract/create.d.ts.map +0 -1
- package/dist/contract/create.js +0 -249
- package/dist/contract/create.js.map +0 -1
- package/dist/contract/freeze.d.ts +0 -85
- package/dist/contract/freeze.d.ts.map +0 -1
- package/dist/contract/freeze.js +0 -151
- package/dist/contract/freeze.js.map +0 -1
- package/dist/contract/harnesses.d.ts +0 -21
- package/dist/contract/harnesses.d.ts.map +0 -1
- package/dist/contract/harnesses.js +0 -39
- package/dist/contract/harnesses.js.map +0 -1
- package/dist/contract/index.d.ts +0 -17
- package/dist/contract/index.d.ts.map +0 -1
- package/dist/contract/index.js +0 -17
- package/dist/contract/index.js.map +0 -1
- package/dist/contract/input.d.ts +0 -45
- package/dist/contract/input.d.ts.map +0 -1
- package/dist/contract/input.js +0 -78
- package/dist/contract/input.js.map +0 -1
- package/dist/contract/models.d.ts +0 -57
- package/dist/contract/models.d.ts.map +0 -1
- package/dist/contract/models.js +0 -380
- package/dist/contract/models.js.map +0 -1
- package/dist/contract/payload-merge.d.ts +0 -76
- package/dist/contract/payload-merge.d.ts.map +0 -1
- package/dist/contract/payload-merge.js +0 -215
- package/dist/contract/payload-merge.js.map +0 -1
- package/dist/events/tool-display.d.ts +0 -22
- package/dist/events/tool-display.d.ts.map +0 -1
- package/dist/events/tool-display.js +0 -60
- package/dist/events/tool-display.js.map +0 -1
- package/dist/events/tool-shape.d.ts +0 -48
- package/dist/events/tool-shape.d.ts.map +0 -1
- package/dist/events/tool-shape.js +0 -225
- package/dist/events/tool-shape.js.map +0 -1
- package/dist/relay/index.d.ts +0 -65
- package/dist/relay/index.d.ts.map +0 -1
- package/dist/relay/index.js +0 -197
- package/dist/relay/index.js.map +0 -1
- package/dist/turns/index.d.ts +0 -11
- package/dist/turns/index.d.ts.map +0 -1
- package/dist/turns/index.js +0 -11
- package/dist/turns/index.js.map +0 -1
- package/dist/turns/queries.d.ts +0 -36
- package/dist/turns/queries.d.ts.map +0 -1
- package/dist/turns/queries.js +0 -37
- package/dist/turns/queries.js.map +0 -1
- package/dist/turns/replay.d.ts +0 -105
- package/dist/turns/replay.d.ts.map +0 -1
- package/dist/turns/replay.js +0 -163
- package/dist/turns/replay.js.map +0 -1
- package/dist/turns/status.d.ts +0 -49
- package/dist/turns/status.d.ts.map +0 -1
- package/dist/turns/status.js +0 -56
- package/dist/turns/status.js.map +0 -1
- package/dist/turns/turn-store.d.ts +0 -109
- package/dist/turns/turn-store.d.ts.map +0 -1
- package/dist/turns/turn-store.js +0 -169
- package/dist/turns/turn-store.js.map +0 -1
- package/dist/warm/client-cache.d.ts +0 -47
- package/dist/warm/client-cache.d.ts.map +0 -1
- package/dist/warm/client-cache.js +0 -48
- package/dist/warm/client-cache.js.map +0 -1
- package/dist/warm/envelope-cache.d.ts +0 -79
- package/dist/warm/envelope-cache.d.ts.map +0 -1
- package/dist/warm/envelope-cache.js +0 -85
- package/dist/warm/envelope-cache.js.map +0 -1
- package/dist/warm/index.d.ts +0 -18
- package/dist/warm/index.d.ts.map +0 -1
- package/dist/warm/index.js +0 -12
- package/dist/warm/index.js.map +0 -1
- package/dist/warm/payload.d.ts +0 -137
- package/dist/warm/payload.d.ts.map +0 -1
- package/dist/warm/payload.js +0 -112
- package/dist/warm/payload.js.map +0 -1
- package/dist/warm/revision.d.ts +0 -70
- package/dist/warm/revision.d.ts.map +0 -1
- package/dist/warm/revision.js +0 -63
- package/dist/warm/revision.js.map +0 -1
- package/dist/warm/store-policy.d.ts +0 -57
- package/dist/warm/store-policy.d.ts.map +0 -1
- package/dist/warm/store-policy.js +0 -89
- package/dist/warm/store-policy.js.map +0 -1
- package/dist/warm/store.d.ts +0 -42
- package/dist/warm/store.d.ts.map +0 -1
- package/dist/warm/store.js +0 -69
- package/dist/warm/store.js.map +0 -1
- package/dist/wire/frames.d.ts +0 -208
- package/dist/wire/frames.d.ts.map +0 -1
- package/dist/wire/frames.js +0 -245
- package/dist/wire/frames.js.map +0 -1
- package/dist/wire/index.d.ts +0 -7
- package/dist/wire/index.d.ts.map +0 -1
- package/dist/wire/index.js +0 -7
- package/dist/wire/index.js.map +0 -1
package/AGENTS.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# @amalgm/chat contributor guide
|
|
2
|
+
|
|
3
|
+
Read `PURPOSE.md` before changing this package. It is the load-bearing purpose
|
|
4
|
+
and axiom document. Update it in the same change whenever a public law changes.
|
|
5
|
+
|
|
6
|
+
## Ownership
|
|
7
|
+
|
|
8
|
+
Chat answers: “run this resolved agent in a durable conversation.”
|
|
9
|
+
|
|
10
|
+
- `@amalgm/agents` owns agent identity, immutable revisions, installation, and
|
|
11
|
+
Agent Home descriptors.
|
|
12
|
+
- `@amalgm/tools` owns the Toolbox catalog and immutable tool selection.
|
|
13
|
+
- `@amalgm/chat` owns prepared executions, conversations, turns, the runtime
|
|
14
|
+
pump, official ACP updates, persistence, reconnect, interrupt, and usage.
|
|
15
|
+
- A host owns credentials, processes, filesystems, routing, and provider
|
|
16
|
+
network effects.
|
|
17
|
+
- `@amalgm/stream` and application UIs render Chat output; they do not own turn
|
|
18
|
+
lifetime or transport.
|
|
19
|
+
|
|
20
|
+
There is one implementation of each concern. Git is history; do not add a
|
|
21
|
+
second route, store, event grammar, payload cache, or session subsystem for
|
|
22
|
+
older callers.
|
|
23
|
+
|
|
24
|
+
## Working laws
|
|
25
|
+
|
|
26
|
+
1. The authenticated host supplies the owner. Requests cannot choose it.
|
|
27
|
+
2. Agents resolves one installation and exact immutable revision before Chat
|
|
28
|
+
executes it.
|
|
29
|
+
3. Preparation may resolve control-plane facts. Start and send consume one
|
|
30
|
+
immutable prepared handle and never rediscover configuration.
|
|
31
|
+
4. Prompt content and streamed output use official ACP shapes. Amalgm adds only
|
|
32
|
+
namespaced durability metadata and its separate step-usage record.
|
|
33
|
+
5. One runtime pump owns provider iteration. Disconnect only removes a
|
|
34
|
+
subscriber; interrupt is the explicit provider-stop operation.
|
|
35
|
+
6. Accepted input and every output update commit before execution or fanout
|
|
36
|
+
advances past them.
|
|
37
|
+
7. A turn has monotonically increasing durable sequence numbers and seals once.
|
|
38
|
+
Reconnect replays after a cursor and then follows the same live turn.
|
|
39
|
+
8. Restart preserves committed output and marks uncertain work interrupted
|
|
40
|
+
unless an adapter proves reattachment.
|
|
41
|
+
9. Auth mode is explicit and never falls back: platform, subscription, or BYOK.
|
|
42
|
+
10. Unknown usage is `null`, not fabricated zero. Billing authority is separate
|
|
43
|
+
from context telemetry.
|
|
44
|
+
|
|
45
|
+
## Public composition
|
|
46
|
+
|
|
47
|
+
Application code uses `Chat` or the browser-safe `@amalgm/chat/api` client.
|
|
48
|
+
Node hosts use `createChatHost` from `@amalgm/chat/host`. That composed host
|
|
49
|
+
owns one owner-scoped SQLite journal and one HTTP protocol under `/chat`:
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
POST /chat/executions
|
|
53
|
+
GET /chat/conversations
|
|
54
|
+
POST /chat/conversations
|
|
55
|
+
GET /chat/conversations/:id
|
|
56
|
+
PATCH /chat/conversations/:id
|
|
57
|
+
DELETE /chat/conversations/:id
|
|
58
|
+
POST /chat/conversations/:id/resume
|
|
59
|
+
POST /chat/conversations/:id/turns
|
|
60
|
+
GET /chat/conversations/:id/turns/:turnId/events
|
|
61
|
+
GET /chat/conversations/:id/active
|
|
62
|
+
POST /chat/conversations/:id/interrupt
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Platform egress and selected remote MCP relays are session-local auxiliary
|
|
66
|
+
doors under that same `/chat` host. They are not separate Chat services.
|
|
67
|
+
|
|
68
|
+
## Tree
|
|
69
|
+
|
|
70
|
+
```text
|
|
71
|
+
src/input/ official ACP prompt validation
|
|
72
|
+
src/execution/ normalized contracts and immutable prepared handles
|
|
73
|
+
src/sessions/ Chat capability, runtime pump, reconnect, interrupt
|
|
74
|
+
src/conversations/ private records, transcript projection, storage ports
|
|
75
|
+
src/acp/ official ACP projection
|
|
76
|
+
src/events/ provider-neutral native adapter events
|
|
77
|
+
src/normalizers/ provider event translators
|
|
78
|
+
src/transcript/ transcript reduction
|
|
79
|
+
src/usage/ context, step, turn, and billing-normalization laws
|
|
80
|
+
host/adapters/ native and generic ACP effects
|
|
81
|
+
host/sqlite/ WAL conversation store and durable turn journal
|
|
82
|
+
host/http.js the one HTTP/SSE protocol
|
|
83
|
+
host/index.js the one Node host composition
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Verification
|
|
87
|
+
|
|
88
|
+
Every change must leave purpose, axioms, file tree, and behavior aligned.
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
npm test
|
|
92
|
+
npm pack --dry-run
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Test invariants rather than individual symptoms: exact revision resolution,
|
|
96
|
+
input-before-invocation, update-before-fanout, one pump, disconnect survival,
|
|
97
|
+
cursor replay, idempotent interrupt, restart recovery, and official ACP-only
|
|
98
|
+
surface output.
|
package/PURPOSE.md
CHANGED
|
@@ -1,115 +1,146 @@
|
|
|
1
|
-
# @amalgm/chat —
|
|
2
|
-
|
|
3
|
-
Status: extraction in progress · founded 2026-08-06 · source of truth for laws:
|
|
4
|
-
`amalgm-engine/runtime/scripts/chat-core/` (production until cutover)
|
|
1
|
+
# @amalgm/chat — purpose and axioms
|
|
5
2
|
|
|
6
3
|
## Purpose
|
|
7
4
|
|
|
8
|
-
Chat is
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
-
|
|
108
|
-
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
5
|
+
Amalgm Chat is the small, reliable, high-performance SDK for talking to any
|
|
6
|
+
agent. It serves developers and agents building chat products: they should be
|
|
7
|
+
able to create a new interface in minutes, switch among Claude Code, Codex,
|
|
8
|
+
Cursor, OpenCode, Pi, and ACP agents without changing the interface's
|
|
9
|
+
conversation model, and receive one trustworthy transcript and usage record.
|
|
10
|
+
|
|
11
|
+
The SDK owns conversation laws. It does not own process spawning, credentials,
|
|
12
|
+
cloud synchronization, workspaces, provider installation, or UI rendering.
|
|
13
|
+
Those effects are supplied by a host. Amalgm's UI, API, CLI, MCP surface,
|
|
14
|
+
automations, and third-party apps must all use the same public SDK.
|
|
15
|
+
|
|
16
|
+
## Workstream 1 primitives
|
|
17
|
+
|
|
18
|
+
- An **ACP session** is the standard agent/client interaction boundary.
|
|
19
|
+
- A **turn** is one accepted user prompt and its ordered result.
|
|
20
|
+
- A **model step** is one provider model invocation inside a turn.
|
|
21
|
+
- A **session update** is the official ACP output shape.
|
|
22
|
+
- A **step usage record** is Amalgm's immutable usage extension for one model
|
|
23
|
+
step.
|
|
24
|
+
- A **turn usage record** is derived from its finalized step usage records.
|
|
25
|
+
- A **raw record** is the native provider evidence retained beside a normalized
|
|
26
|
+
projection.
|
|
27
|
+
- A **prompt** is an ordered list of official ACP content blocks.
|
|
28
|
+
- An **execution contract** is the normalized set of choices required by one
|
|
29
|
+
future turn.
|
|
30
|
+
- A **prepared execution** is an immutable execution revision plus an opaque,
|
|
31
|
+
already-resolved host binding.
|
|
32
|
+
|
|
33
|
+
## Workstream 1 axioms
|
|
34
|
+
|
|
35
|
+
1. ACP owns session lifecycle, prompt content, MCP server configuration,
|
|
36
|
+
permission requests, agent output, tool activity, and terminal stop reasons
|
|
37
|
+
wherever the stable protocol has those semantics.
|
|
38
|
+
2. Amalgm does not copy ACP types. The public ACP boundary imports and exposes
|
|
39
|
+
the official TypeScript SDK.
|
|
40
|
+
3. Amalgm extensions use ACP's `_meta` mechanism when they annotate an ACP
|
|
41
|
+
value. Rich usage remains a separate typed record because stable ACP does
|
|
42
|
+
not describe step-level token usage.
|
|
43
|
+
4. Text and reasoning are ACP content chunks. Tool activity is ACP `tool_call`
|
|
44
|
+
and `tool_call_update` with `pending`, `in_progress`, `completed`, or
|
|
45
|
+
`failed` state.
|
|
46
|
+
5. MCP describes remote tools and their transport. In-process tools may skip
|
|
47
|
+
MCP transport, but they expose the same content and result semantics.
|
|
48
|
+
6. A model step has one stable id and at most one finalized usage record.
|
|
49
|
+
Replay, reconnect, and additional subscribers cannot add usage.
|
|
50
|
+
7. Unknown token counts are `null`, never zero. Zero means the provider
|
|
51
|
+
explicitly measured zero.
|
|
52
|
+
8. Turn usage is the bucket-wise sum of its steps only when every contributing
|
|
53
|
+
step reports that bucket. Otherwise that turn bucket is `null`.
|
|
54
|
+
9. A cumulative provider counter becomes a step delta only against a proven
|
|
55
|
+
prior baseline. A missing baseline or counter reset remains unknown.
|
|
56
|
+
10. Raw provider usage and its provenance survive normalization.
|
|
57
|
+
11. Every surface consumes official ACP session updates; Chat has no second
|
|
58
|
+
event grammar.
|
|
59
|
+
12. Provider-specific behavior stays in adapters. Surfaces do not branch on
|
|
60
|
+
provider names.
|
|
61
|
+
13. Prompt content and execution configuration are separate. Send carries an
|
|
62
|
+
ACP prompt and a prepared execution handle, never an untrusted launch
|
|
63
|
+
payload.
|
|
64
|
+
14. Preparing may discover and resolve. Starting and sending may only consume
|
|
65
|
+
an already-prepared binding.
|
|
66
|
+
15. Auth and computer are selected per turn, not frozen to a conversation. A
|
|
67
|
+
running provider operation retains the execution facts it actually used.
|
|
68
|
+
16. A conversation store commits accepted input and every streamed update
|
|
69
|
+
before the provider or subscribers can advance past it.
|
|
70
|
+
17. Provider iteration belongs to the runtime pump, never to a client
|
|
71
|
+
subscriber. Disconnect and reconnect are cursor changes, not turn lifetime.
|
|
72
|
+
18. A process restart preserves committed output and marks uncertain active
|
|
73
|
+
work interrupted; it never silently repeats external effects.
|
|
74
|
+
19. Agents resolves identity and immutable revision; Chat owns the conversation
|
|
75
|
+
that executes that resolved revision. Chat never imports the Agents store.
|
|
76
|
+
20. Interrupt is a provider operation followed by a durable terminal state. A
|
|
77
|
+
turn is not cancelled merely because a subscriber disconnected or a UI
|
|
78
|
+
stopped rendering it.
|
|
79
|
+
21. Interrupt is idempotent for one active turn. The runtime receives at most
|
|
80
|
+
one stop request and every subscriber observes the same persisted result.
|
|
81
|
+
22. A host exposes Chat by composing the public `Chat` capability and its one
|
|
82
|
+
HTTP protocol; no other turn store, pump, or transport grammar exists.
|
|
83
|
+
23. A host supplies the machine-local runtime-state root. Every managed
|
|
84
|
+
provider home descends from that root and never enters portable user ground.
|
|
85
|
+
24. A prepared model binding retains three distinct identities: the normalized
|
|
86
|
+
selected model, the gateway identity used for auth and usage, and the exact
|
|
87
|
+
CLI token accepted by its adapter. Surfaces select; preparation translates.
|
|
88
|
+
No identity may be reconstructed from another after preparation.
|
|
89
|
+
25. Platform credentials are live host capabilities, never frozen strings. The
|
|
90
|
+
egress boundary requests one audience- and provider-scope-exact grant for
|
|
91
|
+
each HTTP operation, retries one rejected grant once after renewal, and
|
|
92
|
+
lets any remaining failure become the turn's durable failed state.
|
|
93
|
+
|
|
94
|
+
## North-star proof
|
|
95
|
+
|
|
96
|
+
A tiny example interface must use only the public SDK to:
|
|
97
|
+
|
|
98
|
+
- start or resume a session;
|
|
99
|
+
- send text and attachments;
|
|
100
|
+
- expose MCP and ordinary tools;
|
|
101
|
+
- handle permission requests;
|
|
102
|
+
- render text, reasoning, and tool activity from official ACP shapes;
|
|
103
|
+
- reconnect to the same turn; and
|
|
104
|
+
- interrupt a running turn without confusing disconnect with cancellation;
|
|
105
|
+
- show finalized usage for every model step and the derived turn.
|
|
106
|
+
|
|
107
|
+
Changing the selected adapter may change negotiated capabilities. It may not
|
|
108
|
+
require a new event grammar, transcript reducer, or UI data model.
|
|
109
|
+
|
|
110
|
+
## Current truth
|
|
111
|
+
|
|
112
|
+
The public SDK now has a high-level `Chat` capability, official ACP prompt
|
|
113
|
+
content, a normalized prepared-execution contract, exact revision handles, and
|
|
114
|
+
an official ACP output projection. Five native adapters and one generic ACP
|
|
115
|
+
adapter receive the canonical prompt directly. Every native adapter has been
|
|
116
|
+
exercised through the real public session path with text and an image. Claude
|
|
117
|
+
Code and Pi also passed combined image, selected-MCP-tool, `ask` permission,
|
|
118
|
+
tool-result, and streamed-output turns. Cursor and OpenCode have equivalent
|
|
119
|
+
real tool acceptance, and the generic adapter passed text and a selected MCP
|
|
120
|
+
tool against the live Cursor ACP server. Cursor accepts its native login or a
|
|
121
|
+
Cursor API key; OpenCode accepts an exact catalog variant. Step-usage identity
|
|
122
|
+
and aggregation are first-class laws. The public path now persists private
|
|
123
|
+
conversation headers, prompts, transcript projections, terminal turns, and
|
|
124
|
+
official ACP updates through an injected store. The reference SQLite adapter
|
|
125
|
+
uses WAL and commits input before provider invocation and output before fanout.
|
|
126
|
+
One background pump continues without subscribers; cursor replay survives a
|
|
127
|
+
host restart, and uncertain running turns recover as interrupted. The shipped
|
|
128
|
+
skill teaches this path.
|
|
129
|
+
|
|
130
|
+
The composable Node host uses the same owner-scoped SQLite journal and exposes
|
|
131
|
+
one HTTP protocol for execution preparation, conversation start/resume, turns,
|
|
132
|
+
official ACP updates, cursor reconnect, and interrupt. One user database holds
|
|
133
|
+
many private conversations across agent installations, while provider-native
|
|
134
|
+
homes remain isolated per installation beneath a host-supplied machine-local
|
|
135
|
+
runtime-state root.
|
|
136
|
+
|
|
137
|
+
It is not yet the complete north star. The remote gateway/Live authority does
|
|
138
|
+
not yet expose the conversation catalog and change stream; Live/R2
|
|
139
|
+
synchronization is not connected; provider adapters do not yet feed the full
|
|
140
|
+
step-usage ledger; every attachment form has not been exercised against every
|
|
141
|
+
provider; and permission requests are not yet a first-class application
|
|
142
|
+
stream. Generic ACP admission works from an immutable agent launch descriptor,
|
|
143
|
+
but Amp, Gemini CLI, and Kiro were not installed for individual acceptance
|
|
144
|
+
tests.
|
|
145
|
+
|
|
146
|
+
The public contracts live in `docs/contracts/` and the shipped Chat skill.
|
package/README.md
CHANGED
|
@@ -1,66 +1,94 @@
|
|
|
1
1
|
# @amalgm/chat
|
|
2
2
|
|
|
3
|
-
The
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
with [PURPOSE.md](PURPOSE.md) (the charter, seven jobs, ten axioms) and
|
|
8
|
-
[docs/responsibilities.md](docs/responsibilities.md) (every duty, the
|
|
9
|
-
four-copies ground truth, the garbage ledger, the known wounds).
|
|
3
|
+
The small, provider-agnostic SDK for agent conversations. Application code
|
|
4
|
+
prepares an execution, starts or resumes a session, sends official ACP content,
|
|
5
|
+
and consumes official ACP updates. Claude Code, Codex, Cursor, OpenCode, Pi,
|
|
6
|
+
and generic ACP behavior stay behind host adapters.
|
|
10
7
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
payload merge, input normalization
|
|
18
|
-
src/warm/ warm-payload laws: revision, fingerprint, cache policies
|
|
19
|
-
src/usage/ token algebra, turn finalization, ownership fork, catalog
|
|
20
|
-
src/normalizers/ claude · codex · opencode · cursor · pi → the grammar
|
|
21
|
-
src/api/ fetch adapters over SDK services
|
|
22
|
-
src/ports.ts the ports a host injects (clock, hash, uuid)
|
|
23
|
-
host/ the reference host: adapters, tooling, orchestration,
|
|
24
|
-
chat-server shell (effectful, imports the laws from dist)
|
|
25
|
-
docs/ the chat corpus: SDK spec, runtime law, normalizer
|
|
26
|
-
contracts + errata, internals map, warm payloads,
|
|
27
|
-
reducer divergences
|
|
28
|
-
```
|
|
8
|
+
Read [AGENTS.md](AGENTS.md) for the architecture and current gaps,
|
|
9
|
+
[PURPOSE.md](PURPOSE.md) for the axioms, and
|
|
10
|
+
[docs/contracts/input-and-execution.md](docs/contracts/input-and-execution.md)
|
|
11
|
+
for the public input path, and
|
|
12
|
+
[docs/contracts/conversation-persistence.md](docs/contracts/conversation-persistence.md)
|
|
13
|
+
for local conversations and durable turns.
|
|
29
14
|
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
15
|
+
```ts
|
|
16
|
+
import { Chat } from "@amalgm/chat";
|
|
17
|
+
import {
|
|
18
|
+
SqliteConversationStore,
|
|
19
|
+
createSqliteJournalBatchPolicy,
|
|
20
|
+
} from "@amalgm/chat/sqlite";
|
|
34
21
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
22
|
+
const conversations = new SqliteConversationStore({
|
|
23
|
+
databasePath: "/amalgm/users/user-id/conversations/conversations.sqlite",
|
|
24
|
+
});
|
|
25
|
+
const chat = new Chat({
|
|
26
|
+
runtime,
|
|
27
|
+
ownerUserId: authenticatedUser.id,
|
|
28
|
+
conversations,
|
|
29
|
+
uuid,
|
|
30
|
+
clockIso,
|
|
31
|
+
sha256Hex,
|
|
32
|
+
journalBatch: createSqliteJournalBatchPolicy(),
|
|
33
|
+
});
|
|
40
34
|
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
35
|
+
const execution = await chat.prepareExecution("composer", {
|
|
36
|
+
agent: {
|
|
37
|
+
adapterId: "codex",
|
|
38
|
+
installationId: "my-codex",
|
|
39
|
+
revisionId: "revision-7",
|
|
40
|
+
},
|
|
41
|
+
model: {
|
|
42
|
+
providerId: "openai",
|
|
43
|
+
modelId: "gpt-5.6-codex",
|
|
44
|
+
settings: [{ configId: "thought_level", value: "high" }],
|
|
45
45
|
},
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
auth: { mode: "subscription", bindingId: "codex-login" },
|
|
47
|
+
tools: { revisionId: null, toolIds: [] },
|
|
48
|
+
cwd: {
|
|
49
|
+
path: "/workspace/project",
|
|
50
|
+
workspaceId: null,
|
|
51
|
+
materializationRevision: null,
|
|
52
|
+
},
|
|
53
|
+
permissionMode: "ask",
|
|
54
|
+
computerId: "computer-1",
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const session = await chat.startSession({ execution });
|
|
58
|
+
const updates = await session.send({
|
|
59
|
+
execution,
|
|
60
|
+
prompt: { parts: [{ type: "text", text: "Hello" }] },
|
|
49
61
|
});
|
|
50
62
|
|
|
51
|
-
const
|
|
52
|
-
|
|
63
|
+
for await (const update of updates) render(update);
|
|
64
|
+
|
|
65
|
+
// Any client can reconnect from its last committed sequence.
|
|
66
|
+
for await (const update of session.reconnect(updates.turnId, { afterSequence: 42 })) {
|
|
67
|
+
render(update);
|
|
68
|
+
}
|
|
53
69
|
```
|
|
54
70
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
71
|
+
`prepareExecution` is the control plane. A host resolves tools, auth, agent
|
|
72
|
+
revision, provider/model, cwd, permissions, and placement there. Start and send
|
|
73
|
+
consume the prepared revision; send does not discover configuration.
|
|
58
74
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
75
|
+
```text
|
|
76
|
+
src/input/ ordered official ACP prompt content
|
|
77
|
+
src/execution/ normalized contracts, revisions, and prepared handles
|
|
78
|
+
src/sessions/ public prepare/start/resume/send capability
|
|
79
|
+
src/conversations/ private conversation, transcript, storage, and UI laws
|
|
80
|
+
src/acp/ official ACP door and event projection
|
|
81
|
+
src/events/ canonical native event grammar
|
|
82
|
+
src/normalizers/ native event translators
|
|
83
|
+
src/transcript/ transcript reduction
|
|
84
|
+
src/usage/ step and turn usage normalization
|
|
85
|
+
host/adapters/ effectful native protocol adapters
|
|
86
|
+
host/sqlite/ WAL conversation store and durable turn journal
|
|
87
|
+
host/http.js the one HTTP/SSE protocol, platform egress, and MCP relay door
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
npm install
|
|
92
|
+
npm test
|
|
93
|
+
npm pack --dry-run
|
|
94
|
+
```
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The canonical agent/client boundary is the official ACP SDK. Re-exporting
|
|
3
|
+
* it here gives Chat consumers one versioned door without copying the schema.
|
|
4
|
+
*/
|
|
5
|
+
export * from '@agentclientprotocol/sdk';
|
|
6
|
+
export { AMALGM_ACP_META_KEY, toAcpSessionNotification, toAcpSessionUpdate, toAcpToolKind, type AcpProjectionContext, type AmalgmAcpMeta, } from './projection.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/acp/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,0BAA0B,CAAC;AAEzC,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,kBAAkB,EAClB,aAAa,EACb,KAAK,oBAAoB,EACzB,KAAK,aAAa,GACnB,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The canonical agent/client boundary is the official ACP SDK. Re-exporting
|
|
3
|
+
* it here gives Chat consumers one versioned door without copying the schema.
|
|
4
|
+
*/
|
|
5
|
+
export * from '@agentclientprotocol/sdk';
|
|
6
|
+
export { AMALGM_ACP_META_KEY, toAcpSessionNotification, toAcpSessionUpdate, toAcpToolKind, } from './projection.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/acp/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,0BAA0B,CAAC;AAEzC,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,kBAAkB,EAClB,aAAa,GAGd,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { SessionNotification, SessionUpdate, ToolKind } from '@agentclientprotocol/sdk';
|
|
2
|
+
import type { AmalgmEvent } from '../events/schema.js';
|
|
3
|
+
export declare const AMALGM_ACP_META_KEY = "amalgm";
|
|
4
|
+
export interface AcpProjectionContext {
|
|
5
|
+
conversationId?: string;
|
|
6
|
+
turnId?: string;
|
|
7
|
+
sequence?: number;
|
|
8
|
+
messageId?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface AmalgmAcpMeta {
|
|
11
|
+
conversationId?: string;
|
|
12
|
+
turnId?: string;
|
|
13
|
+
sequence?: number;
|
|
14
|
+
native: {
|
|
15
|
+
type: string;
|
|
16
|
+
timestampMs: number;
|
|
17
|
+
raw?: unknown;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/** Map the richer native tool vocabulary into ACP's stable categories. */
|
|
21
|
+
export declare function toAcpToolKind(kind: unknown): ToolKind;
|
|
22
|
+
/**
|
|
23
|
+
* Project the provider-neutral native event grammar onto an official ACP session
|
|
24
|
+
* update. Events without an ACP session-update meaning return `null` instead
|
|
25
|
+
* of being disguised as a synthetic update.
|
|
26
|
+
*/
|
|
27
|
+
export declare function toAcpSessionUpdate(event: AmalgmEvent, context?: AcpProjectionContext): SessionUpdate | null;
|
|
28
|
+
/** Wrap a projected update in ACP's official session notification shape. */
|
|
29
|
+
export declare function toAcpSessionNotification(sessionId: string, event: AmalgmEvent, context?: AcpProjectionContext): SessionNotification | null;
|
|
30
|
+
//# sourceMappingURL=projection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projection.d.ts","sourceRoot":"","sources":["../../src/acp/projection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,aAAa,EAEb,QAAQ,EACT,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,eAAO,MAAM,mBAAmB,WAAW,CAAC;AAE5C,MAAM,WAAW,oBAAoB;IACnC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,GAAG,CAAC,EAAE,OAAO,CAAC;KACf,CAAC;CACH;AAoBD,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,CA6BrD;AAgBD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,EAClB,OAAO,GAAE,oBAAyB,GACjC,aAAa,GAAG,IAAI,CA4EtB;AAED,4EAA4E;AAC5E,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,WAAW,EAClB,OAAO,GAAE,oBAAyB,GACjC,mBAAmB,GAAG,IAAI,CAI5B"}
|