@amalgm/agents 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.
Files changed (73) hide show
  1. package/PURPOSE.md +29 -22
  2. package/README.md +36 -46
  3. package/dist/agents.d.ts +4 -26
  4. package/dist/agents.js +4 -87
  5. package/dist/bin/mcp.js +1 -1
  6. package/dist/bundles/create.d.ts +13 -0
  7. package/dist/bundles/create.js +125 -0
  8. package/dist/bundles/graph-records.d.ts +10 -0
  9. package/dist/bundles/graph-records.js +61 -0
  10. package/dist/bundles/graph.d.ts +6 -0
  11. package/dist/bundles/graph.js +121 -0
  12. package/dist/bundles/install.d.ts +6 -0
  13. package/dist/bundles/install.js +64 -0
  14. package/dist/bundles/types.d.ts +97 -0
  15. package/dist/bundles/types.js +1 -0
  16. package/dist/bundles/util.d.ts +14 -0
  17. package/dist/bundles/util.js +56 -0
  18. package/dist/bundles/validate.d.ts +2 -0
  19. package/dist/bundles/validate.js +92 -0
  20. package/dist/cli/help.d.ts +1 -1
  21. package/dist/cli/help.js +2 -13
  22. package/dist/cli/open.d.ts +1 -1
  23. package/dist/cli/open.js +1 -5
  24. package/dist/cli/run.js +3 -8
  25. package/dist/errors.d.ts +1 -1
  26. package/dist/errors.js +0 -2
  27. package/dist/http/bundle-routes.d.ts +2 -0
  28. package/dist/http/bundle-routes.js +67 -0
  29. package/dist/http/server.js +4 -8
  30. package/dist/http-types.d.ts +3 -0
  31. package/dist/index.d.ts +7 -2
  32. package/dist/index.js +5 -2
  33. package/dist/mcp/agent-tools.js +1 -1
  34. package/dist/mcp/server.js +1 -1
  35. package/dist/mcp/tools.js +1 -2
  36. package/dist/rows.d.ts +1 -4
  37. package/dist/rows.js +0 -39
  38. package/dist/schema.js +53 -101
  39. package/dist/types.d.ts +0 -106
  40. package/docs/ARCHITECTURE.md +21 -33
  41. package/docs/CLI.md +3 -43
  42. package/docs/DATA_MODEL.md +7 -46
  43. package/docs/DEFINITIONS.md +4 -4
  44. package/docs/ENGINE_INTEGRATION.md +22 -67
  45. package/docs/MCP.md +3 -19
  46. package/docs/REST.md +14 -85
  47. package/docs/SDK.md +12 -61
  48. package/docs/SECURITY.md +6 -35
  49. package/examples/basic.ts +8 -22
  50. package/package.json +2 -2
  51. package/skills/amalgm-agents/SKILL.md +3 -12
  52. package/skills/amalgm-agents/agents/openai.yaml +2 -2
  53. package/dist/cli/session-commands.d.ts +0 -4
  54. package/dist/cli/session-commands.js +0 -54
  55. package/dist/drivers.d.ts +0 -4
  56. package/dist/drivers.js +0 -25
  57. package/dist/event-store.d.ts +0 -13
  58. package/dist/event-store.js +0 -50
  59. package/dist/http/session-routes.d.ts +0 -2
  60. package/dist/http/session-routes.js +0 -67
  61. package/dist/http/stream.d.ts +0 -3
  62. package/dist/http/stream.js +0 -30
  63. package/dist/mcp/session-tools.d.ts +0 -3
  64. package/dist/mcp/session-tools.js +0 -81
  65. package/dist/messages.d.ts +0 -3
  66. package/dist/messages.js +0 -56
  67. package/dist/runtime.d.ts +0 -29
  68. package/dist/runtime.js +0 -176
  69. package/dist/session-store.d.ts +0 -15
  70. package/dist/session-store.js +0 -83
  71. package/dist/turn-store.d.ts +0 -31
  72. package/dist/turn-store.js +0 -164
  73. package/docs/DRIVERS.md +0 -72
@@ -1,56 +1,17 @@
1
- # Persistence and recovery
1
+ # Persistence
2
2
 
3
3
  The default database is `agents.db` inside the state directory resolved by
