@zackbart/connecta 0.10.5 → 0.11.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.
Files changed (93) hide show
  1. package/AGENTS.md +8 -6
  2. package/CHANGELOG.md +150 -0
  3. package/README.md +5 -4
  4. package/bin/connecta.mjs +0 -7
  5. package/dist/activity.d.ts +11 -1
  6. package/dist/activity.d.ts.map +1 -1
  7. package/dist/activity.js +44 -3
  8. package/dist/activity.js.map +1 -1
  9. package/dist/catalog-service.d.ts +24 -0
  10. package/dist/catalog-service.d.ts.map +1 -1
  11. package/dist/catalog-service.js +68 -9
  12. package/dist/catalog-service.js.map +1 -1
  13. package/dist/connectors/api.d.ts +2 -2
  14. package/dist/connectors/remote-mcp.d.ts +1 -1
  15. package/dist/errors.d.ts +49 -4
  16. package/dist/errors.d.ts.map +1 -1
  17. package/dist/errors.js +68 -1
  18. package/dist/errors.js.map +1 -1
  19. package/dist/execute.d.ts +73 -3
  20. package/dist/execute.d.ts.map +1 -1
  21. package/dist/execute.js +161 -29
  22. package/dist/execute.js.map +1 -1
  23. package/dist/index.d.ts +28 -30
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +29 -37
  26. package/dist/index.js.map +1 -1
  27. package/dist/invocation.d.ts +9 -2
  28. package/dist/invocation.d.ts.map +1 -1
  29. package/dist/invocation.js +61 -31
  30. package/dist/invocation.js.map +1 -1
  31. package/dist/meta-tools.d.ts +24 -59
  32. package/dist/meta-tools.d.ts.map +1 -1
  33. package/dist/meta-tools.js +107 -359
  34. package/dist/meta-tools.js.map +1 -1
  35. package/dist/operator-ui/generated.d.ts +1 -1
  36. package/dist/operator-ui/generated.d.ts.map +1 -1
  37. package/dist/operator-ui/generated.js +1 -1
  38. package/dist/operator-ui/generated.js.map +1 -1
  39. package/dist/registry.d.ts +12 -10
  40. package/dist/registry.d.ts.map +1 -1
  41. package/dist/registry.js +8 -17
  42. package/dist/registry.js.map +1 -1
  43. package/dist/routes/mcp.d.ts.map +1 -1
  44. package/dist/routes/mcp.js +19 -21
  45. package/dist/routes/mcp.js.map +1 -1
  46. package/dist/routes/shared.d.ts +9 -11
  47. package/dist/routes/shared.d.ts.map +1 -1
  48. package/dist/routes/shared.js.map +1 -1
  49. package/dist/server.js +5 -4
  50. package/dist/server.js.map +1 -1
  51. package/dist/skills.d.ts +8 -18
  52. package/dist/skills.d.ts.map +1 -1
  53. package/dist/skills.js +13 -60
  54. package/dist/skills.js.map +1 -1
  55. package/dist/types.d.ts +6 -20
  56. package/dist/types.d.ts.map +1 -1
  57. package/dist/version.d.ts +1 -1
  58. package/dist/version.js +1 -1
  59. package/documentation/code-first-exploration.md +16 -16
  60. package/documentation/code-mode.md +137 -63
  61. package/documentation/connectors.md +1 -1
  62. package/documentation/meta-tools.md +96 -33
  63. package/documentation/rich-output-design.md +212 -0
  64. package/ethos.md +17 -19
  65. package/examples/node/README.md +1 -2
  66. package/examples/node/src/index.ts +1 -3
  67. package/examples/worker/README.md +19 -16
  68. package/examples/worker/src/d1-activity-row.ts +40 -0
  69. package/examples/worker/src/d1-activity.ts +3 -2
  70. package/examples/worker/src/index.ts +6 -14
  71. package/examples/worker/wrangler.jsonc +3 -6
  72. package/package.json +1 -1
  73. package/src/activity.ts +69 -3
  74. package/src/catalog-service.ts +113 -20
  75. package/src/connectors/api.ts +2 -2
  76. package/src/connectors/remote-mcp.ts +1 -1
  77. package/src/errors.ts +104 -3
  78. package/src/execute.ts +237 -37
  79. package/src/index.ts +60 -67
  80. package/src/invocation.ts +61 -19
  81. package/src/meta-tools.ts +136 -482
  82. package/src/operator-ui/browser.ts +10 -2
  83. package/src/operator-ui/generated.ts +1 -1
  84. package/src/registry.ts +7 -35
  85. package/src/routes/mcp.ts +19 -21
  86. package/src/routes/shared.ts +8 -11
  87. package/src/server.ts +7 -7
  88. package/src/skills.ts +11 -74
  89. package/src/types.ts +6 -21
  90. package/src/version.ts +1 -1
  91. package/templates/node/README.md +2 -1
  92. package/templates/node/package.json +1 -1
  93. package/templates/node/src/index.ts +1 -1
package/AGENTS.md CHANGED
@@ -4,10 +4,10 @@ This is the canonical instruction file for coding agents. `CLAUDE.md` is a
4
4
  symlink to this file so every agent works from the same conventions.
5
5
 
