@mercury-fw/channel-http 0.14.2 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # @mercury-fw/channel-http
2
2
 
3
+ ## 0.15.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 9e2fbe4: - the verbatim archive keeps, with each answer, what its turn showed besides the text, as `trace`: reasoning blocks, tool status lines with their outcome, confirmations staged, logins asked for (no tokens, no login links)
8
+ - a stopped turn's interrupted answer keeps its `trace` up to the stop
9
+ - an answer that only staged an action keeps its `pendingNote`
10
+ - a resolved confirmation is archived in its conversation as a message with `confirmation: { id, status, choice? }`, its `content` the reply the person got
11
+ - `GET /conversation` returns `trace`, `pendingNote` and `confirmation`; `recall_verbatim` and a conversation rebuilt from the archive leave them out
12
+ - `ConfirmDeps.onResolved` (`@mercury-fw/confirm-engine`): told how a staged action was resolved
13
+ - `openapi.yaml`: `Message.trace`, `Message.pendingNote`, `Message.confirmation`, `TraceEntry`
14
+
15
+ ## 0.15.0
16
+
17
+ ### Minor Changes
18
+
19
+ - 148417b: - a step whose tool asks the person to log in ends the turn: no further tool calls
20
+ - the turn's text closes with `core.login.note`, naming the services to log in to (`core.login.note-any` when none has a name)
21
+ - `detectLoginRequests(step)` in `@mercury-fw/channel-types`: every login a step asks for, one per link
22
+ - HTTP channel: one `login` event per service the step asks for
23
+ - Google Chat: one login card per service the step asks for
24
+ - **Migration:** apps with their own locale files add `core.login.note` (`{services}`) and `core.login.note-any` to each non-English one
25
+
3
26
  ## 0.14.2
4
27
 
5
28
  ### Patch Changes
package/README.md CHANGED
@@ -72,7 +72,7 @@ Reasoning and answer text arrive as **incremental deltas** — never one finishe
72
72
  | `tool_finish` | `{ toolCallId, outcome }` | a tool call settles (`outcome`: `success` \| `failed` \| `pending`) |
73
73
  | `text` | `{ chunk }` | an answer-text delta |