4
- `@amalgm/core/identity`: `AMALGM_AGENTS_DIR` verbatim when set, otherwise
5
- `$AMALGM_DIR/agents`, otherwise the scoped layout
6
- `~/.amalgm/users/local/agents`. Set `stateDir` or `databasePath` to relocate
7
- it directly.
4
+ `@amalgm/core/identity`: `AMALGAM_AGENTS_DIR` verbatim when set, otherwise
5
+ `$AMALGAM_DIR/agents`, otherwise `~/.amalgm/users/local/agents`.
8
6
 
9
- ## Tables
7
+ The registry has two tables:
10
8
 
11
9
  | Table | Role |
12
10
  |---|---|
13
11
  | `agents` | stable identity, current revision pointer, tombstone |
14
12
  | `agent_revisions` | immutable normalized definitions |
15
- | `sessions` | pinned revision and opaque driver session id |
16
- | `turns` | accepted input and execution outcome |
17
- | `session_events` | ordered append-only execution observations |
18
-
19
- Foreign keys prevent orphan sessions, turns, and events. SQLite WAL mode and a
20
- five-second busy timeout support multiple read-oriented surfaces while one
21
- service owns mutations.
22
13
 
23
14
  Repeating the current definition is idempotent. Returning to content used by
24
- an earlier revision creates a new revision number so the definition timeline
25
- remains complete and append-only.
26
-
27
- ## Turn states
28
-
29
- ```text
30
- queued → running → completed
31
- ├──→ failed
32
- ├──→ cancelling → cancelled
33
- └──→ interrupted
34
- ```
35
-
36
- `queued`, `running`, and `cancelling` are non-terminal. At service startup they
37
- become `interrupted`, because the previous process may have completed external
38
- side effects before dying. The service never guesses and never automatically
39
- replays uncertain work.
40
-
41
- ## Idempotency
42
-
43
- `idempotencyKey` is unique within a session. Repeating a key returns its
44
- existing turn and does not invoke the driver again. Callers should derive it
45
- from their durable request identity instead of generating a new value on every
46
- retry.
47
-
48
- ## Events
49
-
50
- Every event receives the next integer sequence within its session. SSE first
51
- reads committed events after the requested sequence, then subscribes to newly
52
- committed events. Reconnecting with the last SSE id therefore closes the gap
53
- without polling or losing events.
54
-
55
- Events are facts, not mutable projections. User interfaces derive streaming
56
- text, messages, tool activity, and status from the ledger.
15
+ an earlier revision creates a new revision number, keeping the definition
16
+ timeline complete and append-only. Conversations and turns are stored only by
17
+ Chat.
@@ -37,13 +37,13 @@ products.
37
37
 
38
38
  `id` is a stable machine identity: 1–128 lowercase letters, numbers, dots,
39
39
  underscores, or hyphens. Renaming `name` never changes it. Deleted ids remain
40
- reserved so historical sessions cannot be confused with a new agent.
40
+ reserved so recorded revision identities cannot be reused.
41
41
 
42
42
  ## Revisions
43
43
 
44
44
  The normalized complete definition is hashed. An edit with equal content keeps
45
45
  the current revision. Any changed field creates a new immutable revision.
46
- Sessions always retain the revision selected at creation.
46
+ Chat records the exact revision selected for every prepared execution.
47
47
 
48
48
  ## PATCH behavior
49
49
 
@@ -61,5 +61,5 @@ authoritative and de-duplicated. Set nullable fields such as `model` or
61
61
  - `resources.skills` and `resources.files` are resolved by the host.
62
62
  - `resources.subagents` describes intended relationships; the host still
63
63
  authorizes every agent-to-agent call.
64
- - `driver.config` is non-secret runtime configuration interpreted only by the
65
- selected driver.
64
+ - `driver.config` is non-secret harness configuration interpreted only by
65
+ Chat's host runtime.
@@ -1,74 +1,29 @@
1
- # Amalgm Engine integration
1
+ # Shell integration
2
2
 
3
- Engine remains the composition root. This package becomes the canonical agent
4
- registry and session ledger; Engine supplies adapters for everything outside
5
- that domain.
3
+ Shell is the composition root. Agents supplies the canonical registry and Chat
4
+ supplies the canonical conversation runtime.
6
5
 
7
- ## Existing ownership to replace
6
+ ## Resolver boundary
8
7
 