6
6
  A single MCP endpoint aggregating downstream connectors (remote MCP servers and
7
- plain HTTP APIs) behind a small fixed set of meta-tools. A deployment with an
8
- executor serves seven, `execute_code` among them, and agents reach connectors by
9
- writing JavaScript against it; one without an executor serves the nine classic
10
- tools. One fetch-native core, running on both Node and Cloudflare Workers.
7
+ plain HTTP APIs) behind seven meta-tools, `execute_code` among them. Every
8
+ deployment configures an executor, and agents reach connectors by writing
9
+ JavaScript against it. One fetch-native core, running on both Node and
10
+ Cloudflare Workers.
11
11
 
12
12
  - **[`ethos.md`](./ethos.md) is the constitution.** It states what connecta is
13
13
  and isn't, and its decisions table carries a verdict for every shape already
@@ -15,8 +15,10 @@ tools. One fetch-native core, running on both Node and Cloudflare Workers.
15
15
  designing or building anything: a `refused` row is a "no" with the reason
16
16
  attached, and a `removed` row (toolkits
17
17
  [#178](https://github.com/zackbart/connecta/issues/178), proactive credential
18
- liveness [#179](https://github.com/zackbart/connecta/issues/179)) records a
19
- surface that no longer exists — do not reintroduce it without a new decision.
18
+ liveness [#179](https://github.com/zackbart/connecta/issues/179), the classic
19
+ executor-free surface
20
+ [#273](https://github.com/zackbart/connecta/issues/273)) records a surface
21
+ that no longer exists — do not reintroduce it without a new decision.
20
22
  - There is no TODO.md — the roadmap lives in
21
23
  [GitHub issues](https://github.com/zackbart/connecta/issues). When you find
22
24
  TODO items (in code comments, docs, or conversation), don't accumulate them
package/CHANGELOG.md CHANGED
@@ -2,6 +2,156 @@
2
2
 
3
3
  All notable changes to this package are documented here.
4
4
 
5
+ ## 0.11.0 — 2026-07-31
6
+
7
+ **This is a breaking deployment release.** Connecta no longer carries the old
8
+ executor-free compatibility surface. Every deployment must configure an
9
+ executor and now exposes the same seven tools; construction refuses to boot
10
+ without one. Existing code-first deployments keep their model-facing surface.
11
+ Node deployments that omitted an executor must add `quickJsExecutor()`, while
12
+ Workers deployments must configure a `DynamicWorkerExecutor` and its paid-plan
13
+ Worker Loader binding. Remove any `surface` setting during the upgrade. (#273)
14
+
15
+ The consolidation also removes the classic-only handlers and configuration
16
+ that had become two implementations of the same work. Discovery and batching
17
+ now have one home inside `execute_code`, while `call_tool`,
18
+ `call_destructive_tool`, and result retrieval remain explicit host boundaries.
19
+ The superseded code-first gate has been reduced to its surviving measurement
20
+ record instead of retaining a second executable version of the product.
21
+
22
+ ### Changed
23
+
24
+ - **An executor is required.** `ConnectaConfig.executor` is no longer optional;
25
+ use `quickJsExecutor()` from `@zackbart/connecta/quickjs` on Node or
26
+ `DynamicWorkerExecutor` from `@cloudflare/codemode` on Workers. The CLI
27
+ template, examples, doctor, documentation, and package smoke test all enforce
28
+ the same deployment shape.
29
+ - **Every MCP connection advertises exactly seven tools.** The former
30
+ top-level `list_connectors`, `describe_tools`, and `batch_call` registrations
31
+ are removed. Their supported equivalents are `connecta.search`,
32
+ `connecta.describe`, and `connecta.batch` inside `execute_code`.
33
+ - **The old surface controls fail explicitly.** Supplying the removed
34
+ `ConnectaConfig.surface` option throws instead of being ignored. The
35
+ classic-only `calls.maxBatchResultBytes` option also throws; program batching
36
+ is bounded by the executor and `connecta.batch` limits, while individual
37
+ calls still honor `calls.maxResultBytes` and connector overrides.
38
+ - **Cloudflare deployments require code mode.** The Worker example now requires
39
+ its `worker_loaders` binding and the Workers Paid plan rather than falling
40
+ back to the classic surface when the binding is absent.
41
+ - **The retired code-first gate is archival.** Its executable harness is
42
+ removed now that code-first is the sole product surface; the current-version
43
+ audit remains the live measurement path.
44
+
45
+ ## 0.10.6 — 2026-07-31
46
+
47
+ Programs gained a rich-output channel. `execute_code` code can now call
48
+ `connecta.emit(block)` to deliver text, image, and audio MCP content blocks
49
+ alongside its JSON return value — the piece code mode was missing for output
50
+ that cannot be projected, like a screenshot a downstream tool returned. The
51
+ channel is additive: a program that never emits produces the byte-for-byte
52
+ prior response, no executor changed to carry it, and deployments that do
53
+ nothing get sensible budgets. The design record is
54
+ `documentation/rich-output-design.md` (#267); the contract is `code-mode.md`'s
55
+ "Emitted output" clauses (#270).
56
+
57
+ Agent recovery is now executable data instead of prose at the remaining local
58
+ failure points. Address mistakes, approval reroutes, shortcut collisions, and
59
+ paged results identify their next call directly; activity classifies those
60
+ moments without retaining payloads. Connector behavior and approval authority
61
+ are unchanged.
62
+
63
+ Alongside both, three pieces of runtime text stop naming tools the receiving
64
+ surface does not serve — a routing failure connecta authored itself, and one the
65
+ always-loaded-text sweep missed because it only reads descriptions, not error
66
+ strings and tool results. All three fixes are agent-visible wording; no wire
67
+ shape, tool surface, or policy changes. Operators who tightened
68
+ `discovery.probeTimeoutMs` also get that deadline honored inside `execute_code`,
69
+ which had been probing at the 30-second default no matter what was configured.
70
+
71
+ ### Added
72
+
73
+ - **`connecta.emit(block)` inside `execute_code`.** Strictly validated
74
+ `text` / `image` / `audio` blocks, collected host-side and appended to the
75
+ result after the JSON envelope on success only; a failed program discards
76
+ them visibly (`emittedDiscarded`). Budgets fail loudly at the emit call and
77
+ spend no host-call budget.
78
+ - **`ConnectaConfig.execute.maxEmittedBytes` / `.maxEmittedBlocks`.** The
79
+ emission budgets, defaulting to 4,000,000 serialized bytes and 32 blocks per
80
+ run.
81
+ - **`diagnostics.emitted`.** With `diagnostics: true`, one payload-free
82
+ aggregate (block count and serialized bytes) when a program emitted.
83
+ - **Local routing failures carry structured recovery.** Unknown addresses and
84
+ tools suggest scoped discovery, read-path policy refusals preserve the
85
+ canonical address for `call_destructive_tool` — with the original arguments
86
+ when they fit a 512-byte echo budget, and an instruction to re-send them when
87
+ they do not — and ambiguous code-mode aliases list every canonical
88
+ `connecta.call` candidate. The suggested discovery route follows the caller's
89
+ own surface: `search_tools` for a top-level call, `connecta.search` with the
90
+ same arguments for a miss inside `execute_code`, which cannot call a tool.
91
+ The address gets the same 512-byte budget as the argument echo but the
92
+ opposite rule — clamped with a `…` marker rather than dropped, since the
93
+ address is the thing being corrected. Short addresses, which is all real
94
+ ones, come back exact.
95
+ - **Destructive calls accept explanatory context.** An optional `reason` of at
96
+ most 500 characters gives the MCP host human-readable intent without entering
97
+ downstream arguments or granting authority. An empty or whitespace-only one
98
+ is treated as absent rather than failing the call.
99
+ - **Activity exposes coarse agent friction.** Typed codes derive
100
+ `tool_not_found`, `schema_retry`, `destructive_reroute`, `auth_required`, or
101
+ `result_too_large`; no payload or raw error text is added.
102
+
103
+ ### Changed
104
+
105
+ - **Paged results name the exact next call.** `call_tool` and `batch_call`
106
+ truncation notices include `get_result` arguments with the generated id and
107
+ byte offset zero. Program results and oversized discovery responses still
108
+ carry no `get_result` route: paging a program's return value is refused by
109
+ design, and a program can shrink anything.
110
+ - **`nextAction` is a wider union than it was.** `search_tools` routes may now
111
+ omit `arguments.connector` (an unknown *connector* cannot scope discovery to
112
+ itself), the ambiguous-alias route is keyed `function: "connecta.call"` with
113
+ no `tool` at all, and in-program discovery recovery is keyed
114
+ `function: "connecta.search"` carrying the same `{ query, connector?,
115
+ includeSchemas }` arguments the tool route does. A consumer that narrowed on
116
+ `nextAction.tool` must handle the function-keyed shapes too.
117
+ - **An address that resolves to nothing is now recorded.** A call to a
118
+ connector id that does not exist emits one activity event at the address as
119
+ written, with `unknown_address` and `tool_not_found` friction — provided the
120
+ address splits into the `<connectorId>.<toolName>` shape activity keeps; one
121
+ with no interior dot still records nothing. Previously the single most common
122
+ address mistake left no trace at all. Addresses were already a first-class
123
+ activity field; nothing new is retained. Because those fields now hold
124
+ caller-authored text, the recording seam clamps `connectorId` and `toolName`
125
+ at 128 UTF-8 bytes each and `address` at 257, marked with `…` — far past any
126
+ real id, far short of an invented 40 KB one.
127
+ - **A truncated result is friction, not an error.** An oversized result reports
128
+ `friction: "result_too_large"` on an `outcome: "success"` event and writes no
129
+ `errorCode`, so consumers counting error codes stop counting truncated
130
+ successes as failures. The Worker D1 example gains a `friction` column;
131
+ existing tables need `ALTER TABLE tool_call_activity ADD COLUMN friction
132
+ TEXT` before deploying it.
133
+
134
+ ### Fixed
135
+
136
+ - **Discovery errors stay on their advertised surface.** The over-100-address
137
+ rejection and the catalog-probe timeout label now name `describe_tools` or
138
+ `connecta.describe` according to the route the caller actually took, so a
139
+ program is never told to split its list across a tool it cannot call. The
140
+ route is passed in explicitly rather than inferred from the deployment's
141
+ surface: a classic deployment with an executor serves `describe_tools` at top
142
+ level while every in-program describe still arrives through
143
+ `connecta.describe`.
144
+ - **The OAuth handoff points at a check the caller can run.** `authorize_connector`
145
+ is registered on both surfaces, but its success instructions told every agent
146
+ to "re-run `list_connectors`" — a tool the code-first surface folded away. A
147
+ code-first deployment is now told to retry the original call and confirm the
148
+ catalog loads with `connecta.search` inside `execute_code`; the classic
149
+ wording is unchanged.
150
+ - **`discovery.probeTimeoutMs` reaches code mode.** The sandbox's catalog
151
+ service received the deployment's discovery concurrency but not its probe
152
+ deadline, so an in-program `connecta.describe` against a hung connector waited
153
+ the 30-second default regardless of operator configuration.
154
+
5
155
  ## 0.10.5 — 2026-07-30
6
156
 
7
157
  A consumer-audit recovery release. Schema discovery now provides the bounded
package/README.md CHANGED
@@ -69,7 +69,8 @@ my-connecta/
69
69
  For an agent setting this up, the contract is:
70
70
 
71
71
  1. Edit `src/index.ts`; do not copy Connecta internals into the deployment.
72
- 2. Keep `executor: quickJsExecutor()` for the prescribed seven-tool surface.
72
+ 2. Keep the required `executor: quickJsExecutor()` configuration; without an
73
+ executor the deployment refuses to boot.
73
74
  3. Keep secrets in environment variables or a secret store, never source.
74
75
  4. Add code only for deliberate `api()` connectors.
75
76
  5. Run `npm run typecheck`, start the server, and run
@@ -92,9 +93,9 @@ Other supported deployment shapes:
92
93
  - [Cloudflare Worker deployment](./examples/worker/)
93
94
  - [Subsystem documentation](./documentation/)
94
95
 
95
- Configuring a sandbox QuickJS on Node or a Dynamic Worker on Cloudflare — is
96
- what selects the code-first surface and is the assumed posture. A deployment
97
- without one keeps the earlier nine-tool compatibility interface.
96
+ Every deployment configures a sandbox: QuickJS on Node or a Dynamic Worker on
97
+ Cloudflare. Construction fails with an actionable error when the executor is
98
+ missing, so the model-facing interface is always the same seven tools.
98
99
 
99
100
  ## Project status
100
101
 
package/bin/connecta.mjs CHANGED
@@ -186,13 +186,6 @@ async function doctor() {
186
186
  if (health.status !== "ok") {
187
187
  throw new Error(`Unexpected health status: ${String(health.status)}`);
188
188
  }
189
- if (health.admission?.code === null) {
190
- throw new Error(
191
- "The server has no executor and is serving classic compatibility. " +
192
- "Keep executor: quickJsExecutor() for the prescribed surface.",
193
- );
194
- }
195
-
196
189
  let requestId = 0;
197
190
  const mcp = async (method, params) =>
198
191
  jsonResponse(
@@ -1,6 +1,9 @@
1
1
  import type { Logger } from "./types.js";
2
2
  export type ActivityCallSource = "call_tool" | "call_destructive_tool" | "batch_call" | "execute_code";
3
3
  export type ActivityOutcome = "success" | "error" | "timeout" | "cancelled";
4
+ export type AgentFriction = "tool_not_found" | "schema_retry" | "destructive_reroute" | "auth_required" | "result_too_large";
5
+ /** Coarse recovery class derived without inspecting payloads or error prose. */
6
+ export declare function agentFrictionForCode(code: string | undefined): AgentFriction | undefined;
4
7
  /**
5
8
  * Authenticated identity attached to an activity event. `id` is intentionally
6
9
  * optional: open deployments and shared bearer tokens cannot honestly identify
@@ -36,7 +39,14 @@ export interface ToolCallActivityEvent {
36
39
  outcome: ActivityOutcome;
37
40
  durationMs: number;
38
41
  attempts: number;
42
+ /** Set only when the call actually failed; a truncated success has none. */
39
43
  errorCode?: string;
44
+ /**
45
+ * Payload-free recovery class. Usually derived from `errorCode`, but it can
46
+ * also stand alone: a result too large to return inline is friction for the
47
+ * agent while remaining an `outcome: "success"` call with no error code.
48
+ */
49
+ friction?: AgentFriction;
40
50
  serverName: string;
41
51
  serverVersion: string;
42
52
  deploymentId?: string;
@@ -89,7 +99,7 @@ export interface ActivityRequestContext {
89
99
  defer?: (promise: Promise<unknown>) => void;
90
100
  logger: Logger;
91
101
  }
92
- export type ActivityEventInput = Pick<ToolCallActivityEvent, "connectorId" | "toolName" | "address" | "source" | "outcome" | "durationMs" | "attempts" | "errorCode">;
102
+ export type ActivityEventInput = Pick<ToolCallActivityEvent, "connectorId" | "toolName" | "address" | "source" | "outcome" | "durationMs" | "attempts" | "errorCode" | "friction">;
93
103
  /**
94
104
  * Best-effort by design: activity storage can never change a tool result.
95
105
  * Workers attach async sinks to waitUntil; synchronous sinks such as Analytics
@@ -1 +1 @@
1
- {"version":3,"file":"activity.d.ts","sourceRoot":"","sources":["../src/activity.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"activity.d.ts","sourceRoot":"","sources":["../src/activity.ts"],"names":[],"mappings":"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"}
package/dist/activity.js CHANGED
@@ -1,3 +1,40 @@
1
+ import { boundedEchoText } from "./errors.js";
2
+ /**
3
+ * How long an identity field may be before the store stops believing it.
4
+ *
5
+ * `connectorId` and `toolName` are ordinarily operator- and connector-authored,
6
+ * and 128 bytes is far past any real one. But an address that resolved to
7
+ * nothing is recorded *as written*, which puts a caller-authored string in both
8
+ * fields — and "payload-free by construction" has to mean the event type has
9
+ * nowhere to put a payload, not merely that connecta declines to. A 40 KB
10
+ * invented connector id is a payload wearing an id's clothing.
11
+ *
12
+ * Clamped rather than dropped: the invented id is precisely what an operator
13
+ * needs to see, and its first 128 bytes identify the mistake as well as all
14
+ * 40,000 would. The `…` marker keeps a clamped value from reading as a real one.
15
+ */
16
+ const MAX_ACTIVITY_NAME_BYTES = 128;
17
+ /** Two names and the dot between them. */
18
+ const MAX_ACTIVITY_ADDRESS_BYTES = MAX_ACTIVITY_NAME_BYTES * 2 + 1;
19
+ /** Coarse recovery class derived without inspecting payloads or error prose. */
20
+ export function agentFrictionForCode(code) {
21
+ switch (code) {
22
+ case "unknown_address":
23
+ case "unknown_tool":
24
+ case "ambiguous_tool_alias":
25
+ return "tool_not_found";
26
+ case "invalid_args":
27
+ return "schema_retry";
28
+ case "destructive_tool_requires_approval":
29
+ return "destructive_reroute";
30
+ case "auth_required":
31
+ return "auth_required";
32
+ case "result_too_large":
33
+ return "result_too_large";
34
+ default:
35
+ return undefined;
36
+ }
37
+ }
1
38
  /** Reader implementations throw this for an opaque cursor they cannot decode. */
2
39
  export class InvalidActivityCursorError extends Error {
3
40
  name = "InvalidActivityCursorError";
@@ -13,20 +50,24 @@ export class InvalidActivityCursorError extends Error {
13
50
  export function recordToolActivity(context, input) {
14
51
  if (!context)
15
52
  return;
53
+ // A caller-supplied class wins because it knows something the code table
54
+ // cannot: friction that belongs to a call which did not fail.
55
+ const friction = input.friction ?? agentFrictionForCode(input.errorCode);
16
56
  const event = {
17
57
  schemaVersion: 1,
18
58
  id: crypto.randomUUID(),
19
59
  occurredAt: new Date().toISOString(),
20
60
  requestId: context.requestId,
21
61
  actor: context.actor,
22
- connectorId: input.connectorId,
23
- toolName: input.toolName,
24
- address: input.address,
62
+ connectorId: boundedEchoText(input.connectorId, MAX_ACTIVITY_NAME_BYTES),
63
+ toolName: boundedEchoText(input.toolName, MAX_ACTIVITY_NAME_BYTES),
64
+ address: boundedEchoText(input.address, MAX_ACTIVITY_ADDRESS_BYTES),
25
65
  source: input.source,
26
66
  outcome: input.outcome,
27
67
  durationMs: Math.max(0, Math.trunc(input.durationMs)),
28
68
  attempts: Math.max(1, Math.trunc(input.attempts)),
29
69
  ...(input.errorCode ? { errorCode: input.errorCode } : {}),
70
+ ...(friction ? { friction } : {}),
30
71
  serverName: context.serverInfo.name,
31
72
  serverVersion: context.serverInfo.version,
32
73
  ...(context.deploymentId
@@ -1 +1 @@
1
- {"version":3,"file":"activity.js","sourceRoot":"","sources":["../src/activity.ts"],"names":[],"mappings":"AAyFA,iFAAiF;AACjF,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IAC1C,IAAI,GAAG,4BAA4B,CAAC;IAE7C;QACE,KAAK,CAAC,yBAAyB,CAAC,CAAC;IACnC,CAAC;CACF;AA6BD;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAA2C,EAC3C,KAAyB;IAEzB,IAAI,CAAC,OAAO;QAAE,OAAO;IACrB,MAAM,KAAK,GAA0B;QACnC,aAAa,EAAE,CAAC;QAChB,EAAE,EAAE,MAAM,CAAC,UAAU,EAAE;QACvB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACpC,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACrD,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACjD,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1D,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,IAAI;QACnC,aAAa,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO;QACzC,GAAG,CAAC,OAAO,CAAC,YAAY;YACtB,CAAC,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE;YACxC,CAAC,CAAC,EAAE,CAAC;KACR,CAAC;IACF,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,CAAC,MAAM,IAAI,OAAQ,MAA2B,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACvE,OAAO;QACT,CAAC;QACD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACtD,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;QACH,IAAI,OAAO,CAAC,KAAK;YAAE,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAC;IAClE,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"activity.js","sourceRoot":"","sources":["../src/activity.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,12 @@ export declare const DEFAULT_SEARCH_LIMIT = 8;
5
5
  export declare const MAX_SEARCH_LIMIT = 100;
6
6
  export declare const MAX_DESCRIBE_ADDRESSES = 100;
7
7
  export declare const MAX_DISCOVERY_RESULT_BYTES = 256000;
8
+ /**
9
+ * The discovery route a routing failure should send a caller back through. Same
10
+ * catalog logic serves both the top-level `search_tools` path and the
11
+ * in-program `connecta.search` path, so callers pass the route they own.
12
+ */
13
+ export type SearchRoute = "search_tools" | "connecta.search";
8
14
  export declare class DiscoveryPolicyError extends Error {
9
15
  readonly code: "invalid_args" | "result_too_large";
10
16
  constructor(code: "invalid_args" | "result_too_large", message: string);
@@ -106,13 +112,31 @@ export declare class CatalogService {
106
112
  readonly requestScope: object;
107
113
  private readonly probeTimeoutMs;
108
114
  private readonly concurrency;
115
+ private readonly searchRoute;
109
116
  private readonly loaded;
110
117
  private readonly loading;
111
118
  constructor(registry: RegistryView, baseUrl: string, options?: {
112
119
  requestScope?: object;
113
120
  probeTimeoutMs?: number;
114
121
  concurrency?: number;
122
+ /** The discovery route recovery records name. Default `search_tools`. */
123
+ searchRoute?: SearchRoute;
115
124
  });
125
+ /**
126
+ * Send a caller back to discovery through the surface it can actually reach.
127
+ * Both variants carry the same scoping arguments because `connecta.search`
128
+ * takes the same ones `search_tools` does; only the key naming the callable
129
+ * differs, the way the ambiguous-alias record already names a function.
130
+ *
131
+ * Not private: `InvocationService` builds the same class of record when a
132
+ * call fails schema validation, and it is this catalog's route that decides
133
+ * which key that record carries. Duplicating the branch there would let the
134
+ * two drift.
135
+ */
136
+ searchRecovery(args: {
137
+ query: string;
138
+ connector?: string;
139
+ }, purpose: string): NonNullable<CallErrorDetails["nextAction"]>;
116
140
  loadConnector(id: string, callOptions?: ConnectorOperationOptions): Promise<ToolDef[]>;
117
141
  private loadForDiscovery;
118
142
  resolveTool(address: string, callOptions?: ConnectorOperationOptions): Promise<CatalogResolution>;
@@ -1 +1 @@
1
- {"version":3,"file":"catalog-service.d.ts","sourceRoot":"","sources":["../src/catalog-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"catalog-service.d.ts","sourceRoot":"","sources":["../src/catalog-service.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EACV,yBAAyB,EACzB,YAAY,EACb,MAAM,eAAe,CAAC;AAWvB,OAAO,KAAK,EACV,SAAS,EAET,OAAO,EACR,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,oBAAoB,IAAI,CAAC;AACtC,eAAO,MAAM,gBAAgB,MAAM,CAAC;AACpC,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,eAAO,MAAM,0BAA0B,SAAU,CAAC;AAMlD;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,cAAc,GAAG,iBAAiB,CAAC;AAE7D,qBAAa,oBAAqB,SAAQ,KAAK;IAE3C,QAAQ,CAAC,IAAI,EAAE,cAAc,GAAG,kBAAkB;gBAAzC,IAAI,EAAE,cAAc,GAAG,kBAAkB,EAClD,OAAO,EAAE,MAAM;CAKlB;AA8DD,2EAA2E;AAC3E,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAazE;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,MAAM,CAAC,EAAE,UAAU,GAAG,kBAAkB,GAAG,KAAK,CAAC;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IACpC,kFAAkF;IAClF,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AA+BD,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,UAAU,kBAAkB;IAC1B,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,oBAAoB,CAAC,EAAE,IAAI,CAAC;QAC5B,qBAAqB,CAAC,EAAE,IAAI,CAAC;QAC7B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;QACrB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;QAC7B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,WAAW,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;KACtC,CAAC;CACH;AA4BD,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,aAAa,CAAC,EAAE;QACd,gBAAgB,EAAE,MAAM,EAAE,CAAC;QAC3B,gBAAgB,EAAE,MAAM,EAAE,CAAC;QAC3B,cAAc,EAAE,MAAM,EAAE,CAAC;QACzB,SAAS,CAAC,EAAE,IAAI,CAAC;QACjB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,gBAAgB,CAAC,EAAE,IAAI,CAAC;QACxB,yBAAyB,CAAC,EAAE,MAAM,CAAC;QACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,MAAM,iBAAiB,GACzB;IACE,EAAE,EAAE,IAAI,CAAC;IACT,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;CACnB,GACD;IACE,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,gBAAgB,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAeN;;;;GAIG;AACH,qBAAa,cAAc;IASvB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM;IAT1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgC;IACvD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyC;gBAG9C,QAAQ,EAAE,YAAY,EAC9B,OAAO,EAAE,MAAM,EACxB,OAAO,GAAE;QACP,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,yEAAyE;QACzE,WAAW,CAAC,EAAE,WAAW,CAAC;KACtB;IASR;;;;;;;;;;OAUG;IACH,cAAc,CACZ,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,EAC3C,OAAO,EAAE,MAAM,GACd,WAAW,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC;IAWxC,aAAa,CACjB,EAAE,EAAE,MAAM,EACV,WAAW,GAAE,yBAA8B,GAC1C,OAAO,CAAC,OAAO,EAAE,CAAC;IAkBrB,OAAO,CAAC,gBAAgB;IAYlB,WAAW,CACf,OAAO,EAAE,MAAM,EACf,WAAW,GAAE,yBAA8B,GAC1C,OAAO,CAAC,iBAAiB,CAAC;IAiE7B;;;;OAIG;IACG,gBAAgB,CACpB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,EACtC,WAAW,GAAE,yBAA8B,GAC1C,OAAO,CAAC,iBAAiB,CAAC;IAwFvB,MAAM,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IA+O3D,QAAQ,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;CA0EzE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB;;0BAlnBrC,MAAM,EAAE;0BACR,MAAM,EAAE;wBACV,MAAM,EAAE;oBACZ,IAAI;yBACC,MAAM;2BACJ,IAAI;oCACK,MAAM;mBACvB,MAAM;;;;;YA6mBb,MAAM;gBACF,MAAM;gBACN,MAAM;eACP,kBAAkB,CAAC,MAAM,CAAC,EAAE;;;;;;EA6BtC;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,iBAAiB;;0BAtpBlC,MAAM,EAAE;0BACR,MAAM,EAAE;wBACV,MAAM,EAAE;oBACZ,IAAI;yBACC,MAAM;2BACJ,IAAI;oCACK,MAAM;mBACvB,MAAM;;;;;;cAxDX,MAAM;iBACH,MAAM;sBACD,MAAM;sBACN,OAAO;uBACN,OAAO;+BACC,IAAI;gCACH,IAAI;oBAChB,MAAM,EAAE;4BACA,MAAM,EAAE;qBACf,MAAM,EAAE;sBACP,OAAO,CAAC,aAAa,CAAC;;;;;;EA2sBvC"}
@@ -1,6 +1,6 @@
1
1
  import { compactDiscoverySchema, compactSchema, lexicalCorpusStatistics, lexicalQueryTerms, lexicalSearchQuery, rankTools, schemaObjectKeys, summarizeDiscoveryDescription, summarizeDescription, } from "./catalog.js";
2
2
  import { mapSettledWithConcurrency, resolveDiscoveryConcurrency, } from "./concurrency.js";
3
- import { classifyCallError, framingError } from "./errors.js";
3
+ import { boundedEchoText, classifyCallError, framingError, } from "./errors.js";
4
4
  import { connectorGuide, connectorSkillName, } from "./skills.js";
5
5
  import { DEFAULT_PROBE_TIMEOUT_MS, normalizeTimeoutMs, withAbortableTimeout, } from "./timeout.js";
6
6
  import { isExplicitlyReadOnly } from "./tool-safety.js";
@@ -45,10 +45,21 @@ function discoveryAddresses(args) {
45
45
  throw new DiscoveryPolicyError("invalid_args", 'describe takes { address: "<connectorId>.<toolName>" } or { addresses: ["<connectorId>.<toolName>", ...] }.');
46
46
  }
47
47
  if (value.length > MAX_DESCRIBE_ADDRESSES) {
48
- throw new DiscoveryPolicyError("invalid_args", `addresses must contain at most ${MAX_DESCRIBE_ADDRESSES} entries. Split a larger list across describe_tools calls.`);
48
+ throw new DiscoveryPolicyError("invalid_args", `addresses must contain at most ${MAX_DESCRIBE_ADDRESSES} entries. Split a larger list across connecta.describe calls.`);
49
49
  }
50
50
  return value;
51
51
  }
52
+ /**
53
+ * Search terms derived from an address the catalog could not resolve. Bounded
54
+ * because the address is entirely caller-authored: an invented one can be any
55
+ * length, and this string is copied into a recovery record that is itself
56
+ * copied into both halves of the result envelope.
57
+ */
58
+ function recoveryQuery(address) {
59
+ const separator = address.indexOf(".");
60
+ const candidate = separator >= 0 ? address.slice(separator + 1) : address;
61
+ return boundedEchoText(candidate.replaceAll(/[._-]+/g, " ").trim() || address);
62
+ }
52
63
  /** Serialize once and count the exact bytes the MCP adapter would emit. */
53
64
  export function boundedDiscoveryText(value, hint) {
54
65
  const text = JSON.stringify(value);
@@ -116,6 +127,7 @@ export class CatalogService {
116
127
  requestScope;
117
128
  probeTimeoutMs;
118
129
  concurrency;
130
+ searchRoute;
119
131
  loaded = new Map();
120
132
  loading = new Map();
121
133
  constructor(registry, baseUrl, options = {}) {
@@ -125,6 +137,28 @@ export class CatalogService {
125
137
  this.probeTimeoutMs =
126
138
  normalizeTimeoutMs(options.probeTimeoutMs) ?? DEFAULT_PROBE_TIMEOUT_MS;
127
139
  this.concurrency = resolveDiscoveryConcurrency(options.concurrency);
140
+ this.searchRoute = options.searchRoute ?? "search_tools";
141
+ }
142
+ /**
143
+ * Send a caller back to discovery through the surface it can actually reach.
144
+ * Both variants carry the same scoping arguments because `connecta.search`
145
+ * takes the same ones `search_tools` does; only the key naming the callable
146
+ * differs, the way the ambiguous-alias record already names a function.
147
+ *
148
+ * Not private: `InvocationService` builds the same class of record when a
149
+ * call fails schema validation, and it is this catalog's route that decides
150
+ * which key that record carries. Duplicating the branch there would let the
151
+ * two drift.
152
+ */
153
+ searchRecovery(args, purpose) {
154
+ const searchArgs = {
155
+ query: args.query,
156
+ ...(args.connector !== undefined ? { connector: args.connector } : {}),
157
+ includeSchemas: "compact",
158
+ };
159
+ return this.searchRoute === "connecta.search"
160
+ ? { function: "connecta.search", arguments: searchArgs, purpose }
161
+ : { tool: "search_tools", arguments: searchArgs, purpose };
128
162
  }
129
163
  async loadConnector(id, callOptions = {}) {
130
164
  const cached = this.loaded.get(id);
@@ -157,7 +191,10 @@ export class CatalogService {
157
191
  if (!resolved) {
158
192
  return {
159
193
  ok: false,
160
- error: framingError("unknown_address", `Unknown address "${address}"`),
194
+ error: {
195
+ ...framingError("unknown_address", `Unknown address "${boundedEchoText(address)}"`),
196
+ nextAction: this.searchRecovery({ query: recoveryQuery(address) }, "Find the configured canonical address before retrying."),
197
+ },
161
198
  catalogMs: 0,
162
199
  };
163
200
  }
@@ -180,7 +217,13 @@ export class CatalogService {
180
217
  if (!definition) {
181
218
  return {
182
219
  ok: false,
183
- error: framingError("unknown_tool", `Unknown tool "${resolved.toolName}" on connector "${resolved.connector.id}"`),
220
+ error: {
221
+ ...framingError("unknown_tool", `Unknown tool "${boundedEchoText(resolved.toolName)}" on connector "${resolved.connector.id}"`),
222
+ nextAction: this.searchRecovery({
223
+ query: recoveryQuery(resolved.toolName),
224
+ connector: resolved.connector.id,
225
+ }, "Find the connector's current canonical tool address."),
226
+ },
184
227
  catalogMs: Date.now() - started,
185
228
  connector: resolved.connector,
186
229
  toolName: resolved.toolName,
@@ -206,7 +249,10 @@ export class CatalogService {
206
249
  if (!connector) {
207
250
  return {
208
251
  ok: false,
209
- error: framingError("unknown_address", `Unknown address "${connectorId}.${alias}"`),
252
+ error: {
253
+ ...framingError("unknown_address", `Unknown address "${boundedEchoText(`${connectorId}.${alias}`)}"`),
254
+ nextAction: this.searchRecovery({ query: recoveryQuery(alias) }, "Find the configured canonical address before retrying."),
255
+ },
210
256
  catalogMs: 0,
211
257
  };
212
258
  }
@@ -229,7 +275,10 @@ export class CatalogService {
229
275
  if (!definition) {
230
276
  return {
231
277
  ok: false,
232
- error: framingError("unknown_tool", `Unknown tool "${alias}" on connector "${connector.id}"`),
278
+ error: {
279
+ ...framingError("unknown_tool", `Unknown tool "${boundedEchoText(alias)}" on connector "${connector.id}"`),
280
+ nextAction: this.searchRecovery({ query: recoveryQuery(alias), connector: connector.id }, "Find the connector's current canonical tool address."),
281
+ },
233
282
  catalogMs: Date.now() - started,
234
283
  connector,
235
284
  toolName: alias,
@@ -243,8 +292,13 @@ export class CatalogService {
243
292
  ok: false,
244
293
  error: {
245
294
  code: "ambiguous_tool_alias",
246
- message: `Tool alias "${alias}" is ambiguous on connector "${connector.id}" because ${names} sanitize to the same name. Use connecta.call with an exact address.`,
295
+ message: `Tool alias "${boundedEchoText(alias)}" is ambiguous on connector "${connector.id}" because ${names} sanitize to the same name. Use connecta.call with an exact address.`,
247
296
  retryable: false,
297
+ nextAction: {
298
+ function: "connecta.call",
299
+ addresses: [definition, ...collisions].map((tool) => `${connector.id}.${tool.name}`),
300
+ purpose: "Choose the intended canonical address and call it with the original arguments.",
301
+ },
248
302
  },
249
303
  catalogMs: Date.now() - started,
250
304
  connector,
@@ -275,7 +329,12 @@ export class CatalogService {
275
329
  ? [scopedConnector]
276
330
  : []
277
331
  : this.registry.listConnectors();
278
- const catalogs = await mapSettledWithConcurrency(connectors, this.concurrency, (connector) => this.loadForDiscovery(connector.id, `search_tools probe of "${connector.id}"`));
332
+ const catalogs = await mapSettledWithConcurrency(connectors, this.concurrency, (connector) =>
333
+ // Unlike the describe path, this label never reaches a caller: search
334
+ // only counts rejected catalogs (`unavailableCatalogs` below) and
335
+ // renders its own guidance, so the folded name here stays internal and
336
+ // needs no surface awareness.
337
+ this.loadForDiscovery(connector.id, `search_tools probe of "${connector.id}"`));
279
338
  const searchableCatalogs = catalogs.map((catalog) => catalog.status === "fulfilled"
280
339
  ? {
281
340
  status: "fulfilled",
@@ -469,7 +528,7 @@ export class CatalogService {
469
528
  .map((entry) => entry.resolved?.connector.id)
470
529
  .filter((id) => Boolean(id))),
471
530
  ];
472
- const loaded = await mapSettledWithConcurrency(connectorIds, this.concurrency, (id) => this.loadForDiscovery(id, `describe_tools probe of "${id}"`));
531
+ const loaded = await mapSettledWithConcurrency(connectorIds, this.concurrency, (id) => this.loadForDiscovery(id, `connecta.describe probe of "${id}"`));
473
532
  const catalogs = new Map();
474
533
  loaded.forEach((result, index) => {
475
534
  const connectorId = connectorIds[index];