@mercury-fw/channel-http 0.8.4 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/README.md +7 -4
- package/dist/http-server.d.ts +10 -1
- package/http-server.ts +46 -10
- package/openapi.yaml +76 -9
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# @mercury-fw/channel-http
|
|
2
2
|
|
|
3
|
+
## 0.10.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- b2f8cfb: - A confirmation can offer several choices (for example "only this time" / "always for this host"): a plugin tool stages them with the new `stageChoices` of `SessionToolContext`, and gets one token per choice. The person takes one; the others die with it, and they all expire together.
|
|
8
|
+
- The paper-trail note of a group of choices is one, under its first token, and says which choice was taken.
|
|
9
|
+
- `detectPendingConfirmation` returns the `choices` a staging offers; a plain staging is one choice labelled `Conferma`.
|
|
10
|
+
- A confirmed action can hand its result back to the model (`resume` on a choice): instead of showing the person the raw result, the channel resumes the turn and the model answers on it, the result reaching it as the tool result of the call that staged it, never stored in the history.
|
|
11
|
+
- A resumed turn answers the person who confirmed even in a shared space, and the line standing for the confirmation isn't archived as something they said. A result nobody resumes within five minutes (the life of a confirmation token) is forgotten, and a restart loses it.
|
|
12
|
+
- `InboundTurn.resumeAfterConfirm` and `RESUME_AFTER_CONFIRM` (channel contract) carry the resumed turn; `ConfirmOutcome` has a `resume` status.
|
|
13
|
+
- Terminal: every choice is printed on its own line with its token; a confirmation that resumes runs the turn again.
|
|
14
|
+
- Google Chat: the confirmation card has one button per choice; a typed token or a clicked choice that resumes runs the turn again, in the session's queue. The channel now needs channel-types 0.51.0 or later.
|
|
15
|
+
- HTTP: the `pending` event carries `choices`; a token sent to `POST /turn` that resumes streams the model's answer on the same request; `POST /confirm` answers `resume: true`, and `POST /turn { resume: true, conversationId }` runs that turn. The channel now needs channel-types 0.51.0 or later.
|
|
16
|
+
|
|
17
|
+
## 0.9.0
|
|
18
|
+
|
|
19
|
+
### Minor Changes
|
|
20
|
+
|
|
21
|
+
- b7438a6: - The assistant remembers how each person wants to be called: they say it in conversation and the model saves it with the new `set_preferred_name` tool. It's a setting kept in `.mercury/profiles.json` on the vault's volume, not a wiki note, and every one-to-one turn tells the model the name.
|
|
22
|
+
- A turn can be an opening (`opening: true`, with no text): the assistant speaks first, but only to someone whose name it doesn't know, introducing itself and asking how to call them. For anyone else, and in a shared space, it says nothing and keeps nothing.
|
|
23
|
+
- `ChannelHostReads.me` says how the caller asked to be called, or `null`.
|
|
24
|
+
- HTTP: `POST /turn` takes `{ opening: true, conversationId }`, and `GET /me` answers `{ name }`. A UI asks for an opening right after a sign-in, when the name is `null`. The channel now needs channel-types 0.49.0 or later.
|
|
25
|
+
|
|
3
26
|
## 0.8.4
|
|
4
27
|
|
|
5
28
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -45,10 +45,12 @@ Runs one conversational turn; the reply streams back as Server-Sent Events.
|
|
|
45
45
|
|
|
46
46
|
| field | type | required | description |
|
|
47
47
|
|---|---|---|---|
|
|
48
|
-
| `text` | string | yes | The user message. A bare confirmation token here confirms a staged action (see the `pending` event) without invoking the model. |
|
|
48
|
+
| `text` | string | yes, unless `opening` or `resume` | The user message. A bare confirmation token here confirms a staged action (see the `pending` event) without invoking the model; when the action hands its result back to the model, the model's answer streams on this same request. |
|
|
49
|
+
| `opening` | `true` | no | The assistant speaks first, before the person writes anything: what a UI asks right after someone signs in, when `GET /me` says the assistant doesn't know their name. It introduces itself and asks how to call them, and saves the answer once they give it. For someone it already knows, the stream is a single `final` with an empty text. Needs `conversationId`; `text` is ignored. |
|
|
50
|
+
| `resume` | `true` | no | The turn a `POST /confirm` answered `resume: true` for: the model answers on what the confirmed action handed back. Needs `conversationId`; `text` is ignored. With nothing to resume, the stream is a single `final` with an empty text. |
|
|
49
51
|
| `conversationId` | string | no | Opaque, client-owned id that continues one of your conversations: letters, digits, `-` and `_`, up to 128 characters (a UUID fits) once surrounding whitespace is trimmed, `400` otherwise. Sent again, however long after, it continues that conversation, rebuilt from the archive if Mercury had freed it (see `HTTP_SURFACE_RESUME_MAX_CHARS`). Omitted ⇒ a fresh one-off session that can't be continued. |
|
|
50
52
|
|
|
51
|
-
**Responses**: `200 text/event-stream` (the events below); `400` if `text` is missing, the body isn't JSON, or `conversationId` has other characters than the ones above.
|
|
53
|
+
**Responses**: `200 text/event-stream` (the events below); `400` if `text` is missing, an opening has no `conversationId`, the body isn't JSON, or `conversationId` has other characters than the ones above.
|
|
52
54
|
|
|
53
55
|
Reasoning and answer text arrive as **incremental deltas** — never one finished block — so a UI renders them live; treat the `final` event as the authoritative text. **To cancel** a turn (e.g. a generation that's diverging), close the connection: Mercury aborts the in-flight generation.
|
|
54
56
|
|
|
@@ -61,7 +63,7 @@ Reasoning and answer text arrive as **incremental deltas** — never one finishe
|
|
|
61
63
|
| `tool` | `{ label, detail, toolCallId, name }` | a tool call starts; `name` is the tool the model called, absent when Mercury is saving something to memory |
|
|
62
64
|
| `tool_finish` | `{ toolCallId, outcome }` | a tool call settles (`outcome`: `success` \| `failed` \| `pending`) |
|
|
63
65
|
| `text` | `{ chunk }` | an answer-text delta |
|
|
64
|
-
| `pending` | `{ command, token }` | a confirm-required action was staged; send
|
|
66
|
+
| `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; one, labelled `Conferma`, for a plain staging): the others die with the one sent |
|
|
65
67
|
| `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) |
|
|
66
68
|
| `final` | `{ text }` | the complete answer (also emitted for a token confirmation, with no model turn) |
|
|
67
69
|
| `error` | `{ message }` | the turn failed mid-stream |
|
|
@@ -85,7 +87,7 @@ A code for linking another of the caller's accounts to them, for the UI to show:
|
|
|
85
87
|
|
|
86
88
|
## `POST /confirm`
|
|
87
89
|
|
|
88
|
-
Explicit alternative to re-sending a token as `/turn` `text`. Body `{ token, conversationId }`; returns `{ ok: true, resolved: true, text }` when the token was a pending confirmation, `{ ok: true, resolved: false }` otherwise. `400` if `token` or `conversationId` is missing, or the id has other characters than `/turn` accepts. Never invokes the model.
|
|
90
|
+
Explicit alternative to re-sending a token as `/turn` `text`. Body `{ token, conversationId }`; returns `{ ok: true, resolved: true, text }` when the token was a pending confirmation, `{ ok: true, resolved: false }` otherwise. When the confirmed action hands its result back to the model, it returns `{ ok: true, resolved: true, resume: true }` instead: open `POST /turn { resume: true, conversationId }` to hear the model's answer. `400` if `token` or `conversationId` is missing, or the id has other characters than `/turn` accepts. Never invokes the model.
|
|
89
91
|
|
|
90
92
|
## Read-only introspection
|
|
91
93
|
|
|
@@ -97,6 +99,7 @@ All `GET`, all JSON, all reporting state already held in-process. They need an a
|
|
|
97
99
|
| `GET /conversations?limit=<n>` | `{ conversations: [{ conversationId, lastTimestamp, preview }] }` — your conversations, most-recently-active first |
|
|
98
100
|
| `GET /manifest` | `{ manifest: { coreApiVersion, plugins: [{ name, apiVersion, active, skills, hasBuild, customStatus }], activeClis, skills } }` |
|
|
99
101
|
| `GET /confirmations` | `{ pending: [{ sessionKey, summary, expiresAt }] }` — your pending confirmations; tokens are deliberately never included |
|
|
102
|
+
| `GET /me` | `{ name }` — how you asked the assistant to call you, `null` when you never said; not there on a core older than this channel |
|
|
100
103
|
| `GET /tool-log` | `{ entries: [...] }` — the tool calls of your recent turns |
|
|
101
104
|
| `GET /health` | `{ uptimeSeconds, memory, qdrantReachable, ollamaReachable }` |
|
|
102
105
|
| `GET /wiki/list` | `{ files: [...] }` — `curated/...` and `personal/...` paths |
|
package/dist/http-server.d.ts
CHANGED
|
@@ -60,6 +60,13 @@ export declare function openApiResponse(corsOrigin?: string): Response;
|
|
|
60
60
|
* one-on-one (`multiUser: false`). No `conversationId` means a fresh ephemeral
|
|
61
61
|
* session. Never throws: a refused caller is a 401, a bad body a 400, a
|
|
62
62
|
* mid-turn failure an `error` event on the stream.
|
|
63
|
+
*
|
|
64
|
+
* `{ opening: true, conversationId }`, with no `text`, asks the assistant to
|
|
65
|
+
* speak first in that conversation (right after someone signs in): the core
|
|
66
|
+
* decides whether it has anything to say, and a `final` with an empty text
|
|
67
|
+
* means it hasn't. `{ resume: true, conversationId }` runs the turn a
|
|
68
|
+
* `/confirm` answered `resume: true` for; a bare token whose confirmation
|
|
69
|
+
* resumes runs that turn on the same stream.
|
|
63
70
|
*/
|
|
64
71
|
export declare function handleTurnRequest(req: Request, deps: TurnRequestDeps): Promise<Response>;
|
|
65
72
|
export type ConfirmRequestDeps = {
|
|
@@ -78,7 +85,9 @@ export type ConfirmRequestDeps = {
|
|
|
78
85
|
* pending confirmation and its staged action was consumed and run; the `text`
|
|
79
86
|
* then reports whether that execution succeeded. `resolved: false` means the
|
|
80
87
|
* token was not a pending confirmation (unknown, expired, already used, or not
|
|
81
|
-
* even token-shaped).
|
|
88
|
+
* even token-shaped). `resume: true` (with no `text`) means the action handed
|
|
89
|
+
* its result back to the model: the client hears its answer by opening
|
|
90
|
+
* `/turn { resume: true, conversationId }`. Never touches the model.
|
|
82
91
|
*/
|
|
83
92
|
export declare function handleConfirmRequest(req: Request, deps: ConfirmRequestDeps): Promise<Response>;
|
|
84
93
|
export type LinkRequestDeps = {
|
package/http-server.ts
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
detectLoginRequired,
|
|
27
27
|
detectPendingConfirmation,
|
|
28
28
|
PENDING_CONFIRMATION_NOTE,
|
|
29
|
+
RESUME_AFTER_CONFIRM,
|
|
29
30
|
type HandleTurn,
|
|
30
31
|
type TurnSink,
|
|
31
32
|
type Authenticate,
|
|
@@ -147,24 +148,40 @@ export function openApiResponse(corsOrigin = "*"): Response {
|
|
|
147
148
|
* one-on-one (`multiUser: false`). No `conversationId` means a fresh ephemeral
|
|
148
149
|
* session. Never throws: a refused caller is a 401, a bad body a 400, a
|
|
149
150
|
* mid-turn failure an `error` event on the stream.
|
|
151
|
+
*
|
|
152
|
+
* `{ opening: true, conversationId }`, with no `text`, asks the assistant to
|
|
153
|
+
* speak first in that conversation (right after someone signs in): the core
|
|
154
|
+
* decides whether it has anything to say, and a `final` with an empty text
|
|
155
|
+
* means it hasn't. `{ resume: true, conversationId }` runs the turn a
|
|
156
|
+
* `/confirm` answered `resume: true` for; a bare token whose confirmation
|
|
157
|
+
* resumes runs that turn on the same stream.
|
|
150
158
|
*/
|
|
151
159
|
export async function handleTurnRequest(req: Request, deps: TurnRequestDeps): Promise<Response> {
|
|
152
160
|
const origin = deps.corsOrigin ?? "*";
|
|
153
161
|
const cors = corsHeaders(origin);
|
|
154
162
|
const principal = await caller(req, deps, origin);
|
|
155
163
|
if (principal instanceof Response) return principal;
|
|
156
|
-
let body: { text?: unknown; conversationId?: unknown };
|
|
164
|
+
let body: { text?: unknown; conversationId?: unknown; opening?: unknown; resume?: unknown };
|
|
157
165
|
try {
|
|
158
166
|
body = (await req.json()) as typeof body;
|
|
159
167
|
} catch {
|
|
160
168
|
return Response.json({ ok: false, error: "body must be JSON" }, { status: 400, headers: cors });
|
|
161
169
|
}
|
|
162
|
-
|
|
163
|
-
return Response.json({ ok: false, error: "missing text" }, { status: 400, headers: cors });
|
|
164
|
-
}
|
|
165
|
-
const text = body.text;
|
|
170
|
+
const opening = body.opening === true;
|
|
166
171
|
// A conversation the client names is one it reopens; an ephemeral one never comes back.
|
|
167
172
|
const named = typeof body.conversationId === "string" && body.conversationId.trim().length > 0;
|
|
173
|
+
// The turn a `/confirm` answered `resume: true` for.
|
|
174
|
+
const resume = body.resume === true;
|
|
175
|
+
if (opening && !named) {
|
|
176
|
+
return Response.json({ ok: false, error: "an opening needs a conversationId" }, { status: 400, headers: cors });
|
|
177
|
+
}
|
|
178
|
+
if (resume && !named) {
|
|
179
|
+
return Response.json({ ok: false, error: "a resumed turn needs a conversationId" }, { status: 400, headers: cors });
|
|
180
|
+
}
|
|
181
|
+
if (!opening && !resume && (typeof body.text !== "string" || body.text.trim().length === 0)) {
|
|
182
|
+
return Response.json({ ok: false, error: "missing text" }, { status: 400, headers: cors });
|
|
183
|
+
}
|
|
184
|
+
const text = opening || resume ? "" : (body.text as string);
|
|
168
185
|
const conversationId = named ? (body.conversationId as string).trim() : (deps.newSessionKey ?? (() => crypto.randomUUID()))();
|
|
169
186
|
if (!CONVERSATION_ID.test(conversationId)) {
|
|
170
187
|
return Response.json({ ok: false, error: "invalid conversationId" }, { status: 400, headers: cors });
|
|
@@ -198,12 +215,14 @@ export async function handleTurnRequest(req: Request, deps: TurnRequestDeps): Pr
|
|
|
198
215
|
|
|
199
216
|
// Same deterministic interception as every other channel — a
|
|
200
217
|
// previously-approved mutation must never depend on the model.
|
|
201
|
-
const confirmReply = await deps.confirm(text, sessionKey, principal);
|
|
202
|
-
if (confirmReply !== null) {
|
|
218
|
+
const confirmReply = opening || resume ? null : await deps.confirm(text, sessionKey, principal);
|
|
219
|
+
if (confirmReply !== null && confirmReply !== RESUME_AFTER_CONFIRM) {
|
|
203
220
|
send("final", { text: confirmReply });
|
|
204
221
|
close();
|
|
205
222
|
return;
|
|
206
223
|
}
|
|
224
|
+
// The confirmed action's result goes back to the model: the turn runs again, on this stream.
|
|
225
|
+
const resuming = resume || confirmReply === RESUME_AFTER_CONFIRM;
|
|
207
226
|
|
|
208
227
|
const sink: TurnSink = {
|
|
209
228
|
onToolStart: (label, detail, toolCallId, toolName) => send("tool", { label, detail, toolCallId, name: toolName }),
|
|
@@ -215,7 +234,7 @@ export async function handleTurnRequest(req: Request, deps: TurnRequestDeps): Pr
|
|
|
215
234
|
onReasoningEnd: (id, failed) => send("reasoning_end", { id, failed }),
|
|
216
235
|
onStep: (step) => {
|
|
217
236
|
const pending = detectPendingConfirmation(step);
|
|
218
|
-
if (pending) send("pending", { command: pending.summary, token: pending.token });
|
|
237
|
+
if (pending) send("pending", { command: pending.summary, token: pending.token, choices: pending.choices });
|
|
219
238
|
const login = detectLoginRequired(step);
|
|
220
239
|
if (login) send("login", { service: login.service, url: login.url });
|
|
221
240
|
},
|
|
@@ -229,13 +248,15 @@ export async function handleTurnRequest(req: Request, deps: TurnRequestDeps): Pr
|
|
|
229
248
|
{
|
|
230
249
|
channel: "http",
|
|
231
250
|
multiUser: false,
|
|
232
|
-
text,
|
|
251
|
+
text: resuming ? "" : text,
|
|
233
252
|
sessionKey,
|
|
234
253
|
principal,
|
|
235
254
|
// The caller's id comes from the auth provider, unchecked here.
|
|
236
255
|
logPrefix: `[http:${forLog(sessionKey)}] `,
|
|
237
256
|
abortSignal: abort.signal,
|
|
238
257
|
...(named ? { resume: deps.resumeMaxChars === undefined ? {} : { maxChars: deps.resumeMaxChars } } : {}),
|
|
258
|
+
...(opening ? { opening: true as const } : {}),
|
|
259
|
+
...(resuming ? { resumeAfterConfirm: true as const } : {}),
|
|
239
260
|
},
|
|
240
261
|
sink,
|
|
241
262
|
);
|
|
@@ -275,7 +296,9 @@ export type ConfirmRequestDeps = {
|
|
|
275
296
|
* pending confirmation and its staged action was consumed and run; the `text`
|
|
276
297
|
* then reports whether that execution succeeded. `resolved: false` means the
|
|
277
298
|
* token was not a pending confirmation (unknown, expired, already used, or not
|
|
278
|
-
* even token-shaped).
|
|
299
|
+
* even token-shaped). `resume: true` (with no `text`) means the action handed
|
|
300
|
+
* its result back to the model: the client hears its answer by opening
|
|
301
|
+
* `/turn { resume: true, conversationId }`. Never touches the model.
|
|
279
302
|
*/
|
|
280
303
|
export async function handleConfirmRequest(req: Request, deps: ConfirmRequestDeps): Promise<Response> {
|
|
281
304
|
const origin = deps.corsOrigin ?? "*";
|
|
@@ -305,6 +328,9 @@ export async function handleConfirmRequest(req: Request, deps: ConfirmRequestDep
|
|
|
305
328
|
return Response.json({ ok: true, resolved: true, text: `Confermato ed eseguito: ${JSON.stringify(outcome.data)}` }, { headers: cors });
|
|
306
329
|
case "failed":
|
|
307
330
|
return Response.json({ ok: true, resolved: true, text: `Confermato, ma l'esecuzione è fallita: ${outcome.error}` }, { headers: cors });
|
|
331
|
+
case "resume":
|
|
332
|
+
// The result went back to the model: the client opens `/turn { resume: true }` to hear its answer.
|
|
333
|
+
return Response.json({ ok: true, resolved: true, resume: true }, { headers: cors });
|
|
308
334
|
}
|
|
309
335
|
}
|
|
310
336
|
|
|
@@ -449,6 +475,16 @@ export function readRoutes(
|
|
|
449
475
|
});
|
|
450
476
|
}),
|
|
451
477
|
"/tool-log": route(async (_req, principal) => json({ ok: true, entries: await reads.toolLog(principal) })),
|
|
478
|
+
// Who the caller is to the core, on a core that can say.
|
|
479
|
+
...(reads.me === undefined
|
|
480
|
+
? {}
|
|
481
|
+
: {
|
|
482
|
+
"/me": route(async (_req, principal) => {
|
|
483
|
+
// Null when the core no longer admits the caller: still a name, null.
|
|
484
|
+
const me = (await reads.me!(principal)) as { name: string | null } | null;
|
|
485
|
+
return json({ ok: true, name: me?.name ?? null });
|
|
486
|
+
}),
|
|
487
|
+
}),
|
|
452
488
|
"/health": route(async () => json({ ok: true, ...(await reads.health() as object) })),
|
|
453
489
|
"/wiki/list": route(async (_req, principal) => json({ ok: true, files: await reads.wikiList(principal) })),
|
|
454
490
|
"/wiki/read": route(async (req, principal) => {
|
package/openapi.yaml
CHANGED
|
@@ -71,7 +71,16 @@ info:
|
|
|
71
71
|
An irreversible action is never executed on the model's say-so: the turn
|
|
72
72
|
emits a `pending` event carrying a one-time `token`. The client confirms by
|
|
73
73
|
sending that token back — either as the `text` of a follow-up `POST /turn`,
|
|
74
|
-
or via `POST /confirm`.
|
|
74
|
+
or via `POST /confirm`. An action can offer several `choices` (e.g. "only
|
|
75
|
+
this time" / "always"), each with its own token: the caller sends back one,
|
|
76
|
+
and the others die with it.
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
Some actions hand their result back to the model instead of to the caller
|
|
80
|
+
(a page read after the caller allowed it, for example). Confirming one by
|
|
81
|
+
`POST /turn` streams the model's answer on that same stream; `POST /confirm`
|
|
82
|
+
answers `resume: true`, and the client then opens
|
|
83
|
+
`POST /turn { resume: true, conversationId }` to hear it.
|
|
75
84
|
security:
|
|
76
85
|
- bearerAuth: []
|
|
77
86
|
servers:
|
|
@@ -85,7 +94,14 @@ paths:
|
|
|
85
94
|
Runs one model turn and streams the result as `text/event-stream`. If
|
|
86
95
|
`text` is a pending confirmation token it is resolved deterministically
|
|
87
96
|
without ever consulting the model. Close the connection to cancel an
|
|
88
|
-
in-flight turn.
|
|
97
|
+
in-flight turn. When the confirmation hands its result back to the
|
|
98
|
+
model, the model's answer to it streams instead. With `resume: true`
|
|
99
|
+
and no `text`, the turn is the one a `/confirm` answered `resume: true`
|
|
100
|
+
for. With `opening: true` and no `text`, the assistant
|
|
101
|
+
speaks first in the conversation named (right after someone signs
|
|
102
|
+
in): it does only for someone it doesn't know the name of, asking how
|
|
103
|
+
to call them, and otherwise the stream carries a single `final` with
|
|
104
|
+
an empty text.
|
|
89
105
|
requestBody:
|
|
90
106
|
required: true
|
|
91
107
|
content:
|
|
@@ -104,7 +120,8 @@ paths:
|
|
|
104
120
|
An SSE stream. Each event is one of the types in `TurnEvent`:
|
|
105
121
|
`reasoning`/`reasoning_end`, `text` (incremental deltas), `tool`/
|
|
106
122
|
`tool_finish` (status of a tool call), `pending` (a staged
|
|
107
|
-
confirm-required action, with its command
|
|
123
|
+
confirm-required action, with its command, its token and the
|
|
124
|
+
choices it offers), `login` (a
|
|
108
125
|
service the caller has to log in to first, with the link to open),
|
|
109
126
|
`final` (the
|
|
110
127
|
authoritative complete answer), and `error`.
|
|
@@ -113,7 +130,7 @@ paths:
|
|
|
113
130
|
schema:
|
|
114
131
|
$ref: "#/components/schemas/TurnEvent"
|
|
115
132
|
"400":
|
|
116
|
-
description: Missing/invalid body, or a conversationId with characters outside the allowed ones.
|
|
133
|
+
description: Missing/invalid body, an opening or a resumed turn without a conversationId, or a conversationId with characters outside the allowed ones.
|
|
117
134
|
content:
|
|
118
135
|
application/json:
|
|
119
136
|
schema:
|
|
@@ -142,7 +159,9 @@ paths:
|
|
|
142
159
|
description: >
|
|
143
160
|
`resolved: true` (with the reply `text`) when the token was a pending
|
|
144
161
|
confirmation, `resolved: false` when it was not (unknown, expired, or
|
|
145
|
-
already used).
|
|
162
|
+
already used). `resolved: true` with `resume: true` and no `text`
|
|
163
|
+
when the action handed its result back to the model: the answer
|
|
164
|
+
comes from `POST /turn { resume: true, conversationId }`.
|
|
146
165
|
content:
|
|
147
166
|
application/json:
|
|
148
167
|
schema:
|
|
@@ -305,6 +324,32 @@ paths:
|
|
|
305
324
|
application/json:
|
|
306
325
|
schema:
|
|
307
326
|
type: object
|
|
327
|
+
/me:
|
|
328
|
+
get:
|
|
329
|
+
summary: Who the caller is to the assistant
|
|
330
|
+
description: >
|
|
331
|
+
How the caller asked to be called, `null` when they never said: a UI
|
|
332
|
+
asks for an opening turn after a sign-in only then. Not there on an
|
|
333
|
+
older core, which can't say.
|
|
334
|
+
responses:
|
|
335
|
+
"401":
|
|
336
|
+
$ref: "#/components/responses/Unauthorized"
|
|
337
|
+
"403":
|
|
338
|
+
$ref: "#/components/responses/NotAdmitted"
|
|
339
|
+
"503":
|
|
340
|
+
$ref: "#/components/responses/NotAdmitted"
|
|
341
|
+
"200":
|
|
342
|
+
description: The caller's name, or null.
|
|
343
|
+
content:
|
|
344
|
+
application/json:
|
|
345
|
+
schema:
|
|
346
|
+
type: object
|
|
347
|
+
required: [ok, name]
|
|
348
|
+
properties:
|
|
349
|
+
ok:
|
|
350
|
+
type: boolean
|
|
351
|
+
name:
|
|
352
|
+
type: [string, "null"]
|
|
308
353
|
/tool-log:
|
|
309
354
|
get:
|
|
310
355
|
summary: The tool calls made in the caller's recent turns
|
|
@@ -519,11 +564,18 @@ components:
|
|
|
519
564
|
schemas:
|
|
520
565
|
TurnRequest:
|
|
521
566
|
type: object
|
|
522
|
-
required: [text]
|
|
523
567
|
properties:
|
|
524
568
|
text:
|
|
525
569
|
type: string
|
|
526
|
-
description: The user's message, or a bare confirmation token.
|
|
570
|
+
description: The user's message, or a bare confirmation token. Required, unless `opening` or `resume` is true.
|
|
571
|
+
opening:
|
|
572
|
+
type: boolean
|
|
573
|
+
enum: [true]
|
|
574
|
+
description: The assistant speaks first in `conversationId`, which is then required; `text` is ignored.
|
|
575
|
+
resume:
|
|
576
|
+
type: boolean
|
|
577
|
+
enum: [true]
|
|
578
|
+
description: The turn a `/confirm` answered `resume: true` for, in `conversationId`, which is then required; `text` is ignored.
|
|
527
579
|
conversationId:
|
|
528
580
|
type: string
|
|
529
581
|
pattern: "^[A-Za-z0-9_-]{1,128}$"
|
|
@@ -561,7 +613,18 @@ components:
|
|
|
561
613
|
description: On `pending` — the staged action's summary.
|
|
562
614
|
token:
|
|
563
615
|
type: string
|
|
564
|
-
description: On `pending` — the one-time confirmation token.
|
|
616
|
+
description: On `pending` — the one-time confirmation token (the first choice's).
|
|
617
|
+
choices:
|
|
618
|
+
type: array
|
|
619
|
+
description: On `pending` — every way to answer, in order; a plain staging has one, labelled `Conferma`.
|
|
620
|
+
items:
|
|
621
|
+
type: object
|
|
622
|
+
required: [token, label]
|
|
623
|
+
properties:
|
|
624
|
+
token:
|
|
625
|
+
type: string
|
|
626
|
+
label:
|
|
627
|
+
type: string
|
|
565
628
|
service:
|
|
566
629
|
type: string
|
|
567
630
|
description: On `login` — the service the caller has to log in to.
|
|
@@ -593,7 +656,11 @@ components:
|
|
|
593
656
|
type: boolean
|
|
594
657
|
text:
|
|
595
658
|
type: string
|
|
596
|
-
description: The confirmation reply, present when `resolved` is true.
|
|
659
|
+
description: The confirmation reply, present when `resolved` is true and `resume` isn't.
|
|
660
|
+
resume:
|
|
661
|
+
type: boolean
|
|
662
|
+
enum: [true]
|
|
663
|
+
description: The action handed its result back to the model; its answer comes from `POST /turn { resume: true, conversationId }`.
|
|
597
664
|
Message:
|
|
598
665
|
type: object
|
|
599
666
|
required: [role, content, timestamp]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mercury-fw/channel-http",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
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.
|
|
21
|
+
"@mercury-fw/channel-types": ">=0.51.0 <1.0.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@mercury-fw/channel-types": "0.
|
|
25
|
-
"@mercury-fw/plugin-types": "0.
|
|
24
|
+
"@mercury-fw/channel-types": "0.51.0",
|
|
25
|
+
"@mercury-fw/plugin-types": "0.51.0",
|
|
26
26
|
"@mercury-fw/typescript-config": "*",
|
|
27
27
|
"@types/bun": "^1.4.2",
|
|
28
28
|
"typescript": "^6.0.3"
|