9
- | Current Engine area | Destination |
10
- |---|---|
11
- | `amalgm-mcp/agents/store.js` agent rows | `AgentStore` through `Agents` |
12
- | `amalgm-mcp/agent-config/*` normalized config | immutable agent definitions |
13
- | `amalgm-mcp/agents/talk.js` durable sessions and logs | Agents sessions, turns, events |
14
- | `amalgm-mcp/agents/tools.js` | packaged MCP tools |
15
- | `amalgm-mcp/agents/rest.js` and route wiring | packaged REST adapter |
16
- | `chat-core` native runtime execution | Engine-supplied `AgentDriver` implementations |
17
- | Toolbox lookup and MCP resolution | `@amalgm/tools` adapter inside drivers |
18
- | credential adapter | `authRef` resolver inside drivers |
19
- | Supabase Chat session creation | Chat/cloud adapter observing Agents events |
8
+ Shell gives Chat a resolver with one job: map an installed agent id and optional
9
+ revision id to `agents.getAgentRevision(agentId, revisionId)`, then project that
10
+ immutable definition into Chat's execution contract. The resolver never writes
11
+ either product's store.
20
12
 
21
- Agent bundles currently mix agents, apps, automations, and tool bindings. That
22
- cross-product packaging concern should remain outside this repository. A bundle
23
- installer may call each product's public apply method.
13
+ Chat owns the conversation, accepted prompt, provider session, ordered durable
14
+ updates, transcript, usage, reconnect, and interrupt lifecycle. Agents owns the
15
+ identity and revision selected by that execution. Neither product imports the
16
+ other's database.
24
17
 
25
- ## Required driver adapter
18
+ Tool and action ids are resolved through `@amalgm/tools`; `authRef` is resolved
19
+ through the credential boundary. The resulting concrete values are frozen by
20
+ Chat before it accepts a turn.
26
21
 
27
- Engine should implement one driver per native harness identity (`codex`,
28
- `claude_code`, `opencode`, `pi`, and others). A driver translates the immutable
29
- revision into chat-core's runtime envelope, resolves `authRef`, projects the
30
- Toolbox loadout, forwards normalized streaming events, and returns the native
31
- session id for continuation.
22
+ ## Integration checks
32
23
 
33
- Drivers must not write Agents SQLite or invent another conversation log.
34
-
35
- ## Chat boundary
36
-
37
- Engine may associate an Agents session id with a Chat record. Chat owns title,
38
- participants, layout, read state, and cloud presentation. Agents owns pinned
39
- revision, accepted inputs, driver execution, and events. Synchronization is an
40
- adapter subscribed to committed Agents events; neither database is imported by
41
- the other product.
42
-
43
- ## One-time migration
44
-
45
- 1. Stop the legacy agent mutation and talk surfaces.
46
- 2. Read each legacy agent plus its `agent_config` as one complete definition.
47
- 3. Map `baseHarnessId` to `driver.id`, model fields to `model`, auth mode to an
48
- `authRef`, and legacy loadout ids to `toolbox.toolIds`.
49
- 4. Create missing agents and update existing agents through `Agents`.
50
- 5. Import local conversation JSONL as archived sessions only when its agent and
51
- chronological message identity are unambiguous; otherwise retain it as a
52
- legacy read-only export.
53
- 6. Start packaged REST and MCP adapters behind Engine's existing authenticated
54
- routes.
55
- 7. Enable native drivers and verify continuation against real harness sessions.
56
- 8. Delete the legacy registry, config, talk, REST, and MCP implementations only
57
- after parity and rollback checks pass.
58
-
59
- Migration must be idempotent. Record the source identity and migration version
60
- outside agent metadata or in a namespaced metadata field; never manufacture a
61
- new revision on equal reruns.
62
-
63
- ## Integration tests
64
-
65
- Before switchover, run:
66
-
67
- - legacy agent create/update/delete through the UI against `Agents`;
68
- - a session created on revision 1, followed by an agent edit and continuation;
69
- - native resume after Engine restart;
70
- - Toolbox loadout enforcement through `@amalgm/tools`;
71
- - provider authentication failure without credential persistence in Agents;
72
- - agent-to-agent background calls and cancellation;
73
- - Chat projection without Chat becoming the session source of truth; and
74
- - one-time migration twice with byte-for-byte equal resulting definitions.
24
+ - create, update, list, delete, and exact revision resolution use `Agents`;
25
+ - editing an agent never changes a Chat execution that already names a revision;
26
+ - Toolbox and credential references are authorized during preparation;
27
+ - provider restart, reconnect, and interrupt are handled only by Chat; and
28
+ - agent-to-agent interaction creates or joins a Chat conversation through the
29
+ same prepared-execution protocol as the UI.
package/docs/MCP.md CHANGED
@@ -3,22 +3,6 @@
3
3
  `amalgm-agents-mcp` is the standalone stdio server. `createMcpServer` from
