@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 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
@@ -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>;
@@ -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(req: Request, deps: { complete: CompleteLoginFn }): Promise<Response> {
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 Mercury again for a new link.`, 400);
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("The login link came back without a code or a state. Ask Mercury again for a new link.", 400);
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(complete: CompleteLoginFn): Record<string, { GET: (req: Request) => Promise<Response> }> {
375
- return { "/login/callback": { GET: (req) => handleLoginCallback(req, { complete }) } };
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",
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.47.0",
25
- "@mercury-fw/plugin-types": "0.47.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"