@plurnk/plurnk-agui 1.3.12 → 1.5.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 (44) hide show
  1. package/.env.defaults +8 -6
  2. package/README.md +11 -3
  3. package/SPEC.md +295 -88
  4. package/dist/AguiPlus.d.ts +2 -1
  5. package/dist/AguiPlus.d.ts.map +1 -1
  6. package/dist/AguiPlus.js +7 -7
  7. package/dist/AguiPlus.js.map +1 -1
  8. package/dist/DaemonSeam.d.ts +15 -26
  9. package/dist/DaemonSeam.d.ts.map +1 -1
  10. package/dist/DaemonSeam.js +1 -1
  11. package/dist/DaemonSeam.js.map +1 -1
  12. package/dist/EventRouter.d.ts.map +1 -1
  13. package/dist/EventRouter.js +16 -5
  14. package/dist/EventRouter.js.map +1 -1
  15. package/dist/Module.d.ts +5 -7
  16. package/dist/Module.d.ts.map +1 -1
  17. package/dist/Module.js +440 -163
  18. package/dist/Module.js.map +1 -1
  19. package/dist/Portal.d.ts +6 -0
  20. package/dist/Portal.d.ts.map +1 -1
  21. package/dist/Portal.js +12 -8
  22. package/dist/Portal.js.map +1 -1
  23. package/dist/ProposalHitl.d.ts.map +1 -1
  24. package/dist/ProposalHitl.js +48 -39
  25. package/dist/ProposalHitl.js.map +1 -1
  26. package/dist/Translator.d.ts +1 -1
  27. package/dist/Translator.d.ts.map +1 -1
  28. package/dist/Translator.js +114 -70
  29. package/dist/Translator.js.map +1 -1
  30. package/dist/config.d.ts +17 -0
  31. package/dist/config.d.ts.map +1 -0
  32. package/dist/config.js +30 -0
  33. package/dist/config.js.map +1 -0
  34. package/dist/index.d.ts +1 -1
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/observe.d.ts +8 -0
  37. package/dist/observe.d.ts.map +1 -0
  38. package/dist/observe.js +56 -0
  39. package/dist/observe.js.map +1 -0
  40. package/dist/types.d.ts +11 -21
  41. package/dist/types.d.ts.map +1 -1
  42. package/dist/types.js +1 -1
  43. package/dist/types.js.map +1 -1
  44. package/package.json +13 -8
package/.env.defaults CHANGED
@@ -4,15 +4,17 @@
4
4
  # The listener's ADDRESS is the daemon's surface (PLURNK_HOST/PLURNK_PORT — owned
5
5
  # by plurnk-service); the module owns the semantics on that surface.
6
6
 
7
- # Bearer for the module's edge authz. Empty = local trust (the loopback bind is
8
- # the boundary); set a value and every request must carry `authorization: Bearer <it>`.
7
+ # Bearer for the module's edge authz. Empty = no module-level bearer requirement;
8
+ # set a value and every non-preflight request must carry
9
+ # `authorization: Bearer <it>` ({§agui-http-authorization}).
9
10
  PLURNK_AGUI_TOKEN=
10
11
 
11
12
  # Per-run turn cap handed to the engine when a run doesn't carry its own maxTurns.
12
- # Empty = no module-level cap (the engine's own ceiling still applies).
13
+ # Empty = no module-level default; otherwise -1 or a non-negative safe integer
14
+ # (the engine's own operator ceiling still applies).
13
15
  PLURNK_AGUI_MAX_TURNS=
14
16
 
15
- # SSE heartbeat cadence in milliseconds (agui#3). A long model generation emits no
16
- # events, and consumer stacks kill silent bodies (undici defaults to 300s); a
17
- # comment frame every cadence keeps every consumer fed. 0 disables.
17
+ # Required SSE heartbeat cadence in milliseconds, from 0 through 2147483647.
18
+ # A long model generation emits no events, so a comment frame at this cadence keeps
19
+ # consumers fed. 0 disables.
18
20
  PLURNK_AGUI_HEARTBEAT_MS=15000
package/README.md CHANGED
@@ -7,7 +7,7 @@ interface and translates daemon lifecycle events into AG-UI events.
7
7
 
8
8
  `POST /` accepts `RunAgentInput` and returns an AG-UI event stream.
9
9
 
10
- PLURNK uses standard AG-UI events for runs, messages, steps, tool calls, state,
10
+ PLURNK uses standard AG-UI events for Runs, messages, steps, tool calls, state,
11
11
  and approval requests. Additional execution metadata uses namespaced
12
12
  `plurnk.*` custom events so generic AG-UI clients can ignore it safely.
13
13
 
@@ -27,9 +27,17 @@ daemon.registerModule(Module.init({
27
27
  }));