4
4
  `@amalgm/agents/mcp` embeds the same server.
5
5
 
6
- It exposes seven tools:
7
-
8
- | Tool | Purpose |
9
- |---|---|
10
- | `agents_list` | List persistent agents |
11
- | `agents_get` | Inspect one agent |
12
- | `agents_create` | Create an agent |
13
- | `agents_update` | Edit an agent |
14
- | `agents_delete` | Delete an agent while retaining session history |
15
- | `agents_get_conversation` | Inspect a durable agent session |
16
- | `talk_to_agent` | Start or continue an agent session |
17
-
18
- `talk_to_agent` accepts the legacy `agent`, `conversation_id`, `description`,
19
- and `prompt` fields. `agent_id`, `session_id`, and structured `message` are
20
- also accepted. It returns `conversation_id` as the durable Agents session ID,
21
- not a Chat ID. Use `run_in_background` for long work.
22
-
23
- All handlers call the injected `Agents` service. MCP contains no second
24
- registry, transcript, execution engine, or routing subsystem.
6
+ It exposes five registry tools: `agents_list`, `agents_get`, `agents_create`,
7
+ `agents_update`, and `agents_delete`. Their handlers call the injected
8
+ `Agents` service; MCP contains no second registry and no conversation runtime.
package/docs/REST.md CHANGED
@@ -1,91 +1,20 @@
1
1
  # REST API
2
2
 
3
- Create an embeddable server with `createRestServer` from
4
- `@amalgm/agents/http`, or run `amalgm-agents-rest`.
3
+ Create an embeddable server with `createRestServer` from `@amalgm/agents/http`,
4
+ or run `amalgm-agents-rest`. The CLI binds `127.0.0.1:4317` by default.
5
5
 
6
- The CLI default is `127.0.0.1:4317`. If a token is configured, all `/v1`
7
- requests require the token via `Authorization: Bearer <token>` (scheme
8
- case-insensitive) or the `x-amalgm-runtime-token` header. A missing or wrong
9
- token receives the kernel's canonical 401 from `@amalgm/core/transport`,
10
- compared in constant time. `/healthz` is a minimal unauthenticated liveness
11
- response. JSON bodies default to a 512 KB limit.
12
-
13
- ## Agent configuration
14
-
15
- | Method | Path | Result |
16
- |---|---|---|
17
- | `GET` | `/agent-config` | List normalized configs from live agent revisions |
18
- | `POST` | `/agent-config/get` | Read `{ agent_id }` |
19
- | `POST` | `/agent-config/update` | Atomically apply `{ agent_id, config }` |
20
- | `POST` | `/agent-config/import-native` | Import safe native fields for `{ agent_id, replace? }` |
21
-
22
- Set `nativeHomeDir` when embedding the server or `--native-home`/
23
- `AMALGM_NATIVE_HOME` with the REST binary. Native import intentionally ignores
24
- auth files, secrets, and MCP server configuration.
25
-
26
- ## Agents
27
-
28
- | Method | Path | Result |
29
- |---|---|---|
30
- | `GET` | `/v1/agents` | List live agents |
31
- | `POST` | `/v1/agents` | Create from complete body |
32
- | `GET` | `/v1/agents/:id` | Read current definition |
33
- | `PATCH` | `/v1/agents/:id` | Merge a definition patch |
34
- | `DELETE` | `/v1/agents/:id` | Tombstone agent |
35
-
36
- Use `?include_deleted=true` on list or get to include tombstones.
37
-
38
- ## Sessions
6
+ When configured, authentication uses `Authorization: Bearer <token>` or the
7
+ `x-amalgm-runtime-token` header. `/healthz` is unauthenticated. JSON bodies
8
+ default to a 512 KB limit.
39
9
 
40
10
  | Method | Path | Result |
41
11
  |---|---|---|
