@m8t-stack/cli 0.2.72 → 0.2.74

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/dist/cli.js CHANGED
@@ -81,6 +81,17 @@ var init_reasons = __esm({
81
81
  }
82
82
  });
83
83
 
84
+ // ../../packages/api-contract/dist/esm/delegated-identity.js
85
+ var SERVICE_APP_ROLE, END_USER_KEY_MAX_LENGTH, END_USER_KEY_PATTERN;
86
+ var init_delegated_identity = __esm({
87
+ "../../packages/api-contract/dist/esm/delegated-identity.js"() {
88
+ "use strict";
89
+ SERVICE_APP_ROLE = "Agents.Invoke";
90
+ END_USER_KEY_MAX_LENGTH = 200;
91
+ END_USER_KEY_PATTERN = new RegExp(`^[A-Za-z0-9._-]{1,${String(END_USER_KEY_MAX_LENGTH)}}$`);
92
+ }
93
+ });
94
+
84
95
  // ../../packages/api-contract/dist/esm/team.js
85
96
  var init_team = __esm({
86
97
  "../../packages/api-contract/dist/esm/team.js"() {
@@ -224,6 +235,7 @@ var init_esm = __esm({
224
235
  init_response();
225
236
  init_errors2();
226
237
  init_reasons();
238
+ init_delegated_identity();
227
239
  init_team();
228
240
  init_me();
229
241
  init_binding();
@@ -1370,7 +1382,7 @@ var init_enable_hosted_brain = __esm({
1370
1382
  import { Builtins, Cli } from "clipanion";
1371
1383
 
1372
1384
  // src/lib/package-version.ts
1373
- var CLI_VERSION = "0.2.72";
1385
+ var CLI_VERSION = "0.2.74";
1374
1386
 
1375
1387
  // src/lib/render-error.ts
1376
1388
  init_errors();
@@ -15663,10 +15675,16 @@ import * as fs9 from "fs";
15663
15675
  import * as path9 from "path";
15664
15676
  var SEED_MANIFEST_PATH = ".m8t/seed-manifest.json";
15665
15677
  var SEED_PATHS = ["skills", "references", "targets"];
15678
+ function isUpstream(v) {
15679
+ if (v === void 0) return true;
15680
+ if (!v || typeof v !== "object") return false;
15681
+ const u = v;
15682
+ return typeof u.repo === "string" && u.repo.length > 0 && typeof u.ref === "string" && u.ref.length > 0;
15683
+ }
15666
15684
  function isLineage(v) {
15667
15685
  if (!v || typeof v !== "object") return false;
15668
15686
  const l = v;
15669
- return typeof l.name === "string" && typeof l.refreshedToCommit === "string" && typeof l.refreshedToVersion === "string" && Array.isArray(l.ownedPaths) && l.ownedPaths.every((p) => typeof p === "string");
15687
+ return typeof l.name === "string" && typeof l.refreshedToCommit === "string" && typeof l.refreshedToVersion === "string" && Array.isArray(l.ownedPaths) && l.ownedPaths.every((p) => typeof p === "string") && isUpstream(l.upstream);
15670
15688
  }
15671
15689
  function parseSeedManifest(text) {
15672
15690
  if (!text?.trim()) return null;
@@ -15684,6 +15702,11 @@ function parseSeedManifest(text) {
15684
15702
  function buildSeedManifest(seeds) {
15685
15703
  return { schemaVersion: 1, seeds };
15686
15704
  }
15705
+ function carryUpstream(prior, lineage) {
15706
+ if (lineage.upstream) return lineage;
15707
+ const before = prior?.seeds.find((s) => s.name === lineage.name)?.upstream;
15708
+ return before ? { ...lineage, upstream: before } : lineage;
15709
+ }
15687
15710
  function upsertLineage(manifest, lineage) {
15688
15711
  const prior = manifest?.seeds ?? [];
15689
15712
  const others = prior.filter((s) => s.name !== lineage.name);
@@ -15960,6 +15983,15 @@ async function syncAgentContent(args) {
15960
15983
  await hydrateAgentsInto(args.root, pin.agents, args.deps);
15961
15984
  return Object.values(pin.agents).map((a) => ({ persona: a.persona, repo: a.repo, ref: a.ref }));
15962
15985
  }
15986
+ function upstreamForSeed(root, seedName) {
15987
+ try {
15988
+ const pin = parseReleasePin(fs12.readFileSync(path12.join(root, PIN_REL_PATH), "utf8"), PIN_REL_PATH);
15989
+ const agent = Object.values(pin.agents).find((a) => a.persona === seedName);
15990
+ return agent ? { repo: agent.repo, ref: agent.ref } : void 0;
15991
+ } catch {
15992
+ return void 0;
15993
+ }
15994
+ }
15963
15995
  function agentContentHint(root, persona) {
15964
15996
  try {
15965
15997
  const pin = parseReleasePin(fs12.readFileSync(path12.join(root, PIN_REL_PATH), "utf8"), PIN_REL_PATH);
@@ -16034,7 +16066,8 @@ function writeSeedMarker(args) {
16034
16066
  name: args.seedName,
16035
16067
  refreshedToCommit: args.refreshedToCommit,
16036
16068
  refreshedToVersion: args.version,
16037
- ownedPaths: deriveOwnedPaths(args.seedDir)
16069
+ ownedPaths: deriveOwnedPaths(args.seedDir),
16070
+ ...args.upstream ? { upstream: args.upstream } : {}
16038
16071
  }]);
16039
16072
  const dest = path13.join(args.destDir, SEED_MANIFEST_PATH);
16040
16073
  fs13.mkdirSync(path13.dirname(dest), { recursive: true });
@@ -16658,7 +16691,15 @@ var BrainCreateCommand = class extends M8tCommand {
16658
16691
  materializeBrainTree({ templateSrc, destDir: tmpDir, seedDir });
16659
16692
  if (seedName && seedDir) {
16660
16693
  const headSha = resolveScaffoldCommit(repoRoot, env);
16661
- writeSeedMarker({ destDir: tmpDir, seedName, seedDir, refreshedToCommit: headSha, version: "(scaffold)" });
16694
+ const upstream = upstreamForSeed(repoRoot, seedName);
16695
+ writeSeedMarker({
16696
+ destDir: tmpDir,
16697
+ seedName,
16698
+ seedDir,
16699
+ refreshedToCommit: headSha,
16700
+ version: "(scaffold)",
16701
+ ...upstream ? { upstream } : {}
16702
+ });
16662
16703
  }
16663
16704
  this.context.stdout.write(
16664
16705
  seedName ? `${colors.dim("\u2192")} copied brain-template/ + overlaid seed ${colors.field(seedName)} to ${tmpDir}
@@ -21534,14 +21575,15 @@ async function refreshBrainRepo(args) {
21534
21575
  const ownedNow = new Set(args.trees.ownedAtTheirs);
21535
21576
  assertNoDanglingIndexRefs(finalPaths, (p) => ownedNow.has(p), indexBodies);
21536
21577
  const newOwned = deriveOwnedPaths(args.trees.theirsDir);
21578
+ const priorManifest = args.priorManifest ?? (args.lineage ? { schemaVersion: 1, seeds: [args.lineage] } : null);
21537
21579
  const nextManifest = upsertLineage(
21538
- args.priorManifest ?? (args.lineage ? { schemaVersion: 1, seeds: [args.lineage] } : null),
21539
- {
21580
+ priorManifest,
21581
+ carryUpstream(priorManifest, {
21540
21582
  name: args.seedName,
21541
21583
  refreshedToCommit: args.targetCommit ?? "",
21542
21584
  refreshedToVersion: args.version,
21543
21585
  ownedPaths: newOwned
21544
- }
21586
+ })
21545
21587
  );
21546
21588
  files.push({ path: SEED_MANIFEST_PATH, content: serializeSeedManifest(nextManifest) });
21547
21589
  for (const sb of args.supersedeBranches ?? []) {
@@ -23303,6 +23345,7 @@ var PlatformEnableAutoUpdateCommand = class extends M8tCommand {
23303
23345
  import { Command as Command42, Option as Option39 } from "clipanion";
23304
23346
 
23305
23347
  // src/lib/app-reg.ts
23348
+ init_esm();
23306
23349
  init_errors();
23307
23350
  var APP_NAME = "m8t-webapp";
23308
23351
  var AZURE_CLI_FIRST_PARTY_APP_ID = "04b07795-8ddb-461a-bbee-02f9e1bf7b46";
@@ -23403,6 +23446,52 @@ async function ensureExposeAnApi(appId, appObjectId) {
23403
23446
  ]);
23404
23447
  }
23405
23448
  }
23449
+ async function ensureServiceAppRole(appId, appObjectId) {
23450
+ const existingRoles = await azJson([
23451
+ "ad",
23452
+ "app",
23453
+ "show",
23454
+ "--id",
23455
+ appId,
23456
+ "--query",
23457
+ "appRoles",
23458
+ "--output",
23459
+ "json"
23460
+ ]);
23461
+ if (!Array.isArray(existingRoles)) {
23462
+ throw new LocalCliError({
23463
+ code: "APP_REG_ROLES_UNREADABLE",
23464
+ message: `Could not read the existing app roles on app registration ${appId}.`,
23465
+ hint: "Re-run once you can read the app registration; writing the role now would risk replacing roles we cannot see."
23466
+ });
23467
+ }
23468
+ const already = existingRoles.find((r) => r.value === SERVICE_APP_ROLE);
23469
+ if (already && already.isEnabled !== false) return;
23470
+ const appRoles = already ? existingRoles.map((r) => r.value === SERVICE_APP_ROLE ? { ...r, isEnabled: true } : r) : [
23471
+ ...existingRoles,
23472
+ {
23473
+ id: globalThis.crypto.randomUUID(),
23474
+ displayName: "Invoke agents",
23475
+ description: "Allows a service principal to call the gateway agent API.",
23476
+ value: SERVICE_APP_ROLE,
23477
+ allowedMemberTypes: ["Application"],
23478
+ isEnabled: true
23479
+ }
23480
+ ];
23481
+ await runAz([
23482
+ "rest",
23483
+ "--method",
23484
+ "PATCH",
23485
+ // The OBJECT id, not the app id: Graph's /applications/{id} addresses the
23486
+ // object id, and an appId here is a 404.
23487
+ "--url",
23488
+ `https://graph.microsoft.com/v1.0/applications/${appObjectId}`,
23489
+ "--headers",
23490
+ "Content-Type=application/json",
23491
+ "--body",
23492
+ JSON.stringify({ appRoles })
23493
+ ]);
23494
+ }
23406
23495
  async function ensureAppReg(opts) {
23407
23496
  if (opts.clientId) {
23408
23497
  return { tenantId: opts.tenantId, clientId: opts.clientId, appObjectId: null };
@@ -23422,6 +23511,7 @@ async function ensureAppReg(opts) {
23422
23511
  });
23423
23512
  }
23424
23513
  await ensureExposeAnApi(app.appId, objId);
23514
+ await ensureServiceAppRole(app.appId, objId);
23425
23515
  return { tenantId: opts.tenantId, clientId: app.appId, appObjectId: objId };
23426
23516
  }
23427
23517
  const me = await azJson(
@@ -23533,6 +23623,7 @@ async function ensureAppReg(opts) {
23533
23623
  })
23534
23624
  ]);
23535
23625
  await ensureExposeAnApi(created.appId, created.id);
23626
+ await ensureServiceAppRole(created.appId, created.id);
23536
23627
  return { tenantId: opts.tenantId, clientId: created.appId, appObjectId: created.id };
23537
23628
  }
23538
23629
  async function ensureGatewayRedirectUri(gatewayClientId, fqdn) {
@@ -29925,7 +30016,7 @@ ${colors.error("\u2717")} The GitHub App on disk is installed on ${colors.field(
29925
30016
  // src/commands/bootstrap/launch.ts
29926
30017
  var DEFAULT_RG = "rg-m8t-stack";
29927
30018
  var DEFAULT_INSTALLER = "ghcr.io/m8t-labs/m8t-installer";
29928
- var DEFAULT_INSTALLER_TAG = "v0.1.58";
30019
+ var DEFAULT_INSTALLER_TAG = "v0.1.59";
29929
30020
  var ACI_NAME = "m8t-installer";
29930
30021
  var MI_NAME = "m8t-installer-mi";
29931
30022
  var BootstrapLaunchCommand = class extends M8tCommand {
@@ -30892,19 +30983,22 @@ async function resolveSeedContext(opts) {
30892
30983
  if (!appCreds) return null;
30893
30984
  let endpoint = opts.endpointOverride;
30894
30985
  let subscriptionId = opts.subscriptionId;
30895
- if (!endpoint) {
30986
+ let recorded = opts.brainsOverride;
30987
+ if (!endpoint || !opts.brainOverride && recorded === void 0) {
30896
30988
  const state = await readBootstrapState();
30897
30989
  if (!state) {
30898
30990
  throw new LocalCliError({ code: "BOOTSTRAP_NO_STATE", message: "No bootstrap state found.", hint: "Run 'm8t bootstrap launch' first, or pass --endpoint." });
30899
30991
  }
30900
30992
  subscriptionId ??= state.subscriptionId;
30901
30993
  const doc = await readStatusBlob({ saName: state.statusSaName, resourceGroup: state.resourceGroup, subscriptionId: state.subscriptionId });
30902
- endpoint = doc.result?.foundryEndpoint;
30994
+ endpoint ??= doc.result?.foundryEndpoint;
30995
+ recorded ??= doc.result?.brains;
30903
30996
  if (!endpoint) {
30904
30997
  throw new LocalCliError({ code: "SEED_NO_ENDPOINT", message: "Could not resolve the Foundry endpoint from the install status.", hint: "Pass --endpoint <foundryEndpoint>." });
30905
30998
  }
30906
30999
  }
30907
- const brainRepos = opts.brainOverride ? [opts.brainOverride] : [`${appCreds.org}/stacey-brain`, `${appCreds.org}/ezra-brain`];
31000
+ const brainRepos = opts.brainOverride ? [opts.brainOverride] : recorded ?? [];
31001
+ if (brainRepos.length === 0) return null;
30908
31002
  return { endpoint, brainRepos, appCreds, subscriptionId };
30909
31003
  }
30910
31004
  var MEMORY_INDEX_PATH = "memory/MEMORY.md";
@@ -31051,7 +31145,12 @@ function spawnDetachedSeedWatch() {
31051
31145
  }
31052
31146
  }
31053
31147
  async function reactiveSeedOnInstallComplete(args) {
31054
- const ctx = await resolveSeedContext({ endpointOverride: args.endpoint, appCredsOverride: args.appCredsOverride, subscriptionId: args.subscriptionId });
31148
+ const ctx = await resolveSeedContext({
31149
+ endpointOverride: args.endpoint,
31150
+ appCredsOverride: args.appCredsOverride,
31151
+ subscriptionId: args.subscriptionId,
31152
+ brainsOverride: args.brains
31153
+ });
31055
31154
  if (!ctx) return;
31056
31155
  const token = await (args.getFoundryTokenImpl ?? getFoundryToken)();
31057
31156
  const { hadIntake, block } = await findOnboardingProfile({ endpoint: ctx.endpoint, token, fetchImpl: args.fetchImpl });
@@ -31081,8 +31180,7 @@ async function reactiveSeedOnInstallComplete(args) {
31081
31180
 
31082
31181
  // src/lib/install-summary.ts
31083
31182
  var DEFAULT_WORKERS = [
31084
- { name: "stacey", label: "Stacey - Startup Advisor", brain: "stacey-brain", executor: "stacey-coder" },
31085
- { name: "ezra", label: "Ezra - Azure Expert", brain: "ezra-brain", executor: "ezra-executor" }
31183
+ { name: "ezra", label: "Ezra - Azure Expert", brain: "ezra-brain" }
31086
31184
  ];
31087
31185
  function renderInstallSummary(args) {
31088
31186
  const open3 = args.webappUrl ? `${args.webappUrl} (or run: m8t open)` : "run: m8t open";
@@ -31094,11 +31192,11 @@ function renderInstallSummary(args) {
31094
31192
  if (args.brainOrg) {
31095
31193
  lines.push(" Your team:");
31096
31194
  for (const w of DEFAULT_WORKERS) {
31097
- lines.push(` \u2022 ${w.label} \xB7 brain: ${args.brainOrg}/${w.brain} \xB7 executor: ${w.executor}`);
31195
+ lines.push(` \u2022 ${w.label} \xB7 brain: ${args.brainOrg}/${w.brain}`);
31098
31196
  }
31099
31197
  lines.push(
31100
31198
  "",
31101
- " Reach them: @stacey / @ezra (or /stacey) in your coding agent",
31199
+ " Reach them: @ezra (or /ezra) in your coding agent",
31102
31200
  " \xB7 the webapp \xB7 or connect Telegram in the webapp (Channels)"
31103
31201
  );
31104
31202
  } else {
@@ -32192,7 +32290,7 @@ async function runCompanionInstallCommand(stdout, install) {
32192
32290
  return 1;
32193
32291
  }
32194
32292
  stdout.write(
32195
- `Desktop companions installed: Stacey and Ezra are ready.
32293
+ `Desktop companions installed - they are at the edge of your screen.
32196
32294
  Version: ${state.version}
32197
32295
  `
32198
32296
  );
@@ -32352,7 +32450,7 @@ async function finalizeInstall(args, deps = defaultDeps2) {
32352
32450
  args.stdout(renderInstallSummary({ webappUrl, brainOrg }) + "\n");
32353
32451
  args.stdout(
32354
32452
  `${colors.field("Optional local tooling for your coding agent:")}
32355
- \u2022 Talk to your deployed workers from agent sessions (e.g. /stacey) \u2014 install the m8t plugin: guides/install/m8t-plugin.md.
32453
+ \u2022 Talk to your deployed workers from agent sessions (e.g. /ezra) \u2014 install the m8t plugin: guides/install/m8t-plugin.md.
32356
32454
  \u2022 Azure-capable MCP servers (microsoft/azure-skills, Microsoft Learn) \u2014 see the optional steps in guides/install.md.
32357
32455
  \u2022 Deploy workers conversationally with the opt-in persona skills \u2014 see guides/workers.md.
32358
32456
  \u2022 Make sure your m8t CLI is current: npm i -g @m8t-stack/cli@latest
@@ -32363,6 +32461,9 @@ ${colors.field("Then open a brand new chat/session")} \u2014 new skills + MCP se
32363
32461
  try {
32364
32462
  await deps.reactiveSeed({
32365
32463
  endpoint: args.doc.result?.foundryEndpoint,
32464
+ // What the install RECORDED creating. Seeding a fixed roster instead used to
32465
+ // fail every default install against a brain that was never created.
32466
+ brains: args.doc.result?.brains,
32366
32467
  subscriptionId: args.subscriptionId,
32367
32468
  stdout: args.stdout
32368
32469
  });
@@ -32384,14 +32485,14 @@ ${colors.field("Then open a brand new chat/session")} \u2014 new skills + MCP se
32384
32485
  const alreadyHasCompanion = await deps.companionStatus().then((s) => s.state !== "not-installed").catch(() => true);
32385
32486
  const pinned = alreadyHasCompanion ? void 0 : args.doc.result?.platformVersion;
32386
32487
  args.stdout(
32387
- (pinned === void 0 ? "Putting Stacey and Ezra on your desktop \u2014 fetching the latest released build\n" : `Putting Stacey and Ezra on your desktop \u2014 fetching the build ${pinned} pins
32488
+ (pinned === void 0 ? "Putting your mates on your desktop \u2014 fetching the latest released build\n" : `Putting your mates on your desktop \u2014 fetching the build ${pinned} pins
32388
32489
  `) + ` ${colors.hint("(about 120 MB; on a slow link this takes a few minutes)")}
32389
32490
  `
32390
32491
  );
32391
32492
  try {
32392
32493
  const companion = await deps.convergeCompanion(pinned);
32393
32494
  if (companion.state === "installed") {
32394
- args.stdout("Desktop companions installed: Stacey and Ezra are ready.\n\n");
32495
+ args.stdout("Desktop companions installed - they are at the edge of your screen.\n\n");
32395
32496
  } else if (companion.state === "not-released") {
32396
32497
  args.stdout(
32397
32498
  `${pinned === void 0 ? "The latest platform release carries no desktop companions." : `The release this platform is pinned to (${pinned}) carries no desktop companions.`}
@@ -34230,11 +34331,11 @@ function parseEvent(value) {
34230
34331
  };
34231
34332
  }
34232
34333
  if (value.type === "roster") {
34233
- if (!hasExactKeys(value, ["type", "origin", "mates"]) || !isGatewayOrigin(value.origin) || !Array.isArray(value.mates) || value.mates.length !== 2) {
34334
+ if (!hasExactKeys(value, ["type", "origin", "mates"]) || !isGatewayOrigin(value.origin) || !Array.isArray(value.mates) || value.mates.length === 0) {
34234
34335
  return eventError();
34235
34336
  }
34236
34337
  const mates = value.mates.map(parseMate);
34237
- if (new Set(mates.map(({ personaKey }) => personaKey)).size !== 2 || new Set(mates.map(({ agentName }) => agentName)).size !== 2) {
34338
+ if (new Set(mates.map(({ personaKey }) => personaKey)).size !== mates.length || new Set(mates.map(({ agentName }) => agentName)).size !== mates.length) {
34238
34339
  return eventError();
34239
34340
  }
34240
34341
  return { type: "roster", origin: value.origin, mates };
@@ -34425,7 +34526,8 @@ function resolveAgentName(agents, personaKey) {
34425
34526
  const matches = agents.filter(
34426
34527
  (agent) => agent.personaKey === personaKey && isAgentName(agent.name)
34427
34528
  );
34428
- if (matches.length !== 1) {
34529
+ if (matches.length === 0) return null;
34530
+ if (matches.length > 1) {
34429
34531
  throw new PredispatchFailure("mate-unavailable");
34430
34532
  }
34431
34533
  const match = matches[0];
@@ -34434,6 +34536,11 @@ function resolveAgentName(agents, personaKey) {
34434
34536
  }
34435
34537
  return match.name;
34436
34538
  }
34539
+ function requireAgentName(agents, personaKey) {
34540
+ const name = resolveAgentName(agents, personaKey);
34541
+ if (name === null) throw new PredispatchFailure("mate-unavailable");
34542
+ return name;
34543
+ }
34437
34544
  function decodeConversationId(data) {
34438
34545
  if (!isRecord3(data) || typeof data.id !== "string" || !OPAQUE_ID.test(data.id)) {
34439
34546
  throw new PredispatchFailure("not-connected");
@@ -34598,22 +34705,15 @@ async function rosterCompanions(sink, deps = {}) {
34598
34705
  const activeSince = new Date(
34599
34706
  installed === null || installed > now ? now : installed
34600
34707
  ).toISOString();
34601
- const mates = [
34602
- {
34603
- personaKey: "startup-advisor",
34604
- agentName: resolveAgentName(agents, "startup-advisor"),
34605
- displayName: "Stacey",
34606
- portraitKey: "stacey",
34607
- activeSince
34608
- },
34609
- {
34610
- personaKey: "ezra",
34611
- agentName: resolveAgentName(agents, "ezra"),
34612
- displayName: "Ezra",
34613
- portraitKey: "ezra",
34614
- activeSince
34615
- }
34708
+ const PRESENTABLE = [
34709
+ { personaKey: "startup-advisor", displayName: "Stacey", portraitKey: "stacey" },
34710
+ { personaKey: "ezra", displayName: "Ezra", portraitKey: "ezra" }
34616
34711
  ];
34712
+ const mates = PRESENTABLE.flatMap((mate) => {
34713
+ const agentName = resolveAgentName(agents, mate.personaKey);
34714
+ return agentName === null ? [] : [{ ...mate, agentName, activeSince }];
34715
+ });
34716
+ if (mates.length === 0) throw new PredispatchFailure("mate-unavailable");
34617
34717
  const event = parseEvent({ type: "roster", origin, mates });
34618
34718
  sink(event);
34619
34719
  return event;
@@ -34745,7 +34845,7 @@ async function dispatchConversation(request, sink, deps, consume, readDesktopMar
34745
34845
  token,
34746
34846
  controller.signal
34747
34847
  );
34748
- const agentName = resolveAgentName(agents, request.personaKey);
34848
+ const agentName = requireAgentName(agents, request.personaKey);
34749
34849
  const conversationId = await (deps.resolveConversationId ?? resolveConversationId)(
34750
34850
  fetchImpl,
34751
34851
  origin,
@@ -34856,7 +34956,7 @@ async function historyCompanionMessages(request, sink, deps = {}) {
34856
34956
  token,
34857
34957
  controller.signal
34858
34958
  );
34859
- const agentName = resolveAgentName(agents, request.personaKey);
34959
+ const agentName = requireAgentName(agents, request.personaKey);
34860
34960
  const conversationId = await (deps.resolveConversationId ?? resolveConversationId)(
34861
34961
  fetchImpl,
34862
34962
  origin,