28
28
  ```
29
29
 
30
+ The service supplies this package's `.env.defaults` through the assembled
31
+ environment before module startup. A direct in-process consumer must provide
32
+ that environment or an explicit `heartbeatMs`; explicit `token`, `maxTurns`,
33
+ and `heartbeatMs` options override their corresponding environment values.
34
+ `SPEC.md` owns the exact value contract.
35
+
30
36
  The module owns transport authentication, request validation, event translation,
31
- and proposal delivery. Core owns persistence and model-loop policy; clients own
32
- rendering and local terminal/editor behavior.
37
+ and proposal delivery. It consumes core's disposition-bearing proposal projection
38
+ for both live events and reconnect rather than rebuilding policy from loop flags.
39
+ Core owns persistence and model-loop policy; clients own rendering and local
40
+ terminal/editor behavior.
33
41
 
34
42
  ## Development
35
43
 
package/SPEC.md CHANGED
@@ -7,78 +7,112 @@ recompute them.
7
7
 
8
8
  ## Architecture
9
9
 
10
- - **The module is an in-process plugin of the daemon** {§agui-daemon-client} — activated
10
+ - §agui-daemon-client **The module is an in-process plugin of the daemon** — activated
11
11
  at boot (`registerModule` → the core seam handle); it opens the AG-UI+ listener and owns
12
12
  the client interface. No WebSocket, no separate process.
13
- - **A plurnk SESSION is the world; an AG-UI THREAD is a conversation over it** {§agui-thread-is-run}
14
- — plurnk's machine model (service SPEC §machine-processes) splits the WORLD (a workspace: one
13
+ - §agui-thread-binding **A PLURNK workspace is the world; an AG-UI thread is a conversation over it**
14
+ — the lifecycle vocabulary is defined by service {§lifecycle-terms}. PLURNK's machine model ({§machine-processes}) splits the world (a workspace: one
15
15
  curated workspace) from the CONVERSATION (a worker: a history over that world). AG-UI's workspace
16
16
  concept is the workspace, selected by name, VERBATIM, via `forwardedProps.plurnk.workspace`
17
17
  (attach if it exists, create with exactly that name otherwise — no prefix, no forging). The
18
18
  workspace is REQUIRED: a worker has no existence without a world, so its absence is a contract
19
- violation the module rejects (500) — never a workspace forged from the `threadId`. The
19
+ violation the module rejects (400) - never a workspace forged from the `threadId`. The
20
20
  `threadId` is the conversation over that world, and the name is the identity at
21
- BOTH levels: `threadId` == the workspace name binds the workspace's MODEL run (the default
22
- conversation, `ensureModelWorker` — origin identifies it, never a name parse); a DISTINCT
21
+ BOTH levels: `threadId` == the workspace name binds the workspace's model worker (the default
22
+ conversation, `ensureModelWorker` — its durable default-conversation role identifies it,
23
+ never a name parse or root ordering); a DISTINCT
23
24
  `threadId` names its own conversation worker — found by name if it exists (forks and prior
24
- conversations are addressable as threads), minted via `createConversationWorker` (svc#366)
25
- if it doesn't. World-scoped actions (`loop.inject`, `loop.cancel`, `log.read` default,
26
- `run.fork`) operate on the THREAD's conversation, never blindly on the model worker.
27
- Extended context persists across AG-UI runs because the worker's log does.
28
- - **AG-UI owns the client lifecycle** {§agui-run-authority} — `threadId`, `runId`,
25
+ conversations are addressable as threads), minted via `createConversationWorker`
26
+ if it doesn't. The core workspace envelope carries only the workspace and selected client
27
+ actor ({§methods-rebind}); AG-UI owns the separate per-thread conversation binding.
28
+ `loop.inject`, `loop.cancel`, and `run.fork` operate on the THREAD's conversation.
29
+ `log.read` and `entry.read` default there and may explicitly select another workspace worker.
30
+ Extended context persists across AG-UI Runs because the worker's log does.
31
+ - §agui-run-authority **AG-UI owns the client lifecycle** — `threadId`, `runId`,
29
32
  `RUN_STARTED`, `RUN_FINISHED`, `RUN_ERROR`, interrupt outcomes, and `RunAgentInput.resume`
30
33
  follow the official `@ag-ui/core` schemas. PLURNK does not maintain a parallel client
31
34
  lifecycle dialect. PLURNK owns the internal worker/loop/turn topology and projects it
32
35
  through standard events plus namespaced `plurnk.*` extensions.
33
36
 
34
- ## The projection {§agui-projection}
35
-
36
- One daemon notification in, zero-or-more AG-UI events out (`Translator`, pure):
37
-
38
- | plurnk wire | AG-UI events |
39
- |---|---|
40
- | `loop.run` accepted | `RUN_STARTED` |
41
- | `log/entry` turn boundary | `STEP_FINISHED` + `STEP_STARTED` (`turn-<id>`) |
42
- | `log/entry` op=PLAN (model) | `REASONING_START` + `REASONING_MESSAGE_START/CONTENT/END` + `REASONING_END` (§475: current AG-UI reasoning; the deprecated THINKING_* is retired) |
43
- | `log/entry` op=SEND (model) | `TEXT_MESSAGE_START/CONTENT/END` + `CUSTOM plurnk.send` (signal/status) |
44
- | `log/entry` other op (model) | `TOOL_CALL_START/ARGS/END` (+ `TOOL_CALL_RESULT` when rx exists) |
45
- | `log/entry` op=model (mirror) | a correlated `REASONING_START` / `REASONING_ENCRYPTED_VALUE`* / `REASONING_END` span when the reasoning-item `attrs.reasoning` is present (see §agui-sealed-reasoning); otherwise nothing — forensic |
46
- | `log/entry` origin≠model | `CUSTOM plurnk.ambient` (foists, deltas, narrations) |
47
- | `loop/proposal` | `TOOL_CALL_START/ARGS/END`, then `RUN_FINISHED` with an interrupt outcome |
48
- | `loop/terminated` | `STATE_DELTA` (budget) + `CUSTOM plurnk.terminated` + `RAW` (the provider's native completion frame, `source: provider`, §475) + `RUN_FINISHED` (200) or `RUN_ERROR` (else) |
49
- | `telemetry/event` | `CUSTOM plurnk.telemetry` |
50
- | `stream/event` + `stream/concluded` | `CUSTOM plurnk.stream` + `ACTIVITY_SNAPSHOT` (the standard background-activity channel: `activityType` = the scheme, replace-snapshot, §475) |
51
- | `loop/quiesced` | `CUSTOM plurnk.quiesced` |
37
+ ## §agui-projection The projection
38
+
39
+ One accepted Run or daemon notification produces zero-or-more AG-UI events:
40
+
41
+ | plurnk wire | AG-UI events |
42
+ | ------------------------------------------ | ------------ |
43
+ | schema-valid `RunAgentInput` | `RUN_STARTED` + initial `STATE_SNAPSHOT` |
44
+ | `log/entry` turn boundary | `STEP_FINISHED` + `STEP_STARTED` (`turn-<id>`) |
45
+ | `log/entry` op=PLAN (model) | `ACTIVITY_SNAPSHOT` {§agui-plan-activity} |
46
+ | `log/entry` op=SEND (model) | `TEXT_MESSAGE_START/CONTENT/END` + `CUSTOM plurnk.send` (signal/status) |
47
+ | `log/entry` other op (model) | `TOOL_CALL_START/ARGS/END` (+ `TOOL_CALL_RESULT` when rx exists) |
48
+ | `log/entry` actionless `kind=model_emission` | At most one `REASONING_ENCRYPTED_VALUE`, attached to the same turn's actual SEND assistant message when {§agui-encrypted-reasoning} is satisfied; otherwise nothing beyond the forensic row. |
49
+ | `log/entry` origin≠model | `CUSTOM plurnk.ambient` (foists, deltas, narrations) |
50
+ | client-owned `loop/proposal` | `TOOL_CALL_START/ARGS/END`, then `RUN_FINISHED` with an interrupt outcome |
51
+ | `loop/terminated` | `STATE_DELTA` (budget) + `CUSTOM plurnk.terminated` (including the daemon's top-level attribution projection) + `RAW` (the provider's native completion frame, `source: provider`, §475) + `RUN_FINISHED` (`result.status === 200`) or `RUN_ERROR` (otherwise, from the exact RFC 9457 Problem Details) |
52
+ | transport failure after SSE opens | `CUSTOM plurnk.problem` (exact Problem Details) + `RUN_ERROR` (`code` = Problem `type`, `message` = Problem `detail`) |
53
+ | `notice/event` | `CUSTOM plurnk.notice` |
54
+ | `stream/event` + `stream/concluded` | `CUSTOM plurnk.stream` + `ACTIVITY_SNAPSHOT` (the standard background-activity channel: `activityType` = the scheme, replace-snapshot, §475). A conclusion preserves its exact universal `result`, including RFC 9457 Problem Details; AG-UI does not reconstruct failure from a status or summary. |
55
+ | `workspace/branch-batch` | `CUSTOM plurnk.branch_batch` with the daemon's full queued/running/completed/failed/recovery-required lifecycle payload |
56
+
57
+ §agui-plan-activity **PLAN is activity, not reasoning.** PLAN is the model's public,
58
+ durable statement of intended goals. Provider reasoning is a separate channel, so PLAN
59
+ never projects into AG-UI `REASONING_*` events. Live delivery and reattach preserve the
60
+ same log identity and verbatim goals:
61
+
62
+ | Projection | Standard representation |
63
+ | ---------- | ----------------------- |
64
+ | live | `ACTIVITY_SNAPSHOT { messageId: coordinate ?? id, activityType: "PLAN", content: { goals: body }, replace: true }` |
65
+ | reattach | `ActivityMessage { id: coordinate ?? id, role: "activity", activityType: "PLAN", content: { goals: body } }` inside `MESSAGES_SNAPSHOT` |
52
66
 
53
67
  - **An op row IS a tool call** — its `coordinate` is the `toolCallId`, its tx the args (one
54
68
  delta: a dispatched plurnk op is atomic), its rx the result. The log-shaped richness the
55
69
  core vocabulary can't hold (fold state, tags, tokens) stays on the row inside
56
70
  `plurnk.ambient`/`TOOL_CALL_RESULT` payloads.
57
- - **Sealed reasoning: a hard interface to the standard** {§agui-sealed-reasoning} — reasoning
58
- transmission is a SOLVED problem (OpenAI Responses / AG-UI reasoning-item; DIVERGENCES row 3 =
59
- reasoning CONVERGED, with no exception for its representation), so agui consumes the standard
60
- shape VERBATIM and does not translate a bespoke one. The REQUIRED seam contract: core surfaces
61
- the model's reasoning on the model row's `attrs.reasoning` as a LIST of reasoning items —
62
- `[{ id: string, subtype: "message" | "tool-call", encrypted?: [{ data, format }] }]` — because a
63
- turn can carry N reasoning entities (distinct ids), each its own span (the OpenAI Responses
64
- model). `id` is the entity's identity (the SAME id its open reasoning carries, so open text and
65
- sealed value are two faces of one entity). agui projects, per item, `REASONING_ENCRYPTED_VALUE`
66
- (`subtype`/`entityId`/`encryptedValue`) with
67
- `entityId` = the item `id`, correlated to a `REASONING_START/END` span keyed by that same `id`.
68
- `format` has no AG-UI slot; it rides `plurnk.row` losslessly. A non-array carrier is invalid.
69
- An item with a null/absent `id` or an unknown
70
- `subtype` is DROPPED (uncorrelatable → agui never coins an id or coerces a subtype).
71
- - **The custom namespace** {§agui-custom-namespace} — plurnk-specific metadata rides
71
+ - §agui-encrypted-reasoning **Encrypted reasoning projects only onto an entity
72
+ AG-UI actually created.** Core supplies the exact normalized provider-detail
73
+ list on the actionless `attrs.kind="model_emission"` row's `attrs.reasoning`.
74
+ No synthetic operation is introduced. The provider detail `id` is
75
+ forensic identity, not an AG-UI entity ID ({§provider-encrypted-reasoning}).
76
+
77
+ | Condition | Projection |
78
+ | ------------------------------------------- | ---------- |
79
+ | Same-turn SEND + one nonempty message value | One `REASONING_ENCRYPTED_VALUE` with `subtype: "message"` and `entityId` equal to that SEND message's coordinate. |
80
+ | Null or absent provider detail `id` | No effect on correlation; the actual SEND identity owns the client relation. |
81
+ | No SEND or not exactly one message value | No standard encrypted event. Nothing is selected, joined, or overwritten. |
82
+ | Provider-only and unprojected evidence | Detail `id`, `format`, ordering, and every value remain lossless on the `plurnk.row` mirror evidence. |
83
+ | Reattach | The same singular value occupies `encryptedValue` on the corresponding SEND `AssistantMessage` in `MESSAGES_SNAPSHOT`. |
84
+
85
+ AG-UI's single message slot cannot represent multiple provider details without
86
+ losing cardinality. The translator therefore emits neither invented reasoning
87
+ spans nor repeated events whose last value would silently overwrite its
88
+ siblings.
89
+ - §agui-custom-namespace **The custom namespace** — plurnk-specific metadata rides
72
90
  `CUSTOM` events named `plurnk.*` (`plurnk.send`, `plurnk.ambient`,
73
- `plurnk.telemetry`, `plurnk.stream`, `plurnk.quiesced`, `plurnk.terminated` — the full loop
91
+ `plurnk.notice`, `plurnk.stream`, `plurnk.branch_batch`, `plurnk.terminated` — the full loop
74
92
  outcome the budget `STATE_DELTA` can't hold). Generic frontends skip unknown customs; plurnk-aware frontends render
75
93
  them richly. Nothing plurnk-specific ever masquerades as a core event.
76
- - **Numbers pass through verbatim** {§agui-numbers-passthrough} — the budget `STATE_DELTA`
77
- carries the daemon's own usage figures (`contextTokens`, `contextSize` = the effective
78
- prompt budget, service#345). The module never recomputes a number; the daemon's gauge is
79
- the gauge.
80
94
 
81
- - **The row channel** {§agui-row-channel} — every log row ALSO rides `CUSTOM plurnk.row`
95
+ §agui-numbers-passthrough **Usage numbers pass through verbatim.** The module
96
+ never recomputes the daemon's gauge.
97
+
98
+ | AG-UI state location | Daemon source | Meaning |
99
+ |:--------------------------------------------|:-----------------------------------------|:--------|
100
+ | `snapshot.plurnk.providers[*].promptBudget` | `providers.list.aliases[*]` | Each provider alias's effective model-facing prompt ceiling, or `null` when unknown. |
101
+ | `STATE_DELTA /budget/contextTokens` | `loop/terminated.usage.contextTokens` | Latest turn's provider-reported prompt occupancy. |
102
+ | `STATE_DELTA /budget/promptBudget` | `loop/terminated.usage.promptBudget` | Latest turn's effective model-facing prompt ceiling, or `null` when unknown. |
103
+ | `STATE_DELTA /budget/promptTokens` | `loop/terminated.usage.promptTokens` | Loop-total provider-reported prompt usage. |
104
+ | `STATE_DELTA /budget/completionTokens` | `loop/terminated.usage.completionTokens` | Loop-total provider-reported completion usage. |
105
+
106
+ The `plurnk.terminated` custom event preserves those totals plus
107
+ `reasoningTokens` and `cachedTokens`; generic AG-UI budget state has no fields
108
+ for the latter pair.
109
+
110
+ §agui-cost-evidence `plurnk.terminated.usage` preserves the daemon's ordered
111
+ `costs` evidence and nullable `costUsd` verbatim. Generic AG-UI has no standard
112
+ monetary field; the custom event therefore distinguishes direct, Models.dev,
113
+ unknown, and zero evidence without fabricating any value.
114
+
115
+ - §agui-row-channel **The row channel** — every log row ALSO rides `CUSTOM plurnk.row`
82
116
  carrying the full wire entry (fold state, tags-in-signal, tokens, coordinate) alongside its
83
117
  core projection. Rich clients (TUI/nvim) render plurnk-native fidelity from `plurnk.row`;
84
118
  generic clients never see the difference. This is the metadata channel the exclusive-portal
@@ -88,75 +122,248 @@ One daemon notification in, zero-or-more AG-UI events out (`Translator`, pure):
88
122
  `STATE_DELTA`s. A dropped SSE stream cancels the loop (`loop.cancel`) — the frontend hanging
89
123
  up IS the abort signal; no worker is orphaned unwatched.
90
124
 
91
- - **Reattach replays** {§agui-replay} — a rediscovered thread (the module restarted, a second
125
+ - §agui-replay **Reattach replays** — a rediscovered thread (the module restarted, a second
92
126
  frontend arrived) attaches to its existing workspace by name→id and opens ORIENTED: the model
93
- worker's SENDs replay as `MESSAGES_SNAPSHOT` (the conversation spine; everything else stays
94
- reachable via live `plurnk.row`). Pending proposals remain durable and are presented as
127
+ worker's PLAN activities and SEND speech replay as `MESSAGES_SNAPSHOT`; everything else stays
128
+ reachable via live `plurnk.row`. Pending proposals remain durable and are presented as
95
129
  interrupts when the owning conversation is resumed; a days-old question is discoverable,
96
130
  never converted into a mystery hang.
97
131
 
98
- ## Stop-the-world {§agui-proposal-resolve}
132
+ ## §agui-proposal-resolve Stop-the-world
99
133
 
100
- Every client-owned daemon proposal — file edits, MCP auths, `[300]` operator questions
101
- (service#346) — emits an AG-UI tool call and terminates run A with
134
+ Every client-owned daemon proposal - file edits and `[300]` operator questions —
135
+ emits an AG-UI tool call and terminates AG-UI Run A with
102
136
  `RUN_FINISHED.outcome.type = "interrupt"`. The durable loop remains paused indefinitely
103
- by default; absence is not an answer. Run B on the same thread supplies standard
137
+ by default; absence is not an answer. AG-UI Run B on the same thread supplies standard
104
138
  `RunAgentInput.resume` entries. Each entry correlates through `interruptId = toolCallId =