42
- | `GET` | `/v1/sessions` | List sessions |
43
- | `POST` | `/v1/sessions` | Start `{ agentId, revisionId?, sessionId?, metadata? }` |
44
- | `GET` | `/v1/sessions/:id` | Read session |
45
- | `DELETE` | `/v1/sessions/:id` | Archive inactive session |
46
- | `GET` | `/v1/sessions/:id/turns` | List turns |
47
- | `GET` | `/v1/sessions/:id/events` | List ordered events |
48
- | `POST` | `/v1/sessions/:id/messages` | Send a turn |
49
- | `POST` | `/v1/sessions/:id/cancel` | Cancel active turn |
50
-
51
- List filters are `agent_id` and `include_archived=true`. Event pagination uses
52
- `after` and `limit` (maximum 1000).
53
-
54
- Send a message:
55
-
56
- ```json
57
- {
58
- "message": "Review the current diff.",
59
- "idempotencyKey": "review-001",
60
- "wait": true
61
- }
62
- ```
63
-
64
- `message` may also be a structured `AgentMessage`. `wait: false` returns `202`
65
- after durable acceptance; otherwise the response waits for a terminal turn.
66
-
67
- ## Server-sent events
68
-
69
- Connect to:
70
-
71
- ```text
72
- GET /v1/sessions/:id/events/stream?after=<last-sequence>
73
- ```
74
-
75
- The stream sends committed backlog first and then live events. SSE `id` equals
76
- the session sequence. Reconnect with the last seen id as `after`. Heartbeat
77
- comments are sent every 15 seconds.
78
-
79
- ## Errors
80
-
81
- Errors use the HTTP status associated with `AgentError`:
82
-
83
- ```json
84
- {
85
- "error": {
86
- "code": "conflict",
87
- "message": "Session already has an active turn.",
88
- "details": {}
89
- }
90
- }
91
- ```
12
+ | `GET` | `/v1/agents` | List available agents |
13
+ | `POST` | `/v1/agents` | Create from a complete definition |
14
+ | `GET` | `/v1/agents/:id` | Read the current definition |
15
+ | `PATCH` | `/v1/agents/:id` | Apply a definition patch |
16
+ | `DELETE` | `/v1/agents/:id` | Tombstone an identity |
17
+
18
+ Use `?include_deleted=true` on list or get to include tombstones. The same
19
+ server also exposes agent configuration, installed skills, and bundle routes
20
+ documented by their SDK modules. It exposes no conversation routes.
package/docs/SDK.md CHANGED
@@ -1,72 +1,23 @@
1
1
  # SDK reference
2
2
 
3
- The `Agents` class is the sole public behavior boundary. All mutations are
4
- durable before a method returns.
5
-
6
- ## Construction
3
+ `Agents` is the public behavior boundary for the local agent registry. Every
4
+ mutation is durable before it returns.
7
5
 
8
6
  ```ts
9
- const agents = new Agents({
10
- stateDir: './state',
11
- drivers: [codexDriver],
12
- maxInputBytes: 256_000,
13
- maxEventBytes: 256_000,
14
- turnTimeoutMs: 600_000,
15
- });
7
+ const agents = new Agents({ stateDir: './state' });
16
8
  ```
17
9
 
18
- `databasePath` overrides the database location directly. `turnTimeoutMs: 0`
19
- disables the service timeout. Call `close()` to abort owned executions, wait
20
- for them to settle, and close SQLite.
21
-
22
- ## Agent methods
10
+ `databasePath` overrides the database location directly. Call `close()` when
11
+ the embedding process releases the registry.
23
12
 
24
13
  | Method | Behavior |
25
14
  |---|---|
26
- | `createAgent(definition)` | Create identity and revision 1; conflicts on any reused id |
27
- | `updateAgent(id, patch)` | Merge a patch and apply the resulting definition |
28
- | `deleteAgent(id)` | Tombstone the identity while retaining history |
15
+ | `createAgent(definition)` | Create an identity and immutable revision 1 |
16
+ | `updateAgent(id, patch)` | Apply a patch, appending a revision when content changes |
17
+ | `deleteAgent(id)` | Tombstone the identity while retaining its revisions |
29
18
  | `getAgent(id, includeDeleted?)` | Read the current definition |
