dsh-web-search-enhanced 0.2.1 → 0.2.2

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/lib/index.js CHANGED
@@ -14680,7 +14680,8 @@ const SEARCH = {
14680
14680
  tools: {
14681
14681
  action: "web_search_enhanced",
14682
14682
  list: "list_web_search_providers"
14683
- }
14683
+ },
14684
+ command: "setup-search"
14684
14685
  };
14685
14686
  //#endregion
14686
14687
  //#region ../core/src/shared/route.ts
@@ -14952,8 +14953,6 @@ async function runOnProvider(voice, access, connectionId, request, call, unhinte
14952
14953
  /** The recipient `sendsTo` names for fetch `local`; the text says `fetches from this machine`. */
14953
14954
  const THIS_MACHINE = "this machine";
14954
14955
  const SESSION_MODEL = "the service behind the session model";
14955
- /** Operator data in the listing is one line and bounded; labels and service names share the settings label bound. */
14956
- const LABEL_MAX = 200;
14957
14956
  const HOST_MAX = 253;
14958
14957
  /** Why the session model cannot search, in English; the execution layer's error and the listing share it. */
14959
14958
  const UNSUPPORTED_REASON_TEXT = {
@@ -15084,7 +15083,7 @@ function renderSearchListing(voice, value) {
15084
15083
  }
15085
15084
  function renderLines(voice, value, head, parts) {
15086
15085
  const entries = value.providers.map((entry) => {
15087
- const line = [statusText(entry)];
15086
+ const line = [statusText$1(entry)];
15088
15087
  if (entry.id === value.sessionProvider) line.push("selected for this session");
15089
15088
  if (entry.use !== void 0) line.push(entry.use);
15090
15089
  line.push(...parts.marks(entry));
@@ -15100,7 +15099,7 @@ function renderLines(voice, value, head, parts) {
15100
15099
  ...tail
15101
15100
  ].join("\n");
15102
15101
  }
15103
- function statusText(entry) {
15102
+ function statusText$1(entry) {
15104
15103
  switch (entry.status) {
15105
15104
  case "ready": return "ready";
15106
15105
  case "needs-key": return "needs an API key (ask the user)";
@@ -15118,7 +15117,7 @@ function listedBase(entry) {
15118
15117
  const { use, recipient } = entry.facts;
15119
15118
  return {
15120
15119
  id: entry.id,
15121
- name: oneLine(entry.name, LABEL_MAX),
15120
+ name: oneLine(entry.name, 200),
15122
15121
  ...use === void 0 ? {} : { use },
15123
15122
  sendsTo: recipientText(recipient)
15124
15123
  };
@@ -15126,8 +15125,8 @@ function listedBase(entry) {
15126
15125
  function recipientText(recipient) {
15127
15126
  switch (recipient.kind) {
15128
15127
  case "this-machine": return THIS_MACHINE;
15129
- case "session-model": return recipient.provider === void 0 ? SESSION_MODEL : `${SESSION_MODEL} (${oneLine(recipient.provider, LABEL_MAX)})`;
15130
- case "service": return recipient.host === void 0 ? oneLine(recipient.service, LABEL_MAX) : oneLine(recipient.host, HOST_MAX);
15128
+ case "session-model": return recipient.provider === void 0 ? SESSION_MODEL : `${SESSION_MODEL} (${oneLine(recipient.provider, 200)})`;
15129
+ case "service": return recipient.host === void 0 ? oneLine(recipient.service, 200) : oneLine(recipient.host, HOST_MAX);
15131
15130
  }
15132
15131
  }
15133
15132
  function readiness(entry) {
@@ -15214,8 +15213,8 @@ function nativeAuth(ctx, ref, secrets = /* @__PURE__ */ new Set()) {
15214
15213
  };
15215
15214
  }
15216
15215
  /** Account readiness uses the next selected model, while request authentication uses its frozen route. */
15217
- async function credentialReadiness(ctx, agent, options) {
15218
- const account = options.endpoint !== void 0 && nextModel(ctx, agent)?.provider === "deepseek-account" ? ctx.get("deepseekAccount") : void 0;
15216
+ async function credentialReadiness(ctx, model, options) {
15217
+ const account = options.endpoint !== void 0 && model?.provider === "deepseek-account" ? ctx.get("deepseekAccount") : void 0;
15219
15218
  if (account !== void 0 && await account.resolveToken(options.endpoint) !== void 0) return {
15220
15219
  access: "account",
15221
15220
  status: "ready"
@@ -15311,10 +15310,32 @@ var Snapshots = class {
15311
15310
  }
15312
15311
  };
15313
15312
  //#endregion
15313
+ //#region ../core/src/host/session-origin.ts
15314
+ function sessionOrigin(header) {
15315
+ const { parentSession: parent, isSeeded: seeded, origin } = header;
15316
+ if (origin === "subagent") return {
15317
+ kind: "subagent",
15318
+ parent,
15319
+ seeded
15320
+ };
15321
+ return parent === void 0 ? {
15322
+ kind: "top-level",
15323
+ seeded
15324
+ } : {
15325
+ kind: "fork",
15326
+ parent,
15327
+ seeded
15328
+ };
15329
+ }
15330
+ function parentOf(origin) {
15331
+ return origin.kind === "top-level" ? void 0 : origin.parent;
15332
+ }
15333
+ //#endregion
15314
15334
  //#region ../core/src/host/provider-lists.ts
15315
15335
  /** Live setup/created events do not make a new conversation a restored one. */
15316
15336
  function isNewConversation(session) {
15317
- return session.header.parentSession === void 0 && !session.header.isSeeded && session.firstLiveSeq === 0 && session.firstLifecycleSeq === 0;
15337
+ const origin = sessionOrigin(session.header);
15338
+ return parentOf(origin) === void 0 && !origin.seeded && session.firstLiveSeq === 0 && session.firstLifecycleSeq === 0;
15318
15339
  }
15319
15340
  /** Immutable conversation authorization, sharing the selection queue and storage lifetime. */
15320
15341
  var ProviderLists = class {
@@ -15333,7 +15354,7 @@ var ProviderLists = class {
15333
15354
  const table = (await this.storage.domain()).table("provider_lists");
15334
15355
  const stored = table.get(agent.session.id);
15335
15356
  if (stored !== void 0) return this.nonempty(stored);
15336
- const parent = agent.session.header.parentSession;
15357
+ const parent = parentOf(sessionOrigin(agent.session.header));
15337
15358
  let ids;
15338
15359
  if (parent !== void 0) {
15339
15360
  await this.storage.settled(parent);
@@ -15356,6 +15377,14 @@ function isSelectable(connection) {
15356
15377
  }
15357
15378
  //#endregion
15358
15379
  //#region ../core/src/host/sessions.ts
15380
+ function liveSession(agent) {
15381
+ return {
15382
+ kind: "live",
15383
+ id: agent.session.id,
15384
+ header: agent.session.header,
15385
+ agent
15386
+ };
15387
+ }
15359
15388
  var SelectionConflict = class extends Error {
15360
15389
  constructor() {
15361
15390
  super("the selection changed since it was read");
@@ -15376,20 +15405,20 @@ var Sessions = class {
15376
15405
  this.restriction = restriction;
15377
15406
  this.describe = describe;
15378
15407
  }
15379
- current(agent) {
15380
- return this.exclusive(agent.session.id, async () => this.read(agent, await this.table()));
15408
+ current(target) {
15409
+ return this.exclusive(target.id, async () => this.read(target, await this.table()));
15381
15410
  }
15382
15411
  /** Resolve visibility without creating records or materializing inherited/default options. */
15383
- peek(agent) {
15384
- return this.exclusive(agent.session.id, async () => this.read(agent, await this.table(), false));
15412
+ peek(target) {
15413
+ return this.exclusive(target.id, async () => this.read(target, await this.table(), false));
15385
15414
  }
15386
- change(agent, change, expectedRevision) {
15387
- return this.exclusive(agent.session.id, async () => {
15415
+ change(target, change, expectedRevision) {
15416
+ return this.exclusive(target.id, async () => {
15388
15417
  const table = await this.table();
15389
- await this.read(agent, table);
15418
+ await this.read(target, table);
15390
15419
  const { connectionId, ...options } = change;
15391
15420
  const record = this.storage.optionsCodec.toRecord(options);
15392
- const updated = await table.update(agent.session.id, (current) => {
15421
+ const updated = await table.update(target.id, (current) => {
15393
15422
  if (current.revision !== expectedRevision) throw new SelectionConflict();
15394
15423
  return {
15395
15424
  ...current,
@@ -15398,9 +15427,10 @@ var Sessions = class {
15398
15427
  revision: current.revision + 1
15399
15428
  };
15400
15429
  });
15401
- this.restriction.sync(agent, updated.connectionId);
15402
- if (connectionId !== void 0) {
15403
- const model = nextModel(this.ctx, agent);
15430
+ const agent = this.ctx.get("agents")?.get(target.id);
15431
+ if (agent !== void 0) this.restriction.sync(agent, updated.connectionId);
15432
+ if (connectionId !== void 0 && sessionOrigin(target.header).kind !== "subagent") {
15433
+ const model = this.model(target);
15404
15434
  if (model !== void 0) {
15405
15435
  const memory = await this.pairings.set(model, updated.connectionId).then(() => ({ kind: "stored" }), (error) => ({
15406
15436
  kind: "failed",
@@ -15415,29 +15445,33 @@ var Sessions = class {
15415
15445
  };
15416
15446
  });
15417
15447
  }
15418
- connections(agent) {
15419
- return this.describe(this.settings(), agent);
15448
+ connections(target) {
15449
+ return this.describe(this.settings(), this.model(target));
15420
15450
  }
15421
15451
  selectable(connectionId) {
15422
15452
  return isSelectable(this.settings().connections.get(connectionId));
15423
15453
  }
15454
+ model(target) {
15455
+ return target.kind === "live" ? nextModel(this.ctx, target.agent) : void 0;
15456
+ }
15424
15457
  async table() {
15425
15458
  return (await this.storage.domain()).table("selections");
15426
15459
  }
15427
15460
  exclusive(id, work) {
15428
15461
  return this.storage.exclusive(id, work);
15429
15462
  }
15430
- async read(agent, table, persist = true) {
15463
+ async read(target, table, persist = true) {
15431
15464
  const settings = this.settings();
15432
15465
  const codec = this.storage.optionsCodec;
15433
- const id = agent.session.id;
15466
+ const id = target.id;
15434
15467
  let stored = table.get(id);
15435
- const { parentSession, isSeeded } = agent.session.header;
15436
- const seeded = parentSession !== void 0 && isSeeded;
15468
+ const origin = sessionOrigin(target.header);
15469
+ const parentSession = parentOf(origin);
15470
+ const seeded = parentSession !== void 0 && origin.seeded;
15437
15471
  let inherited = stored !== void 0 && seeded && (stored.inherited ?? table.get(parentSession) !== void 0);
15438
15472
  if (stored === void 0 && seeded) {
15439
15473
  const parentAgent = this.ctx.get("agents")?.get(parentSession);
15440
- if (parentAgent !== void 0 && persist) await this.current(parentAgent);
15474
+ if (parentAgent !== void 0 && persist) await this.current(liveSession(parentAgent));
15441
15475
  else await this.storage.settled(parentSession);
15442
15476
  const parent = table.get(parentSession);
15443
15477
  if (parent !== void 0) {
@@ -15461,7 +15495,7 @@ var Sessions = class {
15461
15495
  source: next.revision > 0 ? "session" : "inherited"
15462
15496
  };
15463
15497
  }
15464
- const fallback = await this.defaultFor(agent, settings);
15498
+ const fallback = await this.defaultFor(target, settings);
15465
15499
  const options = stored === void 0 ? codec.initial(settings) : codec.fromRecord(stored, settings);
15466
15500
  const next = {
15467
15501
  ...codec.toRecord(options),
@@ -15475,8 +15509,8 @@ var Sessions = class {
15475
15509
  source: fallback.source
15476
15510
  };
15477
15511
  }
15478
- async defaultFor(agent, settings) {
15479
- const model = nextModel(this.ctx, agent);
15512
+ async defaultFor(target, settings) {
15513
+ const model = this.model(target);
15480
15514
  const paired = model === void 0 ? void 0 : await this.pairings.get(model);
15481
15515
  if (paired === null) return {
15482
15516
  connectionId: null,
@@ -15503,6 +15537,24 @@ function sameRecord(left, right) {
15503
15537
  return left !== void 0 && JSON.stringify(left) === JSON.stringify(right);
15504
15538
  }
15505
15539
  //#endregion
15540
+ //#region ../core/src/host/selection-write.ts
15541
+ /** The shared eligibility check and revisioned write for commands and Remote set. */
15542
+ async function writeSelection(sessions, target, change, expectedRevision) {
15543
+ if (typeof change.connectionId === "string" && !sessions.selectable(change.connectionId)) return {
15544
+ kind: "unavailable",
15545
+ connectionId: change.connectionId
15546
+ };
15547
+ try {
15548
+ return {
15549
+ kind: "written",
15550
+ current: await sessions.change(target, change, expectedRevision)
15551
+ };
15552
+ } catch (error) {
15553
+ if (error instanceof SelectionConflict) return { kind: "conflict" };
15554
+ throw error;
15555
+ }
15556
+ }
15557
+ //#endregion
15506
15558
  //#region ../core/src/host/remote.ts
15507
15559
  var __runInitializers = function(thisArg, initializers, value) {
15508
15560
  var useValue = arguments.length > 2;
@@ -15650,27 +15702,22 @@ function createConnectionsService(ctx, spec) {
15650
15702
  async get(request) {
15651
15703
  return boundary("get", async () => {
15652
15704
  const { sessionId } = parse(selectionRequest, request);
15653
- const agent = await this.agent(sessionId);
15654
- return this.view(agent, await spec.sessions.current(agent));
15705
+ const target = await this.target(sessionId);
15706
+ return this.view(target, await spec.sessions.current(target));
15655
15707
  });
15656
15708
  }
15657
15709
  async set(request) {
15658
15710
  return boundary("set", async () => {
15659
15711
  const { sessionId, connectionId, options, expectedRevision } = parse(spec.contract.selectionChange, request);
15660
- const agent = await this.agent(sessionId);
15661
- if (typeof connectionId === "string" && !spec.sessions.selectable(connectionId)) throw new RemoteError(spec.namespace + "/unavailable", "the connection is missing, disabled or unsupported", { connectionId });
15662
- let current;
15663
- try {
15664
- const change = {
15665
- ...options,
15666
- ...connectionId === void 0 ? {} : { connectionId }
15667
- };
15668
- current = await spec.sessions.change(agent, change, expectedRevision);
15669
- } catch (error) {
15670
- if (error instanceof SelectionConflict) throw new RemoteError(spec.namespace + "/conflict", "the selection changed elsewhere; re-read it and retry", {});
15671
- throw error;
15672
- }
15673
- return this.view(agent, current);
15712
+ const target = await this.target(sessionId);
15713
+ const change = {
15714
+ ...options,
15715
+ ...connectionId === void 0 ? {} : { connectionId }
15716
+ };
15717
+ const result = await writeSelection(spec.sessions, target, change, expectedRevision);
15718
+ if (result.kind === "unavailable") throw new RemoteError(spec.namespace + "/unavailable", "the connection is missing, disabled or unsupported", { connectionId: result.connectionId });
15719
+ if (result.kind === "conflict") throw new RemoteError(spec.namespace + "/conflict", "the selection changed elsewhere; re-read it and retry", {});
15720
+ return this.view(target, result.current);
15674
15721
  });
15675
15722
  }
15676
15723
  async provider(request) {
@@ -15692,15 +15739,27 @@ function createConnectionsService(ctx, spec) {
15692
15739
  return { pairings: await spec.pairings.list() };
15693
15740
  });
15694
15741
  }
15695
- async agent(sessionId) {
15696
- const found = await this.ctx.sessionController.resolveAgent(sessionId);
15742
+ async target(sessionId) {
15743
+ const id = sessionId;
15744
+ const agent = this.ctx.agents.get(id);
15745
+ if (agent !== void 0) return liveSession(agent);
15746
+ const persistence = this.ctx.get("sessionPersistence");
15747
+ if (persistence !== void 0) {
15748
+ const stored = await persistence.stat(id);
15749
+ if (stored !== void 0 && sessionOrigin(stored.header).kind === "subagent") return {
15750
+ kind: "cold",
15751
+ id,
15752
+ header: stored.header
15753
+ };
15754
+ }
15755
+ const found = await this.ctx.sessionController.resolveAgent(id);
15697
15756
  if ("error" in found) throw found.error;
15698
- return found.agent;
15757
+ return liveSession(found.agent);
15699
15758
  }
15700
- async view(agent, current) {
15759
+ async view(target, current) {
15701
15760
  return {
15702
15761
  ...current,
15703
- connections: await spec.sessions.connections(agent)
15762
+ connections: await spec.sessions.connections(target)
15704
15763
  };
15705
15764
  }
15706
15765
  };
@@ -16014,7 +16073,7 @@ function explicitAccess(ctx, capability, runtime, errors, unavailable) {
16014
16073
  const described = await errors.abortable(capability.describe({
16015
16074
  ...prepared.settings,
16016
16075
  connections
16017
- }, call.agent), call.signal);
16076
+ }, nextModel(ctx, call.agent)), call.signal);
16018
16077
  errors.throwIfAborted(call.signal);
16019
16078
  return new Map(described.map((view) => [view.id, view]));
16020
16079
  } catch {
@@ -16211,6 +16270,188 @@ var SessionStorage = class {
16211
16270
  }
16212
16271
  };
16213
16272
  //#endregion
16273
+ //#region ../core/src/host/command.ts
16274
+ var SelectionOperationError = class extends Error {};
16275
+ const SOURCES = {
16276
+ session: "chosen in this session",
16277
+ inherited: "copied from the parent session",
16278
+ model: "remembered for this model",
16279
+ default: "the default connection"
16280
+ };
16281
+ function registerCommand(ctx, capability, sessions) {
16282
+ const { command, providerId, rowId } = capability.identity;
16283
+ const noun = capability.tool === "web_search" ? "web search" : "web fetch";
16284
+ const capital = capability.tool === "web_search" ? "Web search" : "Web fetch";
16285
+ const options = capability.commandOptions;
16286
+ const hint = options === void 0 ? "[off | <connection id>]" : "[off | <connection id> | freshness auto|fresh|realtime]";
16287
+ const failure = "The " + noun + " selection could not be read or saved; retry, or check the Host logs.";
16288
+ const error = (text) => ({
16289
+ kind: "error",
16290
+ text
16291
+ });
16292
+ const selectionOperation = async (work) => {
16293
+ try {
16294
+ return await work();
16295
+ } catch (cause) {
16296
+ if (cause instanceof InvalidSettingsError) throw cause;
16297
+ ctx.logger.warn("%s command selection read or write failed: %s", rowId, cause);
16298
+ throw new SelectionOperationError("selection read or write failed");
16299
+ }
16300
+ };
16301
+ const route = () => routeFacts(ctx, capability.field, providerId);
16302
+ const routing = () => routingText(route(), capability.tool, providerId);
16303
+ const unavailable = (id) => error(id + " is missing or turned off in the settings. Run /" + command + " to list the connections.");
16304
+ const success = (text) => ({
16305
+ kind: "success",
16306
+ text: text + (route().kind === "this" ? "" : "\n" + routing())
16307
+ });
16308
+ const run = async (invocation) => {
16309
+ const raw = invocation.rawInput.trim();
16310
+ const args = raw === "" ? [] : raw.split(/\s+/u);
16311
+ const usage = () => error("Unknown argument \"" + oneLine(raw, 64) + "\". Usage: /" + command + " " + hint);
16312
+ const keyword = args.length === 0 ? "" : args[0].toLowerCase();
16313
+ const freshnessValue = args.length === 2 ? args[1].toLowerCase() : "";
16314
+ const freshness = options !== void 0 && args.length === 2 && keyword === "freshness";
16315
+ if (args.length > 0 && !freshness && !(args.length === 1 && (keyword === "off" || isConnectionId(args[0])))) return usage();
16316
+ if (freshness && !FRESHNESS.some((value) => value === freshnessValue)) return error("Unknown freshness \"" + oneLine(args[1], 64) + "\". Use auto, fresh or realtime.");
16317
+ const target = liveSession(invocation.agent);
16318
+ const settings = capability.settings();
16319
+ const current = await selectionOperation(() => sessions.current(target));
16320
+ if (args.length === 0) {
16321
+ const views = await sessions.connections(target);
16322
+ const id = current.selection.connectionId;
16323
+ const selected = id === null ? void 0 : views.find((view) => view.id === id);
16324
+ let summary = id === null ? "Off" : selected === void 0 || !sessions.selectable(id) ? id : oneLine(selected.label, 200) + " (" + id + ")";
16325
+ summary += " · " + SOURCES[current.source];
16326
+ if (id !== null && !sessions.selectable(id)) summary += " · missing or turned off in the settings; " + capability.tool + " fails until another connection is chosen";
16327
+ if (options !== void 0) summary += " · freshness: " + options.freshness(current.selection.options);
16328
+ const entries = [];
16329
+ for (const view of views) {
16330
+ const connection = settings.connections.get(view.id);
16331
+ if (!isSelectable(connection)) continue;
16332
+ const name = oneLine(view.label, 200);
16333
+ const parts = [statusText(view)];
16334
+ if (view.id === id) parts.push("current");
16335
+ if (view.freshness === true) parts.push("applies freshness");
16336
+ const recipient = recipientText(capability.enhanced.listing(connection, {
16337
+ agent: invocation.agent,
16338
+ signal: invocation.signal
16339
+ }).recipient);
16340
+ if (recipient === "this machine") parts.push("fetches from this machine");
16341
+ else if (recipient !== name) parts.push((capability.tool === "web_search" ? "queries" : "URLs") + " go to " + recipient);
16342
+ entries.push("- " + view.id + " — " + name + " · " + parts.join(" · "));
16343
+ }
16344
+ if (entries.length === 0) entries.push("- (none; turn connections on in the row settings)");
16345
+ const tail = "Turn off: /" + command + " off" + (options === void 0 ? "" : " · Freshness: /" + command + " freshness auto|fresh|realtime (connections marked \"applies freshness\")");
16346
+ return {
16347
+ kind: "success",
16348
+ text: [
16349
+ summary,
16350
+ routing(),
16351
+ "Connections (/" + command + " <id> chooses one):",
16352
+ ...entries,
16353
+ tail
16354
+ ].join("\n")
16355
+ };
16356
+ }
16357
+ let change;
16358
+ let message;
16359
+ if (freshness && options !== void 0) {
16360
+ const selected = (await sessions.connections(target)).find((view) => view.id === current.selection.connectionId);
16361
+ if (selected === void 0 || selected.freshness !== true || !sessions.selectable(selected.id)) return error("The current connection does not apply freshness. Choose one marked \"applies freshness\" first.");
16362
+ const value = FRESHNESS.find((mode) => mode === freshnessValue);
16363
+ change = options.changeFreshness(value);
16364
+ message = "Freshness is " + value + " from the next model request.";
16365
+ } else if (keyword === "off") {
16366
+ change = { connectionId: null };
16367
+ message = capital + " is off for this session from the next model request.";
16368
+ } else {
16369
+ const id = args[0];
16370
+ if (!sessions.selectable(id)) return unavailable(id);
16371
+ const selected = (await sessions.connections(target)).find((view) => view.id === id);
16372
+ change = { connectionId: id };
16373
+ message = "Now using " + oneLine(selected.label, 200) + " (" + id + ") for " + noun + " from the next model request.";
16374
+ }
16375
+ const result = await selectionOperation(() => writeSelection(sessions, target, change, current.selection.revision));
16376
+ if (result.kind === "unavailable") return unavailable(result.connectionId);
16377
+ if (result.kind === "conflict") return error("The selection changed while this command ran. Run /" + command + " to see it, then try again.");
16378
+ return success(message);
16379
+ };
16380
+ ctx.effect(() => ctx.commands.register({
16381
+ name: command,
16382
+ description: "Show or change this session's " + noun + " connection",
16383
+ input: { hint },
16384
+ async handler(invocation) {
16385
+ try {
16386
+ return await run(invocation);
16387
+ } catch (cause) {
16388
+ if (cause instanceof SelectionOperationError) return error(failure);
16389
+ ctx.logger.warn("%s command failed: %s", rowId, cause);
16390
+ if (cause instanceof InvalidSettingsError) return error("The " + noun + " settings are invalid; fix them in the Enhanced " + noun + " row settings.");
16391
+ throw new Error("The " + noun + " command failed; retry, or check the Host logs.");
16392
+ }
16393
+ }
16394
+ }));
16395
+ }
16396
+ function routingText(route, tool, providerId) {
16397
+ switch (route.kind) {
16398
+ case "this": return "Routing: " + tool + " goes to this plugin.";
16399
+ case "other": return "Routing: " + tool + " goes to " + oneLine(route.provider, 200) + ", so this selection has no effect until the web row routes it to " + providerId + ".";
16400
+ case "auto": return "Routing: the web row pins no " + tool + " provider, so this selection has no effect until it routes " + tool + " to " + providerId + ".";
16401
+ case "unknown": return "Routing: the web row could not be read, so this selection may have no effect.";
16402
+ }
16403
+ }
16404
+ function statusText(view) {
16405
+ switch (view.status) {
16406
+ case "ready": return "ready";
16407
+ case "needs-credential": return view.access === "account" ? "needs DeepSeek sign-in" : "needs an API key";
16408
+ case "unsupported": return "unavailable: " + UNSUPPORTED_REASON_TEXT[view.reason];
16409
+ case "disabled": return "missing or turned off in the settings";
16410
+ }
16411
+ }
16412
+ //#endregion
16413
+ //#region ../core/src/host/terminal.ts
16414
+ function registerTerminal(ctx, root, noun, settings, freshness) {
16415
+ ctx.effect(() => ctx.tuiCommandTrees.register({
16416
+ root,
16417
+ children(path) {
16418
+ if (path[0] !== root) return [];
16419
+ if (freshness && path.length === 2 && path[1] === "freshness") return [
16420
+ {
16421
+ name: "auto",
16422
+ description: "Auto"
16423
+ },
16424
+ {
16425
+ name: "fresh",
16426
+ description: "Within 24 hours"
16427
+ },
16428
+ {
16429
+ name: "realtime",
16430
+ description: "Live"
16431
+ }
16432
+ ];
16433
+ if (path.length !== 1) return [];
16434
+ const nodes = [{
16435
+ name: "off",
16436
+ description: "Turn " + noun + " off for this session"
16437
+ }];
16438
+ try {
16439
+ for (const connection of settings().connections.values()) if (isSelectable(connection)) nodes.push({
16440
+ name: connection.id,
16441
+ description: oneLine(connection.label, 200)
16442
+ });
16443
+ } catch (error) {
16444
+ if (!(error instanceof InvalidSettingsError)) throw error;
16445
+ }
16446
+ if (freshness) nodes.push({
16447
+ name: "freshness",
16448
+ description: "Content freshness, for connections that apply it"
16449
+ });
16450
+ return nodes;
16451
+ }
16452
+ }));
16453
+ }
16454
+ //#endregion
16214
16455
  //#region ../core/src/host/runtime.ts
16215
16456
  /** Install the sole Seat, session lifecycle, route-guarded restrictions and Remote service. */
16216
16457
  function installCapability(ctx, capability) {
@@ -16231,7 +16472,7 @@ function installCapability(ctx, capability) {
16231
16472
  const restriction = new ToolRestriction(ctx, {
16232
16473
  tool: capability.tool,
16233
16474
  routed: () => routeFacts(ctx, capability.field, capability.identity.providerId).kind === "this",
16234
- selection: async (agent) => (await sessions.peek(agent)).selection.connectionId,
16475
+ selection: async (agent) => (await sessions.peek(liveSession(agent))).selection.connectionId,
16235
16476
  enhanced: {
16236
16477
  rowId: capability.identity.rowId,
16237
16478
  names: capability.enhanced.names,
@@ -16247,11 +16488,11 @@ function installCapability(ctx, capability) {
16247
16488
  providers: (agent) => lists.read(agent)
16248
16489
  }
16249
16490
  });
16250
- const sessions = new Sessions(ctx, () => capability.settings(), storage, pairings, restriction, (settings, agent) => capability.describe(settings, agent));
16491
+ const sessions = new Sessions(ctx, () => capability.settings(), storage, pairings, restriction, (settings, model) => capability.describe(settings, model));
16251
16492
  const capture = async (agent, signal) => {
16252
16493
  const operation = restriction.begin(agent);
16253
16494
  try {
16254
- const read = sessions.current(agent);
16495
+ const read = sessions.current(liveSession(agent));
16255
16496
  const { selection } = signal === void 0 ? await read : await errors.abortable(read, signal);
16256
16497
  if (!restriction.active) return {
16257
16498
  kind: "failed",
@@ -16298,7 +16539,17 @@ function installCapability(ctx, capability) {
16298
16539
  snapshots.forget(agent);
16299
16540
  restriction.forget(agent);
16300
16541
  });
16301
- ctx.inject(["sessionController", "typert"], (scope) => {
16542
+ ctx.inject(["commands"], (scope) => {
16543
+ registerCommand(scope, capability, sessions);
16544
+ });
16545
+ ctx.inject(["tuiCommandTrees"], (scope) => {
16546
+ registerTerminal(scope, capability.identity.command, "web " + kind, () => capability.settings(), capability.commandOptions !== void 0);
16547
+ });
16548
+ ctx.inject([
16549
+ "sessionController",
16550
+ "typert",
16551
+ "agents"
16552
+ ], (scope) => {
16302
16553
  createConnectionsService(scope, {
16303
16554
  namespace: capability.remoteNamespace,
16304
16555
  contract: capability.contract,
@@ -17180,7 +17431,7 @@ const { withDeadline, readJson, requestJson, invalidResponse } = transport;
17180
17431
  const mcp = createMcpClient(transport, searchErrors, {
17181
17432
  clientInfo: {
17182
17433
  name: SEARCH.packageName,
17183
- version: "0.2.1"
17434
+ version: "0.2.2"
17184
17435
  },
17185
17436
  messages: {
17186
17437
  toolFailed: (label, detail) => label + " could not complete the search; retry later or choose another search connection" + upstreamSuffix(label, detail),
@@ -18258,14 +18509,14 @@ function searchEnhanced(ctx) {
18258
18509
  }
18259
18510
  //#endregion
18260
18511
  //#region src/host/connections.ts
18261
- async function describeConnections(ctx, settings, agent) {
18512
+ async function describeConnections(ctx, settings, model) {
18262
18513
  return Promise.all([...settings.connections.values()].map(async (connection) => {
18263
18514
  const base = baseOf(connection);
18264
18515
  if (connection.kind === "model") {
18265
18516
  const target = connection.route.kind === "fixed" ? {
18266
18517
  kind: "route",
18267
18518
  route: fixedRoute(connection.route)
18268
- } : sessionRoute(ctx, nextModel(ctx, agent));
18519
+ } : sessionRoute(ctx, model);
18269
18520
  const access = target.kind === "route" ? target.route.auth.kind : "api-key";
18270
18521
  if (connection.disabled) return {
18271
18522
  ...base,
@@ -18298,7 +18549,7 @@ async function describeConnections(ctx, settings, agent) {
18298
18549
  const endpoint = connection.kind === "native" ? typeof connection.options.baseURL === "string" ? connection.options.baseURL : CATALOG[connection.native].endpoint : void 0;
18299
18550
  return {
18300
18551
  ...base,
18301
- ...await credentialReadiness(ctx, agent, {
18552
+ ...await credentialReadiness(ctx, model, {
18302
18553
  endpoint,
18303
18554
  credentialRef: connection.credentialRef
18304
18555
  })
@@ -18343,7 +18594,11 @@ function searchCapability(ctx, settings) {
18343
18594
  contract,
18344
18595
  optionsCodec,
18345
18596
  settings,
18346
- describe: (current, agent) => describeConnections(ctx, current, agent),
18597
+ commandOptions: {
18598
+ freshness: (options) => options.freshness,
18599
+ changeFreshness: (freshness) => ({ freshness })
18600
+ },
18601
+ describe: (current, model) => describeConnections(ctx, current, model),
18347
18602
  target: (connection, options, call) => {
18348
18603
  switch (connection.kind) {
18349
18604
  case "adapter": return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-web-search-enhanced",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "web_search provider for DeepSeek Harness with switchable search backends; installed through dsh-tool-web-enhanced-profile",
5
5
  "keywords": [
6
6
  "deepseek-harness",