@mercury-fw/channel-http 0.8.3 → 0.8.4
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 +11 -0
- package/dist/http-provider.d.ts +2 -0
- package/dist/http-server.d.ts +5 -1
- package/http-provider.ts +3 -0
- package/http-server.ts +21 -7
- package/index.ts +1 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @mercury-fw/channel-http
|
|
2
2
|
|
|
3
|
+
## 0.8.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 62bb3a3: - `persona.name` is the assistant's name, Mercury when left out. A name that's blank, longer than 40 characters or on more than one line stops the app at startup.
|
|
8
|
+
- Every text the model reads refers to the name as `{{assistant}}`, and the core puts the persona's name there: the persona's identity and tone, the system prompt, plugin fragments, skills and tool descriptions. The model no longer takes "Mercury" for its own name when the app calls its assistant something else.
|
|
9
|
+
- Where the one acting is the system around the model, the texts say "the system" or "this instance" instead of Mercury: the wiki tools, the cli-engine's errors, the jira skill and its issue lists.
|
|
10
|
+
- Plugins get `assistantName` in their `build()` context, and channels in their runtime context, for texts they build while running. The login messages, the linking reply and the HTTP login page name the assistant that way.
|
|
11
|
+
- The tools a person runs as the assistant itself are `<tool>AsSelf`, previously `<tool>AsMercury`. The `mercury.act-as-self` roles are unchanged.
|
|
12
|
+
- `mfw create` writes the assistant's name as `persona.name`, with `persona/identity.md` and `persona/tone.md` referring to it. An existing app keeps working as it is: to rename its assistant everywhere, add `name` to its persona and write `{{assistant}}` in its persona files.
|
|
13
|
+
|
|
3
14
|
## 0.8.3
|
|
4
15
|
|
|
5
16
|
### Patch Changes
|
package/dist/http-provider.d.ts
CHANGED
|
@@ -36,6 +36,8 @@ export type HttpProviderDeps = {
|
|
|
36
36
|
linking?: ChannelLinking;
|
|
37
37
|
/** The surface's budget for a reopened conversation (`HTTP_SURFACE_RESUME_MAX_CHARS`). */
|
|
38
38
|
resumeMaxChars?: number;
|
|
39
|
+
/** What the pages people read call the assistant. */
|
|
40
|
+
assistantName?: string;
|
|
39
41
|
};
|
|
40
42
|
export declare function createHttpProvider(deps: HttpProviderDeps): Provider & {
|
|
41
43
|
stop(): Promise<void>;
|
package/dist/http-server.d.ts
CHANGED
|
@@ -102,10 +102,12 @@ export type CompleteLoginFn = (state: string, code: string) => Promise<LoginOutc
|
|
|
102
102
|
* in, with `code` and `state` (or `error`, when they refused). Public: the
|
|
103
103
|
* person's browser carries no token here, and the single-use `state` the core
|
|
104
104
|
* issued for them is what ties the request to their login. Answers with a
|
|
105
|
-
* plain page telling them how it went
|
|
105
|
+
* plain page telling them how it went, naming the assistant as the app does
|
|
106
|
+
* (`Mercury` from an older core that doesn't say).
|
|
106
107
|
*/
|
|
107
108
|
export declare function handleLoginCallback(req: Request, deps: {
|
|
108
109
|
complete: CompleteLoginFn;
|
|
110
|
+
assistantName?: string;
|
|
109
111
|
}): Promise<Response>;
|
|
110
112
|
/** A single read route: its `GET` handler plus the shared `OPTIONS` preflight. */
|
|
111
113
|
type ReadRoute = {
|
|
@@ -133,6 +135,8 @@ export type HttpServerDeps = TurnRequestDeps & {
|
|
|
133
135
|
completeLogin?: CompleteLoginFn;
|
|
134
136
|
/** Linking another account to the caller; `/link` is mounted only with it. */
|
|
135
137
|
linking?: ChannelLinking;
|
|
138
|
+
/** What the pages people read call the assistant. */
|
|
139
|
+
assistantName?: string;
|
|
136
140
|
};
|
|
137
141
|
/** Starts the HTTP surface: `POST /turn` (4a) plus the read-only routes (4b)
|
|
138
142
|
* when `reads` is supplied. */
|
package/http-provider.ts
CHANGED
|
@@ -33,6 +33,8 @@ export type HttpProviderDeps = {
|
|
|
33
33
|
linking?: ChannelLinking;
|
|
34
34
|
/** The surface's budget for a reopened conversation (`HTTP_SURFACE_RESUME_MAX_CHARS`). */
|
|
35
35
|
resumeMaxChars?: number;
|
|
36
|
+
/** What the pages people read call the assistant. */
|
|
37
|
+
assistantName?: string;
|
|
36
38
|
};
|
|
37
39
|
|
|
38
40
|
export function createHttpProvider(deps: HttpProviderDeps): Provider & { stop(): Promise<void> } {
|
|
@@ -51,6 +53,7 @@ export function createHttpProvider(deps: HttpProviderDeps): Provider & { stop():
|
|
|
51
53
|
completeLogin: deps.logins?.complete,
|
|
52
54
|
...(deps.linking === undefined ? {} : { linking: deps.linking }),
|
|
53
55
|
...(deps.resumeMaxChars === undefined ? {} : { resumeMaxChars: deps.resumeMaxChars }),
|
|
56
|
+
...(deps.assistantName === undefined ? {} : { assistantName: deps.assistantName }),
|
|
54
57
|
});
|
|
55
58
|
deps.logins?.accept(deps.logins.callbackUrl);
|
|
56
59
|
},
|
package/http-server.ts
CHANGED
|
@@ -352,18 +352,23 @@ function loginPage(text: string, status: number): Response {
|
|
|
352
352
|
* in, with `code` and `state` (or `error`, when they refused). Public: the
|
|
353
353
|
* person's browser carries no token here, and the single-use `state` the core
|
|
354
354
|
* issued for them is what ties the request to their login. Answers with a
|
|
355
|
-
* plain page telling them how it went
|
|
355
|
+
* plain page telling them how it went, naming the assistant as the app does
|
|
356
|
+
* (`Mercury` from an older core that doesn't say).
|
|
356
357
|
*/
|
|
357
|
-
export async function handleLoginCallback(
|
|
358
|
+
export async function handleLoginCallback(
|
|
359
|
+
req: Request,
|
|
360
|
+
deps: { complete: CompleteLoginFn; assistantName?: string },
|
|
361
|
+
): Promise<Response> {
|
|
362
|
+
const assistant = deps.assistantName ?? "Mercury";
|
|
358
363
|
const params = new URL(req.url).searchParams;
|
|
359
364
|
const error = params.get("error");
|
|
360
365
|
if (error !== null) {
|
|
361
366
|
const reason = error.replace(/[^A-Za-z0-9_.-]/g, "").slice(0, 64);
|
|
362
|
-
return loginPage(`The login didn't happen (${reason}). Ask
|
|
367
|
+
return loginPage(`The login didn't happen (${reason}). Ask ${assistant} again for a new link.`, 400);
|
|
363
368
|
}
|
|
364
369
|
const code = params.get("code");
|
|
365
370
|
const state = params.get("state");
|
|
366
|
-
if (!code || !state) return loginPage(
|
|
371
|
+
if (!code || !state) return loginPage(`The login link came back without a code or a state. Ask ${assistant} again for a new link.`, 400);
|
|
367
372
|
const outcome = await deps.complete(state, code);
|
|
368
373
|
return outcome.ok
|
|
369
374
|
? loginPage(`You're logged in to ${outcome.service}. Go back to the conversation and ask again.`, 200)
|
|
@@ -371,8 +376,15 @@ export async function handleLoginCallback(req: Request, deps: { complete: Comple
|
|
|
371
376
|
}
|
|
372
377
|
|
|
373
378
|
/** The login callback route, mounted when the server can complete logins. */
|
|
374
|
-
function loginRoutes(
|
|
375
|
-
|
|
379
|
+
function loginRoutes(
|
|
380
|
+
complete: CompleteLoginFn,
|
|
381
|
+
assistantName: string | undefined,
|
|
382
|
+
): Record<string, { GET: (req: Request) => Promise<Response> }> {
|
|
383
|
+
return {
|
|
384
|
+
"/login/callback": {
|
|
385
|
+
GET: (req) => handleLoginCallback(req, { complete, ...(assistantName === undefined ? {} : { assistantName }) }),
|
|
386
|
+
},
|
|
387
|
+
};
|
|
376
388
|
}
|
|
377
389
|
|
|
378
390
|
/** A single read route: its `GET` handler plus the shared `OPTIONS` preflight. */
|
|
@@ -471,6 +483,8 @@ export type HttpServerDeps = TurnRequestDeps & {
|
|
|
471
483
|
completeLogin?: CompleteLoginFn;
|
|
472
484
|
/** Linking another account to the caller; `/link` is mounted only with it. */
|
|
473
485
|
linking?: ChannelLinking;
|
|
486
|
+
/** What the pages people read call the assistant. */
|
|
487
|
+
assistantName?: string;
|
|
474
488
|
};
|
|
475
489
|
|
|
476
490
|
/** Starts the HTTP surface: `POST /turn` (4a) plus the read-only routes (4b)
|
|
@@ -502,7 +516,7 @@ export function startHttpServer(deps: HttpServerDeps): ReturnType<typeof Bun.ser
|
|
|
502
516
|
},
|
|
503
517
|
"/openapi.yaml": { GET: () => openApiResponse(origin), OPTIONS: () => preflight(origin) },
|
|
504
518
|
...(deps.reads ? readRoutes(deps.reads, deps.authenticate, origin, deps.admit) : {}),
|
|
505
|
-
...(deps.completeLogin ? loginRoutes(deps.completeLogin) : {}),
|
|
519
|
+
...(deps.completeLogin ? loginRoutes(deps.completeLogin, deps.assistantName) : {}),
|
|
506
520
|
...(deps.linking ? linkRoutes({ ...deps, start: deps.linking.start, corsOrigin: origin }) : {}),
|
|
507
521
|
},
|
|
508
522
|
error: (err) =>
|
package/index.ts
CHANGED
|
@@ -46,6 +46,7 @@ export const httpChannel: ChannelPlugin = {
|
|
|
46
46
|
admit: ctx.admit,
|
|
47
47
|
...(ctx.linking === undefined ? {} : { linking: ctx.linking }),
|
|
48
48
|
...(resumeMaxChars === undefined ? {} : { resumeMaxChars }),
|
|
49
|
+
...(ctx.assistantName === undefined ? {} : { assistantName: ctx.assistantName }),
|
|
49
50
|
...(logins ? { logins: { callbackUrl: `${publicUrl}/login/callback`, accept: logins.accept, complete: logins.complete } } : {}),
|
|
50
51
|
});
|
|
51
52
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mercury-fw/channel-http",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
"@mercury-fw/channel-types": ">=0.45.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.48.0",
|
|
25
|
+
"@mercury-fw/plugin-types": "0.48.0",
|
|
26
26
|
"@mercury-fw/typescript-config": "*",
|
|
27
27
|
"@types/bun": "^1.4.2",
|
|
28
28
|
"typescript": "^6.0.3"
|