30
- | `listAgents(includeDeleted?)` | List live agents by default |
31
-
32
- ## Session methods
33
-
34
- | Method | Behavior |
35
- |---|---|
36
- | `startSession(input)` | Pin a new session to the current or named revision |
37
- | `talk(agentId, input)` | Start or continue a session, then enqueue a turn |
38
- | `enqueue(sessionId, input)` | Return immediately with the turn and completion promise |
39
- | `send(sessionId, input)` | Wait for the turn's terminal state |
40
- | `cancelSession(id)` | Persist cancellation intent and signal its active driver |
41
- | `archiveSession(id)` | Archive an inactive session |
42
- | `listSessions(agentId?, includeArchived?)` | Discover durable sessions |
43
- | `listTurns(sessionId)` | Read accepted inputs and outcomes |
44
- | `listEvents(sessionId, after?, limit?)` | Read ordered events |
45
-
46
- `enqueue` returns `{ turn, completion, duplicate }`. If an idempotency key was
47
- already accepted, `duplicate` is true and the original turn is returned.
48
-
49
- ## Event subscription
50
-
51
- ```ts
52
- const unsubscribe = agents.subscribe(session.id, (event) => {
53
- console.log(event.sequence, event.type, event.data);
54
- });
55
-
56
- await agents.send(session.id, { message: 'Hello' });
57
- unsubscribe();
58
- ```
59
-
60
- Listeners receive events only after commit. To build a reconnectable consumer,
61
- read `listEvents(after)` before subscribing and de-duplicate by sequence, as
62
- the packaged SSE adapter does.
63
-
64
- ## Errors
65
-
66
- Expected failures use `AgentError` with a stable code:
67
-
68
- `invalid_input`, `not_found`, `conflict`, `deleted`, `driver_unavailable`,
69
- `too_large`, or `cancelled`.
19
+ | `listAgents(includeDeleted?)` | List available agents by default |
20
+ | `getAgentRevision(agentId, revisionId?)` | Resolve the current or exact immutable revision |
70
21
 
71
- Driver failures become durable failed turns rather than escaping as transient
72
- transport errors. Inspect `turn.error` and the session event ledger.
22
+ Expected failures use `AgentError` with stable codes: `invalid_input`,
23
+ `not_found`, `conflict`, `deleted`, and `too_large`.
package/docs/SECURITY.md CHANGED
@@ -1,38 +1,9 @@
1
1
  # Security model
2
2
 
3
- Agents stores executable configuration and conversation history, so its state
4
- directory should be treated as user-private data.
3
+ Agent definitions contain `authRef`, never credentials. Toolbox ids, skill ids,
4
+ file references, and subagent ids are requests, not authority; Shell resolves
5
+ and authorizes them while preparing a Chat execution.
5
6
 
6
- ## Secrets
7
-
8
- Agent definitions contain `authRef`, not credentials. Drivers resolve that
9
- reference at execution time through the host's credential boundary. Do not put
10
- tokens, cookies, private keys, or passwords in `driver.config`, `metadata`,
11
- messages, or events.
12
-
13
- ## Capability references
14
-
15
- Toolbox ids and subagent ids are requests, not authority. The composing host
16
- must resolve them against the caller's allowed Toolbox view and agent policy.
17
- Agents never infers permission merely because an id appears in a definition.
18
-
19
- ## REST exposure
20
-
21
- The REST CLI binds `127.0.0.1` by default. Configure a bearer token before
22
- binding to a LAN, container bridge, tunnel, or public interface. The packaged
23
- server intentionally does not implement browser sessions, CORS, TLS, user
24
- accounts, or cloud authorization; Engine supplies those outer boundaries.
25
-
26
- ## Driver trust
27
-
28
- Drivers execute inside the hosting process and are trusted code. A driver can
29
- read its process environment and access the filesystem with that process's
30
- permissions. Load only reviewed modules. Native process drivers should avoid a
31
- shell, pass explicit arguments, bound output, and kill their child on abort.
32
-
33
- ## Stored data
34
-
35
- SQLite files are created beneath a mode-`0700` state directory. Application
36
- packaging and backups must preserve appropriate filesystem permissions.
37
- Messages and driver events may contain sensitive user content; retention and
38
- export policies belong to the embedding product.
7
+ The REST CLI binds loopback by default. Configure a bearer token before
8
+ binding it to a shared interface. SQLite state is created beneath a private
9
+ state directory and should be backed up with equivalent file permissions.
package/examples/basic.ts CHANGED
@@ -1,31 +1,17 @@
1
- import { Agents, defineDriver, messageText } from '@amalgm/agents';
1
+ import { Agents } from '@amalgm/agents';
2
2
 