105
139
  "prop:<logEntryId>"`; the module resolves every pending interrupt for that worker, binds
106
- run B to the persisted loop, and releases it. A resume containing foreign, partial, or
140
+ AG-UI Run B to the persisted loop, and releases it. A resume containing foreign, partial, or
107
141
  multi-worker interrupt sets fails before any proposal is released.
108
142
 
109
- ## The action surface {§agui-management-plane}
143
+ §agui-proposal-disposition **AG-UI consumes disposition; it does not infer policy.** Both the live `loop/proposal` payload and `CoreSeam.pendingProposals()` return the contracts-owned `ProposalProjection`. `disposition.owner` is the sole presentation branch:
144
+
145
+ | Disposition owner | AG-UI behavior |
146
+ | ----------------- | ----------------------------------------------------------------------------- |
147
+ | `client` | Emit/re-surface the proposal tool call and standard interrupt |
148
+ | `loop` | Emit no tool call; core applies the carried decision and the Run continues |
149
+
150
+ Raw `auto`, `noProposals`, operation, attrs, and stale-target facts remain visible evidence but are not re-evaluated here. Reconnect filters by the same disposition, so an internal policy failure cannot silently turn client presentation into an accidental fallback.
151
+
152
+ §agui-provider-policy-forwarding A textual Run forwards `alias`, `model`,
153
+ `childAlias`, and `childModel` from `forwardedProps.plurnk` unchanged to
154
+ `CoreSeam.runLoop`; an explicit `childAlias: null` remains distinguishable from
155
+ an omitted service-default selection.
156
+
157
+ ## §agui-management-plane The action surface
158
+
159
+ PLURNK has three inputs through the one AG-UI Run endpoint. A normal user message
160
+ and a standard proposal resume are not management actions and have no invented
161
+ `loop.run` or `loop.resolve` action names.
162
+
163
+ ```mermaid
164
+ flowchart LR
165
+ client["AG-UI client"] --> run["POST RunAgentInput"]
166
+ run --> classify{"Input form"}
167
+ classify -->|"textual user message"| loop["CoreSeam.runLoop"]
168
+ classify -->|"RunAgentInput.resume"| proposal["CoreSeam.resolveProposal"]
169
+ classify -->|"forwardedProps.plurnk.action"| actions{"AG-UI action registry"}
170
+ actions --> builtIn["Built-in validation<br/>and typed CoreSeam call"]
171
+ actions --> extension["CoreSeam.invokeModuleAction"]
172
+ loop --> events["Core event source"]
173
+ proposal --> events
174
+ builtIn --> events
175
+ events --> projection["AG-UI projection"]
176
+ extension --> result["plurnk.action.result"]
177
+ projection --> client
178
+ result --> client
179
+ ```
180
+
181
+ A management-action Run carries
182
+ `forwardedProps.plurnk.action = { kind, ...params }`. Once settled, it returns
183
+ one `CUSTOM plurnk.action.result` shaped as `{ kind, ok, result | problem }`,
184
+ followed by `RUN_FINISHED`. A proposal-gated action may first end with an
185
+ interrupt and deliver that settled result on the standard resume Run. A failed
186
+ action preserves exact RFC 9457 Problem Details and is the result of a
187
+ successfully transported management Run; it does not turn the Run into
188
+ `RUN_ERROR` or invent a parallel error string. Unknown kinds return an honest
189
+ `unknown-action` Problem. There is no side-channel endpoint.
190
+
191
+ | Public action | Scope | Parameters | Owner / effect |
192
+ |--------------------------|-----------|------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------|
193
+ | `ping` | Worldless | none | AG-UI-local liveness; returns `{}`. |
194
+ | `discover` | Worldless | none | AG-UI-local public membership manifest ({§discovery}). |
195
+ | `providers.list` | Worldless | none | `CoreSeam.listProviders`. |
196
+ | `workspace.list` | Worldless | none | `CoreSeam.listWorkspaces`. |
197
+ | `workspace.create` | Worldless | `name?`, `projectRoot?`, `settings?`, `constraints?` | Creates or attaches the exact named world, or asks core to create an automatically named world. |
198
+ | `workspace.attach` | Worldless | `id`, `workerId?` | `CoreSeam.attachWorkspace`; returns the selected envelope. |
199
+ | `workspace.workers` | Workspace | `id?` | `CoreSeam.listWorkers`; an explicit id overrides the bound workspace. |
200
+ | `log.read` | Workspace | `workerId?`, log-coordinate filters | `CoreSeam.readLog`; defaults to the thread's conversation worker. |
201
+ | `loop.inject` | Workspace | `prompt` | `CoreSeam.runLoop` on the thread's conversation worker; folds into live work or enqueues a loop. |
202
+ | `loop.cancel` | Workspace | none | `CoreSeam.cancelDrain` on the thread's conversation worker. |
203
+ | `workspace.prompts` | Workspace | `limit?` | `CoreSeam.listPrompts`. |
204
+ | `workspace.rename` | Workspace | `name` | `CoreSeam.renameWorkspace`. |
205
+ | `workspace.constrain` | Workspace | `effect`, `glob` | `CoreSeam.constrain`. |
206
+ | `workspace.unconstrain` | Workspace | `effect`, `glob` | `CoreSeam.unconstrain`. |
207
+ | `workspace.constraints` | Workspace | none | `CoreSeam.listConstraints`. |
208
+ | `workspace.derivation` | Workspace | none | `CoreSeam.workspaceDerivationStatus`. |
209
+ | `entry.read` | Workspace | `target`, `workerId?`, `channel?`, `offset?` | Calls `CoreSeam.readEntry` from the explicit worker perspective or the thread conversation by default, preserving validated {§entry-read-result}. |
210
+ | `op.exec` | Workspace | `command` | Constructs one EXEC statement and calls `CoreSeam.dispatchClientAction` on the client worker. |
211
+ | `op.parse` | Workspace | `text` | Parses and projects PLURNK text under {§agui-op-parse}. |
212
+ | `workspace.members` | Workspace | none | `CoreSeam.listMembers`. |
213
+ | `op.look` | Workspace | `text` | Admits one LOOK under {§agui-op-look}, rewrites it to READ, and calls core's no-log `look` projection. |
214
+ | `run.fork` | Workspace | `name?` | `CoreSeam.forkWorker` from the thread's conversation worker. |
215
+ | Registered module action | Worldless | owner-defined | `CoreSeam.invokeModuleAction`; the handler receives only the supplied params and owns their validation and result. |
216
+
217
+ ### §agui-op-parse Parsed-operation projection
218
+
219
+ `op.parse` dispatches all trusted-prefix statements as one client action and
220
+ preserves the parser's source order in its `results` array:
110
221
 
111
- A verb is a §3 action run: `forwardedProps.plurnk.action = {kind, …params}` in, one
112
- `CUSTOM plurnk.action.result` (`{kind, ok, result|error}`) out, `RUN_FINISHED`. There is
113
- no side-channel RPC endpoint; the worker envelope is the whole interface. Unknown kinds
114
- error honestly (`ok:false`). `loop.inject` rides this surface; its steered effect
115
- streams on the original worker's open SSE. `loop.cancel` is its counterpart — it aborts
116
- the model worker's active drain (the addressable spelling of the SSE-hangup abort; both
117
- clients' stop controls ride it). An action that opens a stream remains one live AG-UI run:
118
- its result is held until every observed stream emits `stream/concluded`, then the result
119
- and `RUN_FINISHED` close that same run. A client disconnect before settlement cancels the
120
- action worker with reason `client_disconnected`; it never silently converts the action
121
- into detached background work.
222
+ | Parser output | AG-UI result |
223
+ |------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
224
+ | Statement before the tail boundary | Its corresponding `CoreSeam.dispatchClientAction` result in the statement's position |
225
+ | Bounded hard error | A 400 `agui/action/parse-failed` result in the error's position, preserving parser detail, line, column, source, and severity |
226
+ | `unparsedTail` under {§unparsed-tail-boundary} | Exactly one final 400 `agui/action/parse-failed` result with its verbatim reason and position, `source: "grammar"`, and no adapter-authored recovery |
227
+ | Text item | No result; text is not dispatchable |
122
228
 
123
- ## Topology scope {§agui-topology-scope}
229
+ No statement at or beyond the tail boundary is dispatched. Every parse failure
230
+ uses `stage: "parsing"` and `retryable: false`.
231
+
232
+ ### §agui-op-look Single-statement observation admission
233
+
234
+ `op.look` admits a parser result only when it contains exactly one LOOK
235
+ statement, no other item, and no `unparsedTail`. Hidden surrounding whitespace
236
+ is not an item. The action never selects a trusted prefix or silently discards
237
+ a parser fact.
238
+
239
+ | Parser result | AG-UI outcome |
240
+ |-----------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------|
241
+ | First positioned diagnostic | 400 `agui/action/parse-failed`, preserving parser detail, line, column, source, and severity |
242
+ | No diagnostic, with `unparsedTail` | 400 `agui/action/parse-failed`, preserving its reason and position with `source: "grammar"` and `severity: "error"` |
243
+ | Text item, zero or multiple statements, or non-LOOK | 400 `agui/action/invalid-action-parameters` naming the observed admission fact |
244
+ | Exactly one LOOK and no other parser fact | Change only `op` to READ and call `CoreSeam.look` under {§op-look}; return its exact `OperationResult` through the action envelope |
245
+
246
+ Parser failures use `stage: "parsing"`; action-shape failures use
247
+ `stage: "action-validation"`. Both are non-retryable.
248
+
249
+ §agui-module-actions **One public action namespace.** Core rejects empty and
250
+ duplicate extension registrations ({§module-action-registration}). At module
251
+ startup AG-UI rejects any extension name colliding with a built-in before it
252
+ opens the listener. A recognized Problem thrown by an extension crosses the
253
+ boundary unchanged; an unexpected handler exception becomes the generic
254
+ `action-failed` Problem without exposing private exception text.
255
+
256
+ ### §discovery Discovery membership
257
+
258
+ The `discover` action returns membership, not a parallel description or schema
259
+ system:
260
+
261
+ ```ts
262
+ type Discovery = {
263
+ methods: Record<string, true>;
264
+ notifications: Record<string, true>;
265
+ display: ClientDisplayCapabilities;
266
+ };
267
+ ```
268
+
269
+ `display` is Core's validated, contracts-owned installed scheme/MIME projection
270
+ ({§client-display-capabilities}). AG-UI adds no fallback, font, theme, or packet
271
+ policy.
272
+
273
+ `methods` contains the 22 built-ins in the table plus every registered module
274
+ action. `notifications` contains exactly these externally projected daemon
275
+ event families:
276
+
277
+ | Notification |
278
+ |--------------|
279
+ | `log/entry` |
280
+ | `loop/terminated` |
281
+ | `loop/proposal` |
282
+ | `notice/event` |
283
+ | `stream/event` |
284
+ | `stream/concluded` |
285
+ | `workspace/branch-batch` |
286
+
287
+ Discovery does not report parameter pseudo-schemas, plugin catalogs, package
288
+ versions, or update availability. Object key order is not a contract.
289
+
290
+ `loop.inject`'s steered effect streams on the original worker's open SSE.
291
+ `loop.cancel` is its counterpart: the addressable spelling of the SSE-hangup
292
+ abort. An action that opens a stream remains one live AG-UI Run; its result is
293
+ held until every observed stream emits `stream/concluded`, then the result and
294
+ `RUN_FINISHED` close that Run. A client disconnect before settlement cancels
295
+ the action worker with reason `client_disconnected`; it never silently converts
296
+ the action into detached background work.
297
+
298
+ ## §agui-topology-scope Topology scope
124
299
 
125
300
  The workspace broadcast carries EVERY worker's rows (workers, the plurnk worker, siblings);
126
- only the thread's model worker projects onto the core vocabulary. Foreign-run rows ride
301
+ only the thread's model worker projects onto the core vocabulary. Foreign-worker rows ride
127
302
  `plurnk.row`/`plurnk.ambient` — visible to rich clients as topology, never interleaved
128
303
  into the conversation a generic frontend renders.
129
304
 
130
- ## Event fan and run settlement {§agui-broadcast-fan}
305
+ ## §agui-broadcast-fan Event fan and AG-UI Run settlement
131
306
 
132
- Workspace information fans to every open run: ambient rows and stream activity
307
+ Workspace information fans to every open AG-UI Run: ambient rows and stream activity
133
308
  remain visible across the workspace, with each SSE
134
- using its own render router. Terminal control does not fan. A message run binds
135
- to the exact `loopId` returned by `loop.run`; a proposal-resume run binds to the
309
+ using its own render router. Terminal control does not fan. A message AG-UI Run binds
310
+ to the exact `loopId` returned by `CoreSeam.runLoop`; a proposal-resume AG-UI Run binds to the
136
311
  pending proposal's persisted `loopId` before resolving it. Only that loop's
137
312
  `loop/terminated` event may emit `plurnk.terminated` and close the SSE.
313
+ The custom event preserves the daemon's exact universal `result`; failures use
314
+ the Problem `type` as the AG-UI error code and `detail` as its message. The
315
+ module never reconstructs a failure from a status, summary, or exception text.
138
316
  Proposal tool calls and interrupt outcomes route only to the proposal's owning
139
- worker; interrupting sibling runs would violate AG-UI run identity. Terminations
140
- that race ahead of the `loop.run` acknowledgement are held until
317
+ worker; interrupting sibling AG-UI Runs would violate AG-UI Run identity. Terminations
318
+ that race ahead of the `runLoop` acknowledgement are held until
141
319
  the loop identity is known. A sibling, child, or concurrent loop can therefore
142
- remain visible as topology without ending or relabelling this run.
320
+ remain visible as topology without ending or relabelling this AG-UI Run.
143
321
 
144
322
  Two consequences the module owns and a client must handle:
145
323
 
146
- - **Multiplicity.** Workspace stream information may arrive on every open run. A client
147
- that funnels all runs
148
- through one shared handler (e.g. a single dispatch) must SERIALIZE its management runs —
324
+ - **Multiplicity.** Workspace stream information may arrive on every open AG-UI Run. A client
325
+ that funnels all AG-UI Runs
326
+ through one shared handler (e.g. a single dispatch) must serialize its management Runs —
149
327
  one action in flight, the rest queued — or a background action's stream steals the shared
150
- slot. Both first-party clients do exactly this (nvim's management lane, svc#504).
151
- - **No silent drop.** Workspace information never routes to a lone last-binder — a regression to that
152
- shape is what svc#504 reported (a client-side single-slot handler, since fixed) and is
153
- pinned against here.
328
+ slot. Both first-party clients do exactly this through a serialized management lane.
329
+ - **No silent drop.** Workspace information never routes to a lone last-binder; the
330
+ client-side single-slot regression is pinned against here.
331
+
332
+ ## §agui-configuration Module configuration
154
333
 
155
- ## The worker endpoint {§agui-run-endpoint}
334
+ The daemon assembles installed package defaults through
335
+ {§operator-config-env-defaults}; AG-UI reads and validates its own keys from that
336
+ environment. Explicit `Module.init` options override their corresponding environment
337
+ values for direct in-process composition. The listener address remains service-owned.
338
+
339
+ | Input | Owner | Empty or absent | Accepted value | Effect |
340
+ | ---------------------------------- | ------- | -------------------------------------- | ----------------------------------- | ------ |
341
+ | `PLURNK_HOST` / `PLURNK_PORT` | Service | Invalid at service boot | Service-valid host and port | Core supplies the listener address to `Module.init`. |
342
+ | `PLURNK_AGUI_TOKEN` | AG-UI | No module-level bearer requirement | Any string | A non-empty value requires the exact bearer on every non-preflight request. |
343
+ | `PLURNK_AGUI_MAX_TURNS` | AG-UI | No module-level default | `-1` or a non-negative safe integer | Supplies `maxTurns` only when the Run does not carry its own value. |
344
+ | `PLURNK_AGUI_HEARTBEAT_MS` | AG-UI | Invalid; the package floor is required | Integer `0` through `2147483647` | SSE comment-frame cadence in milliseconds; `0` disables it. |
345
+
346
+ ## §agui-run-endpoint The AG-UI Run endpoint
156
347
 
157
348
  `POST /` (or `/agui`) accepts a schema-valid AG-UI `RunAgentInput`: the last textual
158
349
  `user` message becomes the
159
- `loop.run` prompt (`maxTurns`/`flags.auto` from env); the response is `text/event-stream`,
350
+ `CoreSeam.runLoop` prompt (`maxTurns`/`flags.auto` from the forwarded PLURNK
351
+ properties or module defaults); the response is `text/event-stream`,
160
352
  one `data:` line per event, ending after `RUN_FINISHED`/`RUN_ERROR`. Multimodal user content
161
353
  is rejected until the model-loop seam supports it deliberately. Loop auto never answers
162
354
  a question — that is the daemon's own rule; the module inherits it.
355
+
356
+ §agui-http-authorization When `PLURNK_AGUI_TOKEN` is non-empty, every
357
+ non-preflight request must carry that exact value as an
358
+ `authorization: Bearer <token>` header. Authorization precedes request-body
359
+ reading. A missing or mismatched credential returns the stable 401
360
+ `bearer-token-required` Problem.
361
+
362
+ §agui-http-failure Failures before SSE headers are sent use
363
+ `application/problem+json` with exact
364
+ RFC 9457 Problem Details. Once SSE has opened, `CUSTOM plurnk.problem` preserves
365
+ that same object and `RUN_ERROR` maps it to the standard AG-UI fields. The custom
366
+ event and `plurnk.terminated.result.problem` are lossless; `RUN_ERROR.code` and
367
+ `message` are the required standard projection, not a second failure object.
368
+ Consumers preserve the exact Problem from the lossless surface and never
369
+ reconstruct one from `RUN_ERROR`.
@@ -1,5 +1,6 @@
1
1
  import { type AguiEvent, type ProposalNotification } from "./types.ts";
2
2
  import type { Interrupt, ResumeEntry } from "@ag-ui/core";
3
+ import type { ProblemDetails } from "@plurnk/plurnk-contracts";
3
4
  export declare const proposalToolCallId: (logEntryId: number) => string;
4
5
  export declare const logEntryIdFromToolCallId: (toolCallId: string) => number | null;
5
6
  export declare const proposalToolName: (op: string) => string;
@@ -49,7 +50,7 @@ export type ActionOutcome = {
49
50
  result?: unknown;
50
51
  } | {
51
52
  ok: false;
52
- error: string;
53
+ problem: ProblemDetails;
53
54
  };
54
55
  export declare const actionResult: (kind: string, outcome: ActionOutcome) => AguiEvent;
55
56
  //# sourceMappingURL=AguiPlus.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AguiPlus.d.ts","sourceRoot":"","sources":["../src/AguiPlus.ts"],"names":[],"mappings":"AAQA,OAAO,EAAa,KAAK,SAAS,EAAE,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAClF,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAK1D,eAAO,MAAM,kBAAkB,eAAgB,MAAM,KAAG,MAA8B,CAAC;AACvF,eAAO,MAAM,wBAAwB,eAAgB,MAAM,KAAG,MAAM,GAAG,IAGtE,CAAC;AAOF,eAAO,MAAM,gBAAgB,OAAQ,MAAM,KAAG,MAAqE,CAAC;AAIpH,eAAO,MAAM,gBAAgB,MAAO,oBAAoB,KAAG,SAAS,EAOnE,CAAC;AAEF,eAAO,MAAM,iBAAiB,eAAgB,MAAM,KAAG,SAarD,CAAC;AAGH,MAAM,WAAW,UAAU;IAAG,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE;AAC3G,eAAO,MAAM,oBAAoB,UAAW,WAAW,KAAG,UAAU,GAAG,IAStE,CAAC;AAIF,MAAM,WAAW,aAAa;IAC1B,SAAS,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IAClG,SAAS,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAC9F,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjD,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACzD;AACD,eAAO,MAAM,aAAa,MAAO,aAAa,KAAG,SAA0E,CAAC;AAC5H,eAAO,MAAM,UAAU,YAAa,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,KAAG,SAA8D,CAAC;AAS1J,MAAM,WAAW,aAAa;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE;AAChF,eAAO,MAAM,WAAW,mBAAoB,OAAO,KAAG,aAAa,GAAG,IAOrE,CAAC;AACF,MAAM,MAAM,aAAa,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAC1F,eAAO,MAAM,YAAY,SAAU,MAAM,WAAW,aAAa,KAAG,SACuB,CAAC"}
1
+ {"version":3,"file":"AguiPlus.d.ts","sourceRoot":"","sources":["../src/AguiPlus.ts"],"names":[],"mappings":"AAQA,OAAO,EAAa,KAAK,SAAS,EAAE,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAClF,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAK/D,eAAO,MAAM,kBAAkB,eAAgB,MAAM,KAAG,MAA8B,CAAC;AACvF,eAAO,MAAM,wBAAwB,eAAgB,MAAM,KAAG,MAAM,GAAG,IAGtE,CAAC;AAOF,eAAO,MAAM,gBAAgB,OAAQ,MAAM,KAAG,MAAqE,CAAC;AAIpH,eAAO,MAAM,gBAAgB,MAAO,oBAAoB,KAAG,SAAS,EAOnE,CAAC;AAEF,eAAO,MAAM,iBAAiB,eAAgB,MAAM,KAAG,SAarD,CAAC;AAGH,MAAM,WAAW,UAAU;IAAG,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE;AAC3G,eAAO,MAAM,oBAAoB,UAAW,WAAW,KAAG,UAAU,GAAG,IAStE,CAAC;AAIF,MAAM,WAAW,aAAa;IAC1B,SAAS,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IAClG,SAAS,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAC9F,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjD,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACzD;AACD,eAAO,MAAM,aAAa,MAAO,aAAa,KAAG,SAA0E,CAAC;AAC5H,eAAO,MAAM,UAAU,YAAa,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,KAAG,SAA8D,CAAC;AAS1J,MAAM,WAAW,aAAa;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE;AAChF,eAAO,MAAM,WAAW,mBAAoB,OAAO,KAAG,aAAa,GAAG,IAOrE,CAAC;AACF,MAAM,MAAM,aAAa,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,CAAC;AACpG,eAAO,MAAM,YAAY,SAAU,MAAM,WAAW,aAAa,KAAG,SACuB,CAAC"}
package/dist/AguiPlus.js CHANGED
@@ -1,5 +1,5 @@
1
- // The AG-UI+ projection (single-interface rendering) — prototyped + unit-tested
2
- // standalone ahead of the in-process module (plurnk-agui#2, WS-1). Pure functions:
1
+ // {§agui-projection} The AG-UI+ projection is unit-tested independently of the
2
+ // in-process module. Pure functions:
3
3
  // engine state → AG-UI events, and the inverse resume-mapping. No transport, no I/O
4
4
  // — so it ports into the in-process module unchanged when the seam lands.
5
5
  //
@@ -7,15 +7,15 @@
7
7
  // shared STATE. This is the flagship choreography de-risked as logic before code.
8
8
  import { EventType } from "./types.js";
9
9
  // ── §1 — stop-the-world → tool-call ──────────────────────────────────
10
- // toolCallId correlates the terminating run's TOOL_CALL and interrupt with the next
11
- // run's ResumeEntry → the exact pending proposal. Encodes the logEntryId: `prop:<id>`.
10
+ // toolCallId correlates the terminating AG-UI Run's TOOL_CALL and interrupt with the next
11
+ // AG-UI Run's ResumeEntry → the exact pending proposal. Encodes the logEntryId: `prop:<id>`.
12
12
  export const proposalToolCallId = (logEntryId) => `prop:${logEntryId}`;
13
13
  export const logEntryIdFromToolCallId = (toolCallId) => {
14
14
  const m = /^prop:(\d+)$/.exec(toolCallId);
15
15
  return m === null ? null : Number(m[1]);
16
16
  };
17
- // Tool-call NAME — AG-UI terminology all the way up to the seam (operator ruling,
18
- // 2026-07-09): the client-facing name is AG-UI-conventional, NOT plurnk-namespaced.
17
+ // Tool-call NAME — AG-UI terminology all the way up to the seam: the client-facing
18
+ // name is AG-UI-conventional, not plurnk-namespaced.
19
19
  // A side-effecting proposal is an approval request; a [300] question elicits input.
20
20
  // The plurnk correlation rides the opaque toolCallId (`prop:<logEntryId>`), so the
21
21
  // generic names carry no plurnk vocabulary upward.
@@ -26,7 +26,7 @@ export const proposalToolCall = (p) => {
26
26
  const toolCallId = proposalToolCallId(p.logEntryId);
27
27
  return [
28
28
  { type: EventType.TOOL_CALL_START, toolCallId, toolCallName: proposalToolName(p.op) },
29
- { type: EventType.TOOL_CALL_ARGS, toolCallId, delta: JSON.stringify({ op: p.op, target: p.target, body: p.body, attrs: p.attrs, staleClobberRisk: p.staleClobberRisk ?? false }) },
29
+ { type: EventType.TOOL_CALL_ARGS, toolCallId, delta: JSON.stringify({ op: p.op, target: p.target, body: p.body, attrs: p.attrs, staleClobberRisk: p.staleClobberRisk }) },
30
30
  { type: EventType.TOOL_CALL_END, toolCallId },
31
31
  ];
32
32
  };
@@ -1 +1 @@
1
- {"version":3,"file":"AguiPlus.js","sourceRoot":"","sources":["../src/AguiPlus.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AguiPlus.js","sourceRoot":"","sources":["../src/AguiPlus.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,qCAAqC;AACrC,oFAAoF;AACpF,0EAA0E;AAC1E,EAAE;AACF,gFAAgF;AAChF,kFAAkF;AAElF,OAAO,EAAE,SAAS,EAA6C,MAAM,YAAY,CAAC;AAIlF,wEAAwE;AACxE,0FAA0F;AAC1F,6FAA6F;AAC7F,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,UAAkB,EAAU,EAAE,CAAC,QAAQ,UAAU,EAAE,CAAC;AACvF,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,UAAkB,EAAiB,EAAE;IAC1E,MAAM,CAAC,GAAG,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC1C,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,CAAC,CAAC;AAEF,mFAAmF;AACnF,qDAAqD;AACrD,oFAAoF;AACpF,mFAAmF;AACnF,mDAAmD;AACnD,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,EAAU,EAAU,EAAE,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC;AAEpH,+EAA+E;AAC/E,0EAA0E;AAC1E,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAuB,EAAe,EAAE;IACrE,MAAM,UAAU,GAAG,kBAAkB,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IACpD,OAAO;QACH,EAAE,IAAI,EAAE,SAAS,CAAC,eAAe,EAAE,UAAU,EAAE,YAAY,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;QACrF,EAAE,IAAI,EAAE,SAAS,CAAC,cAAc,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,gBAAgB,EAAE,CAAC,CAAC,gBAAgB,EAAE,CAAC,EAAE;QACzK,EAAE,IAAI,EAAE,SAAS,CAAC,aAAa,EAAE,UAAU,EAAE;KAChD,CAAC;AACN,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,UAAkB,EAAa,EAAE,CAAC,CAAC;IACjE,EAAE,EAAE,kBAAkB,CAAC,UAAU,CAAC;IAClC,MAAM,EAAE,WAAW;IACnB,UAAU,EAAE,kBAAkB,CAAC,UAAU,CAAC;IAC1C,OAAO,EAAE,8BAA8B;IACvC,cAAc,EAAE;QACZ,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACR,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE;YAClE,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;SAC3B;QACD,QAAQ,EAAE,CAAC,UAAU,CAAC;KACzB;CACJ,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,KAAkB,EAAqB,EAAE;IAC1E,MAAM,UAAU,GAAG,wBAAwB,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAC/D,IAAI,UAAU,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACrC,IAAI,KAAK,CAAC,MAAM,KAAK,WAAW;QAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;IAC5E,MAAM,OAAO,GAAG,KAAK,CAAC,OAA6D,CAAC;IACpF,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,CAAC;IACnC,MAAM,IAAI,GAAG,OAAO,OAAO,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IAC1E,IAAI,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACzF,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAC7E,CAAC,CAAC;AAUF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAgB,EAAa,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,cAAc,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;AAC5H,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,OAA6D,EAAa,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;AAU1J,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,cAAuB,EAAwB,EAAE;IACzE,MAAM,MAAM,GAAI,cAAgE,EAAE,MAAM,EAAE,MAAM,CAAC;IACjG,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC/D,MAAM,IAAI,GAAI,MAA6B,CAAC,IAAI,CAAC;IACjD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/D,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,EAAE,GAAG,MAAiC,CAAC;IACrE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC5B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,OAAsB,EAAa,EAAE,CAC5E,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,sBAAsB,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,GAAG,OAAO,EAAE,EAAE,CAAC,CAAC"}