74
74
  | `pending` | `{ command, token, choices }` | a confirm-required action was staged; send a token back to confirm it — as a later `/turn` `text`, or via `POST /confirm`. `choices` is every way to answer (`{ token, label }`, in order, each label in the caller's language; one with an empty `label` for a plain staging, which the UI words itself, a "Confirm" button): the others die with the one sent |
75
- | `login` | `{ service, url }` | the caller isn't logged in to `service` yet, which a plugin acts on as them: show them `url` to open (the model never gets it) |
75
+ | `login` | `{ service, url }` | the caller isn't logged in to `service` yet, which a plugin acts on as them: show them `url` to open (the model never gets it). One per service; the turn ends after the step that asked, its `final` text telling them to log in and write again |
76
76
  | `final` | `{ text, pendingNote? }` | the complete answer (also emitted for a token confirmation, with no model turn). `pendingNote` is there when the model wrote nothing because the turn staged an action: the core's stand-in sentence `text` begins with (then any list the turn surfaced). A UI showing its own confirmation hides it; the conversation's transcript keeps it |
77
77
  | `error` | `{ message }` | the turn failed mid-stream |
78
78
 
@@ -107,7 +107,7 @@ All `GET`, all JSON, all reporting state already held in-process. They need an a
107
107
 
108
108
  | endpoint | `data` on success |
109
109
  |---|---|
110
- | `GET /conversation?id=<conversationId>&limit=<n>&offset=<cursor>` | `{ messages: [{ role, content, interrupted?, timestamp }], nextOffset }` — one of your conversations, its durable transcript in order, each answer as you saw it with the lists it showed (empty for an id that isn't yours). An answer whose turn was cancelled has `interrupted: true` and an empty `content`: the question before it was left unanswered. `400` if `id` is missing or has other characters than `/turn` accepts |
110
+ | `GET /conversation?id=<conversationId>&limit=<n>&offset=<cursor>` | `{ messages: [{ role, content, interrupted?, trace?, pendingNote?, confirmation?, timestamp }], nextOffset }` — one of your conversations, its durable transcript in order, each answer as you saw it with the lists it showed (empty for an id that isn't yours). An answer whose turn was cancelled has `interrupted: true` and an empty `content`: the question before it was left unanswered. An answer's `trace` is what its turn showed besides the text, in order, as the events above showed it: each reasoning block in full, each status line with its tool and outcome, each confirmation staged (its command and its choices' labels, named by an `id`, never a token), each login asked for (its service, never the link); up to the stop for a cancelled turn. `pendingNote` is the turn's `final` one. A message with `confirmation: { id, status, choice? }` says how the staged action with that `id` (its trace entry) was resolved (`ok`, `failed`, or `resume`, whose answer is the next message): its `content` is the reply you got, empty for `resume`. Answers archived before these fields have none of them. `400` if `id` is missing or has other characters than `/turn` accepts |
111
111
  | `GET /conversations?limit=<n>` | `{ conversations: [{ conversationId, lastTimestamp, preview }] }` — your conversations, most-recently-active first; the preview is the newest message that shows something, so the question when the last answer was interrupted |
112
112
  | `GET /manifest` | `{ manifest: { coreApiVersion, plugins: [{ name, apiVersion, active, skills, hasBuild, customStatus }], activeClis, skills } }` |
113
113
  | `GET /confirmations` | `{ pending: [{ sessionKey, summary, expiresAt }] }` — your pending confirmations; tokens are deliberately never included |
package/http-server.ts CHANGED
@@ -23,7 +23,7 @@
23
23
  * package never imports the app.
24
24
  */
25
25
  import {
26
- detectLoginRequired,
26
+ detectLoginRequests,
27
27
  detectPendingConfirmation,
28
28
  type HandleTurn,
29
29
  type TurnSink,
@@ -262,8 +262,7 @@ export async function handleTurnRequest(req: Request, deps: TurnRequestDeps): Pr
262
262
  onStep: (step) => {
263
263
  const pending = detectPendingConfirmation(step);
264
264
  if (pending) send("pending", { command: pending.summary, token: pending.token, choices: pending.choices });
265
- const login = detectLoginRequired(step);
266
- if (login) send("login", { service: login.service, url: login.url });
265
+ for (const login of detectLoginRequests(step)) send("login", { service: login.service, url: login.url });
267
266
  },
268
267
  onUsage: () => {},
269
268
  // The core says when the text is its stand-in for an answer the
package/openapi.yaml CHANGED
@@ -132,7 +132,8 @@ paths:
132
132
  `tool_finish` (status of a tool call), `pending` (a staged
133
133
  confirm-required action, with its command, its token and the
134
134
  choices it offers), `login` (a
135
- service the caller has to log in to first, with the link to open),
135
+ service the caller has to log in to first, with the link to open;
136
+ one per service, and the turn ends after the step that asked),
136
137
  `final` (the
137
138
  authoritative complete answer), and `error`.
138
139
  headers:
@@ -261,7 +262,7 @@ paths:
261
262
  "503":
262
263
  $ref: "#/components/responses/NotAdmitted"
263
264
  "200":
264
- description: The conversation's messages in chronological order; none when it isn't one of the caller's.
265
+ description: The conversation's messages in chronological order, each answer with what its turn showed besides the text; none when it isn't one of the caller's.
265
266
  content:
266
267
  application/json:
267
268
  schema:
@@ -829,9 +830,93 @@ components:
829
830
  type: boolean
830
831
  enum: [true]
831
832
  description: "On an answer whose turn was stopped before it was finished (the client closed the stream): `content` is empty. The question before it was left unanswered."
833
+ trace:
834
+ type: array
835
+ description: >
836
+ On an answer: what the person saw of the turn besides its text, in
837
+ the order it happened, as the turn's events showed it (up to the
838
+ stop, for an interrupted one). Absent when there was nothing, and
839
+ on answers archived before it was kept.
840
+ items:
841
+ $ref: "#/components/schemas/TraceEntry"
842
+ pendingNote:
843
+ type: string
844
+ description: >
845
+ On an answer whose model wrote nothing because the turn staged an
846
+ action: the core's stand-in sentence `content` begins with, as the
847
+ turn's `final` event gave it. A UI showing the confirmation from
848
+ the trace hides it.
849
+ confirmation:
850
+ type: object
851
+ description: >
852
+ On the message saying how a staged action was resolved (a token
853
+ sent back, a choice clicked): `content` is the reply the person
854
+ got, empty when the confirmed action's result went back to the
855
+ model (`resume`), whose answer is the next message. `id` is the
856
+ one of the trace's `confirmation` entry it resolves, which says
857
+ what the action was.
858
+ required: [id, status]
859
+ properties:
860
+ id:
861
+ type: string
862
+ status:
863
+ type: string
864
+ enum: [ok, failed, resume]
865
+ choice:
866
+ type: string
867
+ description: The label of the choice taken, when the action was offered as several.
832
868
  timestamp:
833
869
  type: string
834
870
  description: ISO 8601, millisecond precision — the durable ordering key.
871
+ TraceEntry:
872
+ type: object
873
+ description: >
874
+ One thing a turn showed besides its text. `reasoning`: a reasoning
875
+ block in full, `failed` when it was cut. `tool`: a status line, with
876
+ the tool the model called (`name`, absent for Mercury's own lines) and
877
+ how it went (`outcome`, absent when it never finished). `confirmation`:
878
+ an action staged, with the labels of its choices (one empty label for a
879
+ plain confirmation); `id` names it, never its token. `login`: a login
880
+ asked for, by service, never its link.
881
+ required: [type]
882
+ properties:
883
+ type:
884
+ type: string
885
+ enum: [reasoning, tool, confirmation, login]
886
+ text:
887
+ type: string
888
+ description: On `reasoning`.
889
+ failed:
890
+ type: boolean
891
+ enum: [true]
892
+ description: On `reasoning`.
893
+ label:
894
+ type: string
895
+ description: On `tool`.
896
+ detail:
897
+ type: string
898
+ description: On `tool`.
899
+ name:
900
+ type: string
901
+ description: On `tool`.
902
+ outcome:
903
+ type: string
904
+ enum: [success, failed, pending]
905
+ description: On `tool`.
906
+ id:
907
+ type: string
908
+ description: On `confirmation`.
909
+ command:
910
+ type: string
911
+ description: On `confirmation`.
912
+ choices:
913
+ type: array
914
+ items:
915
+ type: string
916
+ description: On `confirmation`.
917
+ service:
918
+ type: string
919
+ description: On `login`.
835
920
  ConversationPage:
836
921
  type: object
837
922
  required: [ok, messages]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mercury-fw/channel-http",
3
- "version": "0.14.2",
3
+ "version": "0.15.1",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -18,11 +18,11 @@
18
18
  "access": "public"
19
19
  },
20
20
  "peerDependencies": {
21
- "@mercury-fw/channel-types": ">=0.65.0 <1.0.0"
21
+ "@mercury-fw/channel-types": ">=0.68.0 <1.0.0"
22
22
  },
23
23
  "devDependencies": {
24
- "@mercury-fw/channel-types": "0.67.0",
25
- "@mercury-fw/plugin-types": "0.67.0",
24
+ "@mercury-fw/channel-types": "0.69.0",
25
+ "@mercury-fw/plugin-types": "0.69.0",
26
26
  "@mercury-fw/typescript-config": "*",
27
27
  "@types/bun": "^1.4.2",
28
28
  "typescript": "^6.0.3"