3
- const echo = defineDriver({
4
- id: 'echo',
5
- async run(request) {
6
- return {
7
- driverSessionId: request.driverSessionId || `echo-${request.session.id}`,
8
- message: {
9
- role: 'assistant',
10
- parts: [{ type: 'text', text: `Echo: ${messageText(request.input)}` }],
11
- },
12
- };
13
- },
14
- });
3
+ const agents = new Agents({ stateDir: './example-state' });
15
4
 
16
- async function main(): Promise<void> {
17
- const agents = new Agents({ stateDir: './example-state', drivers: [echo] });
5
+ try {
18
6
  agents.createAgent({
19
7
  id: 'reviewer',
20
8
  name: 'Reviewer',
21
- driver: 'echo',
9
+ driver: 'codex',
22
10
  instructions: 'Review carefully.',
23
11
  });
24
12
 
25
- const call = agents.talk('reviewer', { message: 'Check this design.' });
26
- console.log(await call.completion);
27
- console.log(agents.listEvents(call.session.id));
28
- await agents.close();
13
+ const revision = agents.getAgentRevision('reviewer');
14
+ console.log(revision.id, revision.definition);
15
+ } finally {
16
+ agents.close();
29
17
  }
30
-
31
- void main();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@amalgm/agents",
3
- "version": "0.1.2",
4
- "description": "Local-first agent definitions, immutable revisions, and durable sessions.",
3
+ "version": "0.2.0",
4
+ "description": "Local-first agent identities, installations, and immutable revisions.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
7
7
  "repository": {
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: amalgm-agents
3
- description: Create, inspect, edit, delete, and talk to persistent Amalgm agents and their existing sessions. Use when a user wants to manage an agent definition, discover available agents, delegate work to an agent, continue an agent session, or inspect its transcript. Agents are separate from Chat conversations.
3
+ description: Create, inspect, edit, delete, install, and resolve persistent Amalgm agent identities and immutable revisions. Use when a user wants to manage an agent definition or discover available agents.
4
4
  ---
5
5
 
6
6
  # Amalgm Agents
@@ -17,14 +17,5 @@ Use the available Agents MCP tools. If MCP is unavailable, use the equivalent
17
17
  5. Keep tool, skill, file, credential, and subagent values as references; do
18
18
  not copy those products into the agent definition.
19
19
 
20
- ## Talk to an agent
21
-
22
- 1. Resolve the agent with `agents_list` or `agents_get` when its identity is
23
- ambiguous.
24
- 2. Call `talk_to_agent` without a session ID to start a session.
25
- 3. Preserve and return the resulting session ID.
26
- 4. Pass that ID to continue the same session.
27
- 5. Use conversation/session inspection to recover durable results or history.
28
- 6. Use background execution for work likely to outlive one MCP request.
29
-
30
- Never create a Chat conversation merely to represent an Agents session.
20
+ To run an agent, resolve its identity here and use Chat. Agents has no
21
+ conversation, execution, transcript, interrupt, or reconnect operation.
@@ -1,4 +1,4 @@
1
1
  interface:
2
2
  display_name: "Amalgm Agents"
3
- short_description: "Create, manage, and talk to Amalgm agents"
4
- default_prompt: "Use $amalgm-agents to create or talk to an agent."
3
+ short_description: "Create and manage Amalgm agents"
4
+ default_prompt: "Use $amalgm-agents to create or manage an agent."
@@ -1,4 +0,0 @@
1
- import type { Agents } from '../agents.js';
2
- import type { ParsedArgs } from './args.js';
3
- export declare function runSessionCommand(agents: Agents, args: ParsedArgs): Promise<unknown>;
4
- export declare function runTalkCommand(agents: Agents, args: ParsedArgs): Promise<unknown>;
@@ -1,54 +0,0 @@
1
- import { AgentError } from '../errors.js';
2
- import { enabled, flag } from './args.js';
3
- export async function runSessionCommand(agents, args) {
4
- const [, action, first, second] = args.words;
5
- if (action === 'list') {
6
- return { sessions: agents.listSessions(flag(args, 'agent'), enabled(args, 'include-archived')) };
7
- }
8
- if (action === 'start' && first) {
9
- const sessionId = flag(args, 'id');
10
- const revisionId = flag(args, 'revision');
11
- return { session: agents.startSession({
12
- agentId: first,
13
- ...(sessionId ? { sessionId } : {}),
14
- ...(revisionId ? { revisionId } : {}),
15
- }) };
16
- }
17
- if (action === 'show' && first) {
18
- const session = agents.getSession(first);
19
- if (!session)
20
- throw new AgentError('not_found', `Session not found: ${first}`);
21
- return { session, turns: agents.listTurns(first), events: agents.listEvents(first) };
22
- }
23
- if (action === 'events' && first) {
24
- return { events: agents.listEvents(first, Number(flag(args, 'after') || 0)) };
25
- }
26
- if (action === 'send' && first && second) {
27
- const idempotencyKey = flag(args, 'key');
28
- return { turn: await agents.send(first, {
29
- message: second,
30
- ...(idempotencyKey ? { idempotencyKey } : {}),
31
- }) };
32
- }
33
- if (action === 'cancel' && first)
34
- return { turn: agents.cancelSession(first) };
35
- if (action === 'archive' && first)
36
- return { session: agents.archiveSession(first) };
37
- throw new AgentError('invalid_input', 'Unknown or incomplete session command. Run with --help.');
38
- }
39
- export async function runTalkCommand(agents, args) {
40
- const [, agentId, message] = args.words;
41
- if (!agentId || !message)
42
- throw new AgentError('invalid_input', 'talk requires agent id and message.');
43
- const sessionId = flag(args, 'session');
44
- const idempotencyKey = flag(args, 'key');
45
- const call = agents.talk(agentId, {
46
- message,
47
- ...(sessionId ? { sessionId } : {}),
48
- ...(idempotencyKey ? { idempotencyKey } : {}),
49
- });
50
- if (enabled(args, 'background')) {
51
- return { session: call.session, turn: call.turn, duplicate: call.duplicate };
52
- }
53
- return { session: call.session, turn: await call.completion, duplicate: call.duplicate };
54
- }
package/dist/drivers.d.ts DELETED
@@ -1,4 +0,0 @@
1
- import type { AgentDriver } from './types.js';
2
- export declare function defineDriver(driver: AgentDriver): AgentDriver;
3
- export declare function loadDriverModules(specifiers: string[]): Promise<AgentDriver[]>;
4
- export declare function driverSpecifiers(value?: string): string[];
package/dist/drivers.js DELETED
@@ -1,25 +0,0 @@
1
- import path from 'node:path';
2
- import { pathToFileURL } from 'node:url';
3
- import { AgentError } from './errors.js';
4
- export function defineDriver(driver) {
5
- if (!driver || typeof driver.id !== 'string' || typeof driver.run !== 'function') {
6
- throw new AgentError('invalid_input', 'Agent drivers require id and run.');
7
- }
8
- return driver;
9
- }
10
- export async function loadDriverModules(specifiers) {
11
- const drivers = [];
12
- for (const specifier of specifiers) {
13
- const target = specifier.startsWith('.') || specifier.startsWith('/')
14
- ? pathToFileURL(path.resolve(specifier)).href
15
- : specifier;
16
- const loaded = await import(target);
17
- const value = loaded.default ?? loaded.driver ?? loaded;
18
- const driver = typeof value === 'function' ? await value() : value;
19
- drivers.push(defineDriver(driver));
20
- }
21
- return drivers;
22
- }
23
- export function driverSpecifiers(value = process.env.AMALGM_AGENT_DRIVERS || '') {
24
- return value.split(',').map((item) => item.trim()).filter(Boolean);
25
- }
@@ -1,13 +0,0 @@
1
- import type Database from 'better-sqlite3';
2
- import type { EventListener, JsonObject, SessionEvent } from './types.js';
3
- export declare class EventStore {
4
- private readonly database;
5
- private readonly now;
6
- private readonly listener;
7
- constructor(database: Database.Database, now: () => string, listener: EventListener);
8
- append(sessionId: string, turnId: string | null, type: string, data: JsonObject): SessionEvent;
9
- write(sessionId: string, turnId: string | null, type: string, data: JsonObject): SessionEvent;
10
- announce(event: SessionEvent): void;
11
- list(sessionId: string, after?: number, limit?: number): SessionEvent[];
12
- forTurn(turnId: string): SessionEvent[];
13
- }