@zackbart/connecta 0.24.3 → 0.25.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.
- package/AGENTS.md +58 -30
- package/CHANGELOG.md +317 -1
- package/README.md +5 -6
- package/dist/advertised-schema.js +53 -0
- package/dist/auth/downstream-oauth.js +490 -106
- package/dist/branding.d.ts +31 -2
- package/dist/branding.js +116 -8
- package/dist/call-admission.js +139 -113
- package/dist/catalog-service.js +141 -105
- package/dist/catalog.js +258 -33
- package/dist/concurrency.js +24 -23
- package/dist/connector-scope.js +6 -37
- package/dist/connectors/api.d.ts +3 -3
- package/dist/connectors/api.js +10 -2
- package/dist/connectors/guarded-fetch.js +34 -4
- package/dist/connectors/remote-mcp.d.ts +6 -5
- package/dist/connectors/remote-mcp.js +325 -245
- package/dist/credential-contract.d.ts +9 -0
- package/dist/credential-rules.js +2 -2
- package/dist/credentials.d.ts +6 -1
- package/dist/credentials.js +45 -3
- package/dist/errors.d.ts +11 -3
- package/dist/errors.js +2 -1
- package/dist/execute.js +363 -257
- package/dist/executor-admission.js +67 -50
- package/dist/executors/quickjs-runtime.js +4 -2
- package/dist/executors/quickjs.js +251 -210
- package/dist/fix-prompt.js +37 -0
- package/dist/index.d.ts +11 -2
- package/dist/index.js +63 -21
- package/dist/invocation.js +324 -285
- package/dist/meta-tools.js +304 -114
- package/dist/oauth-callback-outcome.js +94 -0
- package/dist/oauth-sealing.js +29 -0
- package/dist/operator-ui/fix-prompts.js +87 -0
- package/dist/operator-ui/generated.js +2 -2
- package/dist/operator-ui/model.d.ts +46 -1
- package/dist/operator-ui/setup-commands.js +53 -0
- package/dist/operator-ui/view.js +109 -2
- package/dist/program-source.js +205 -0
- package/dist/providers/cloudflare.d.ts +14 -2
- package/dist/providers/cloudflare.js +107 -16
- package/dist/providers/linear.d.ts +26 -4
- package/dist/providers/linear.js +19 -4
- package/dist/providers/mixpanel.d.ts +16 -3
- package/dist/providers/mixpanel.js +13 -2
- package/dist/providers/notion.d.ts +8 -1
- package/dist/providers/notion.js +85 -12
- package/dist/providers/revenuecat.d.ts +30 -4
- package/dist/providers/revenuecat.js +70 -5
- package/dist/providers/stripe.d.ts +10 -3
- package/dist/providers/stripe.js +30 -4
- package/dist/providers/vercel.js +12 -2
- package/dist/registry.d.ts +13 -5
- package/dist/registry.js +317 -258
- package/dist/routes/activity.js +120 -137
- package/dist/routes/credentials.js +174 -163
- package/dist/routes/mcp.js +129 -70
- package/dist/routes/oauth-management.js +60 -71
- package/dist/routes/oauth.js +44 -16
- package/dist/routes/operator.js +82 -0
- package/dist/routes/shared.d.ts +2 -0
- package/dist/routes/ui-data.js +210 -0
- package/dist/routes/ui.js +64 -32
- package/dist/runtime/admission.js +43 -0
- package/dist/runtime/call-admission.js +67 -0
- package/dist/runtime/connector-scope.js +72 -0
- package/dist/runtime/run.js +174 -0
- package/dist/runtime/services.js +130 -0
- package/dist/runtime/storage.js +66 -0
- package/dist/server.js +111 -89
- package/dist/skills.js +1 -1
- package/dist/storage/file.js +39 -2
- package/dist/storage/memory.js +28 -16
- package/dist/timeout.js +17 -47
- package/dist/types.d.ts +64 -7
- package/dist/ui.d.ts +16 -2
- package/dist/ui.js +68 -176
- package/dist/url-safety.js +157 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/architecture.md +368 -182
- package/documentation/auth.md +277 -176
- package/documentation/code-mode.md +479 -329
- package/documentation/meta-tools.md +494 -417
- package/ethos.md +44 -47
- package/examples/worker/AGENTS.md +2 -1
- package/examples/worker/README.md +62 -14
- package/examples/worker/src/d1-storage.ts +116 -0
- package/examples/worker/src/index.ts +18 -21
- package/examples/worker/wrangler.jsonc +16 -4
- package/package.json +11 -4
- package/templates/node/.env.example +3 -3
- package/templates/node/AGENTS.md +5 -4
- package/templates/node/README.md +2 -1
- package/templates/node/package.json +1 -1
- package/templates/node/src/index.ts +23 -22
- package/dist/auth/downstream-oauth.d.ts +0 -200
- package/dist/catalog-fingerprint.d.ts +0 -19
- package/dist/catalog-limits.d.ts +0 -9
- package/dist/catalog-service.d.ts +0 -263
- package/dist/catalog.d.ts +0 -87
- package/dist/concurrency.d.ts +0 -3
- package/dist/connectors/guarded-fetch.d.ts +0 -92
- package/dist/credential-rules.d.ts +0 -85
- package/dist/execute.d.ts +0 -154
- package/dist/executor-result.d.ts +0 -10
- package/dist/executors/quickjs-child.d.ts +0 -1
- package/dist/executors/quickjs-protocol.d.ts +0 -67
- package/dist/favicon.d.ts +0 -1
- package/dist/identity.d.ts +0 -4
- package/dist/invocation.d.ts +0 -74
- package/dist/mcp-result.d.ts +0 -8
- package/dist/meta-tools.d.ts +0 -129
- package/dist/operator-ui/generated.d.ts +0 -2
- package/dist/operator-ui/view.d.ts +0 -151
- package/dist/result-shapes.d.ts +0 -13
- package/dist/retired-toolkits.d.ts +0 -2
- package/dist/routes/activity.d.ts +0 -2
- package/dist/routes/credentials.d.ts +0 -2
- package/dist/routes/mcp.d.ts +0 -10
- package/dist/routes/oauth-management.d.ts +0 -2
- package/dist/routes/oauth.d.ts +0 -2
- package/dist/routes/ui.d.ts +0 -2
- package/dist/server.d.ts +0 -9
- package/dist/skills.d.ts +0 -44
- package/dist/timeout.d.ts +0 -21
- package/dist/tool-safety.d.ts +0 -9
- package/documentation/call-admission.md +0 -158
- package/documentation/cloudflare.md +0 -471
- package/documentation/connector-guides.md +0 -176
- package/documentation/connectors.md +0 -431
- package/documentation/linear.md +0 -193
- package/documentation/mixpanel.md +0 -160
- package/documentation/notion.md +0 -308
- package/documentation/operations.md +0 -359
- package/documentation/operator-ui.md +0 -135
- package/documentation/optional-modules-upgrade.md +0 -243
- package/documentation/provider-conventions.md +0 -729
- package/documentation/request-admission.md +0 -204
- package/documentation/revenuecat.md +0 -305
- package/documentation/storage-and-credentials.md +0 -254
- package/documentation/stripe.md +0 -262
- package/documentation/upgrading.md +0 -768
- package/documentation/vercel.md +0 -241
package/dist/catalog-service.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Deferred, Effect, Exit, Result } from "effect";
|
|
2
|
+
import { compactDiscoverySchema, compactDescriptionSchema, lexicalCorpusStatistics, lexicalQueryTerms, lexicalSearchQuery, matchesLexicalTerm, rankTools, schemaObjectKeys, summarizeDiscoveryDescription, summarizeDescription, typescriptSignature, } from "./catalog.js";
|
|
3
|
+
import { resolveDiscoveryConcurrency } from "./concurrency.js";
|
|
3
4
|
import { boundedEchoText, classifyCallError, framingError, } from "./errors.js";
|
|
4
5
|
import { connectorGuide, connectorGuideRequired, connectorGuideSummary, connectorSkillName, } from "./skills.js";
|
|
5
|
-
import {
|
|
6
|
+
import { runEdge, withDeadlineEffect } from "./runtime/run.js";
|
|
7
|
+
import { DEFAULT_PROBE_TIMEOUT_MS, normalizeTimeoutMs, } from "./timeout.js";
|
|
6
8
|
import { isExplicitlyReadOnly } from "./tool-safety.js";
|
|
7
9
|
export const DEFAULT_SEARCH_LIMIT = 8;
|
|
8
10
|
export const MAX_SEARCH_LIMIT = 100;
|
|
@@ -199,8 +201,20 @@ export class CatalogService {
|
|
|
199
201
|
concurrency;
|
|
200
202
|
searchRoute;
|
|
201
203
|
readOptions;
|
|
202
|
-
|
|
203
|
-
|
|
204
|
+
requestSignal;
|
|
205
|
+
// The request-scoped catalog cache: one Deferred per connector asked about,
|
|
206
|
+
// completed by the first asker's registry read and joined by every later
|
|
207
|
+
// one. A success stays for the rest of the request, so a search and the call
|
|
208
|
+
// after it see one catalog; a failure is dropped so the next ask reads
|
|
209
|
+
// again. The service lives and dies with one request, so no Deferred here is
|
|
210
|
+
// ever awaited from another.
|
|
211
|
+
//
|
|
212
|
+
// Registry.getTools also joins concurrent reads in one request scope, which
|
|
213
|
+
// the operator UI and status reads rely on. This map overlaps it only for
|
|
214
|
+
// reads still in flight and is kept for what the registry's cannot do: hold
|
|
215
|
+
// the success for the rest of the request, recorded by the read itself
|
|
216
|
+
// rather than by an asker, whose probe deadline may have ended its wait.
|
|
217
|
+
catalogs = new Map();
|
|
204
218
|
constructor(registry, baseUrl, options = {}) {
|
|
205
219
|
this.registry = registry;
|
|
206
220
|
this.baseUrl = baseUrl;
|
|
@@ -209,6 +223,7 @@ export class CatalogService {
|
|
|
209
223
|
normalizeTimeoutMs(options.probeTimeoutMs) ?? DEFAULT_PROBE_TIMEOUT_MS;
|
|
210
224
|
this.concurrency = resolveDiscoveryConcurrency(options.concurrency);
|
|
211
225
|
this.searchRoute = options.searchRoute ?? "search_tools";
|
|
226
|
+
this.requestSignal = options.requestSignal;
|
|
212
227
|
this.readOptions = options.defer
|
|
213
228
|
? {
|
|
214
229
|
defer: options.defer,
|
|
@@ -237,34 +252,45 @@ export class CatalogService {
|
|
|
237
252
|
? { function: "connecta.search", arguments: searchArgs, purpose }
|
|
238
253
|
: { tool: "search_tools", arguments: searchArgs, purpose };
|
|
239
254
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
this.
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
.
|
|
254
|
-
|
|
255
|
-
|
|
255
|
+
loadConnector(id, callOptions = {}) {
|
|
256
|
+
return runEdge(this.catalog(id, callOptions));
|
|
257
|
+
}
|
|
258
|
+
// One connector's catalog from the request-scoped cache, reading it through
|
|
259
|
+
// the registry when this request has not yet. The first asker's options
|
|
260
|
+
// govern the read and a joiner shares its outcome, as the registry's own
|
|
261
|
+
// flight below does. The read settles the Deferred itself, not the asker's
|
|
262
|
+
// fiber, so a probe deadline ends one asker's wait and never the read.
|
|
263
|
+
catalog(id, callOptions) {
|
|
264
|
+
return Effect.suspend(() => {
|
|
265
|
+
const cached = this.catalogs.get(id);
|
|
266
|
+
if (cached)
|
|
267
|
+
return Deferred.await(cached);
|
|
268
|
+
const read = Deferred.makeUnsafe();
|
|
269
|
+
this.catalogs.set(id, read);
|
|
270
|
+
// The executor turns a synchronous throw from getTools into a rejection.
|
|
271
|
+
new Promise((resolve) => resolve(this.registry.getTools(id, this.baseUrl, this.requestScope, callOptions, this.readOptions))).then((tools) => {
|
|
272
|
+
Deferred.doneUnsafe(read, Exit.succeed(tools));
|
|
273
|
+
}, (cause) => {
|
|
274
|
+
// Evicted before the Deferred resumes anyone, so an asker that
|
|
275
|
+
// retries on hearing of the failure starts a fresh read.
|
|
276
|
+
if (this.catalogs.get(id) === read)
|
|
277
|
+
this.catalogs.delete(id);
|
|
278
|
+
Deferred.doneUnsafe(read, Exit.fail(cause));
|
|
279
|
+
});
|
|
280
|
+
return Deferred.await(read);
|
|
256
281
|
});
|
|
257
|
-
this.loading.set(id, loading);
|
|
258
|
-
return loading;
|
|
259
282
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
283
|
+
// Every named catalog under its own probe deadline, `concurrency` at a time,
|
|
284
|
+
// each settling in its input slot: an unavailable catalog is a Failure
|
|
285
|
+
// there, not a failed discovery. `route` names the surface in a timeout.
|
|
286
|
+
// A probe also ends with its request, so no listing outlives the caller
|
|
287
|
+
// that asked for it.
|
|
288
|
+
discoveryCatalogs(ids, route) {
|
|
289
|
+
return Effect.forEach(ids, (id) => Effect.result(withDeadlineEffect((signal) => this.catalog(id, { signal, timeoutMs: this.probeTimeoutMs }), {
|
|
290
|
+
...(this.requestSignal ? { signal: this.requestSignal } : {}),
|
|
265
291
|
timeoutMs: this.probeTimeoutMs,
|
|
266
|
-
timeoutError: new Error(`${
|
|
267
|
-
});
|
|
292
|
+
timeoutError: new Error(`${route} probe of "${id}" timed out after ${this.probeTimeoutMs}ms`),
|
|
293
|
+
})), { concurrency: this.concurrency });
|
|
268
294
|
}
|
|
269
295
|
outputSchema(connectorId, tool) {
|
|
270
296
|
if (tool.outputSchema)
|
|
@@ -306,32 +332,35 @@ export class CatalogService {
|
|
|
306
332
|
toolName,
|
|
307
333
|
};
|
|
308
334
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
+
resolveTool(address, callOptions = {}) {
|
|
336
|
+
return runEdge(this.resolve(address, callOptions));
|
|
337
|
+
}
|
|
338
|
+
// resolveTool without the Promise, for InvocationService's pipeline, which
|
|
339
|
+
// yields it inside the call's deadline rather than crossing an edge. Never
|
|
340
|
+
// fails: an unloadable catalog is a resolution like any other refusal.
|
|
341
|
+
resolve(address, callOptions = {}) {
|
|
342
|
+
return Effect.suspend(() => {
|
|
343
|
+
const resolved = this.registry.resolveAddress(address);
|
|
344
|
+
if (!resolved) {
|
|
345
|
+
return Effect.succeed(this.unknownAddressFailure(address, address));
|
|
346
|
+
}
|
|
347
|
+
const { connector, toolName } = resolved;
|
|
348
|
+
const started = Date.now();
|
|
349
|
+
return Effect.match(this.catalog(connector.id, callOptions), {
|
|
350
|
+
onFailure: (cause) => this.catalogLoadFailure(cause, started, connector, toolName),
|
|
351
|
+
onSuccess: (tools) => {
|
|
352
|
+
const definition = tools.find((tool) => tool.name === toolName);
|
|
353
|
+
if (!definition) {
|
|
354
|
+
return this.unknownToolFailure(toolName, connector, started);
|
|
355
|
+
}
|
|
356
|
+
return {
|
|
357
|
+
ok: true,
|
|
358
|
+
resolved: { connector, toolName, definition },
|
|
359
|
+
catalogMs: Date.now() - started,
|
|
360
|
+
};
|
|
361
|
+
},
|
|
362
|
+
});
|
|
363
|
+
});
|
|
335
364
|
}
|
|
336
365
|
async search(args) {
|
|
337
366
|
if (args.query !== undefined && typeof args.query !== "string") {
|
|
@@ -361,21 +390,14 @@ export class CatalogService {
|
|
|
361
390
|
? [scopedConnector]
|
|
362
391
|
: []
|
|
363
392
|
: this.registry.listConnectors();
|
|
364
|
-
|
|
365
|
-
//
|
|
366
|
-
//
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
this.loadForDiscovery(connector.id, `search_tools probe of "${connector.id}"`));
|
|
370
|
-
const searchableCatalogs = catalogs.map((catalog) => catalog.status === "fulfilled"
|
|
371
|
-
? {
|
|
372
|
-
status: "fulfilled",
|
|
373
|
-
value: toolsForSafety(catalog.value, safety),
|
|
374
|
-
}
|
|
375
|
-
: catalog);
|
|
393
|
+
// Named for this service's route: a scoped search echoes a timed-out
|
|
394
|
+
// probe's message back as `queryAnalysis.catalogError`, and a program
|
|
395
|
+
// cannot call search_tools.
|
|
396
|
+
const catalogs = await runEdge(this.discoveryCatalogs(connectors.map((connector) => connector.id), this.searchRoute));
|
|
397
|
+
const searchableCatalogs = catalogs.map((catalog) => Result.map(catalog, (tools) => toolsForSafety(tools, safety)));
|
|
376
398
|
const matches = [];
|
|
377
399
|
let matchMode = "all";
|
|
378
|
-
const statistics = lexicalCorpusStatistics(searchableCatalogs.flatMap((catalog) => catalog
|
|
400
|
+
const statistics = lexicalCorpusStatistics(searchableCatalogs.flatMap((catalog) => Result.isSuccess(catalog) ? [catalog.success] : []), retrievalQuery);
|
|
379
401
|
const trimmedQuery = query.trim();
|
|
380
402
|
const isBrowse = trimmedQuery.length === 0;
|
|
381
403
|
const queryTerms = lexicalQueryTerms(retrievalQuery);
|
|
@@ -394,8 +416,8 @@ export class CatalogService {
|
|
|
394
416
|
if (!connector) {
|
|
395
417
|
throw new Error("Catalog result has no corresponding connector");
|
|
396
418
|
}
|
|
397
|
-
if (catalog
|
|
398
|
-
for (const ranked of rankTools(catalog.
|
|
419
|
+
if (Result.isSuccess(catalog)) {
|
|
420
|
+
for (const ranked of rankTools(catalog.success, retrievalQuery, mode, statistics, query)) {
|
|
399
421
|
collected.push({
|
|
400
422
|
connector,
|
|
401
423
|
tool: ranked.tool,
|
|
@@ -407,8 +429,7 @@ export class CatalogService {
|
|
|
407
429
|
});
|
|
408
430
|
}
|
|
409
431
|
}
|
|
410
|
-
orderBase +=
|
|
411
|
-
catalog.status === "fulfilled" ? catalog.value.length : 1;
|
|
432
|
+
orderBase += Result.isSuccess(catalog) ? catalog.success.length : 1;
|
|
412
433
|
});
|
|
413
434
|
return collected;
|
|
414
435
|
};
|
|
@@ -444,12 +465,23 @@ export class CatalogService {
|
|
|
444
465
|
? this.outputSchema(match.connector.id, match.tool)
|
|
445
466
|
: {};
|
|
446
467
|
const input = match.tool.inputSchema ?? { type: "object" };
|
|
447
|
-
const
|
|
448
|
-
?
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
468
|
+
const signature = withSchemas === "typescript"
|
|
469
|
+
? typescriptSignature(input, output.schema, {
|
|
470
|
+
observed: output.source === "observed",
|
|
471
|
+
description: false,
|
|
472
|
+
})
|
|
452
473
|
: undefined;
|
|
474
|
+
const schemaFormat = withSchemas === "typescript" ? undefined : withSchemas;
|
|
475
|
+
const renderedInput = signature
|
|
476
|
+
? { schema: undefined, truncated: signature.inputTruncated }
|
|
477
|
+
: schemaFormat
|
|
478
|
+
? renderSearchSchema(input, schemaFormat)
|
|
479
|
+
: undefined;
|
|
480
|
+
const renderedOutput = signature
|
|
481
|
+
? { schema: undefined, truncated: signature.outputTruncated }
|
|
482
|
+
: schemaFormat && output.schema
|
|
483
|
+
? renderSearchSchema(output.schema, schemaFormat)
|
|
484
|
+
: undefined;
|
|
453
485
|
const schemaKeys = withSchemas && args.includeSchemaKeys
|
|
454
486
|
? schemaKeyMetadata(input, output.schema)
|
|
455
487
|
: undefined;
|
|
@@ -468,15 +500,16 @@ export class CatalogService {
|
|
|
468
500
|
name: match.tool.name,
|
|
469
501
|
address: `${match.connector.id}.${match.tool.name}`,
|
|
470
502
|
...(description !== undefined ? { description } : {}),
|
|
471
|
-
...(
|
|
503
|
+
...(schemaFormat
|
|
472
504
|
? {
|
|
473
505
|
inputSchema: renderedInput?.schema,
|
|
474
506
|
}
|
|
475
507
|
: {}),
|
|
508
|
+
...(signature ? { signature: signature.text } : {}),
|
|
476
509
|
...(renderedInput?.truncated
|
|
477
510
|
? { inputSchemaTruncated: true }
|
|
478
511
|
: {}),
|
|
479
|
-
...(
|
|
512
|
+
...(schemaFormat && output.schema
|
|
480
513
|
? {
|
|
481
514
|
outputSchema: renderedOutput?.schema,
|
|
482
515
|
}
|
|
@@ -535,16 +568,19 @@ export class CatalogService {
|
|
|
535
568
|
unmatchedTerms.push(displayTerm(term));
|
|
536
569
|
}
|
|
537
570
|
}
|
|
538
|
-
const unavailableCatalogs = catalogs.filter(
|
|
571
|
+
const unavailableCatalogs = catalogs.filter(Result.isFailure).length;
|
|
539
572
|
// Named field by field rather than spread: `CallErrorDetails` also carries
|
|
540
573
|
// connector, operation, recovery, and nextAction, and a discovery read is
|
|
541
574
|
// not a call — widening the classifier must not silently widen what a
|
|
542
575
|
// catalog search hands back.
|
|
543
576
|
const scopedCatalogError = (() => {
|
|
544
|
-
|
|
577
|
+
const scopedCatalog = catalogs[0];
|
|
578
|
+
if (!scopedConnector ||
|
|
579
|
+
!scopedCatalog ||
|
|
580
|
+
Result.isSuccess(scopedCatalog)) {
|
|
545
581
|
return undefined;
|
|
546
582
|
}
|
|
547
|
-
const error = classifyCallError(
|
|
583
|
+
const error = classifyCallError(scopedCatalog.failure, "catalog_lookup_failed");
|
|
548
584
|
return {
|
|
549
585
|
code: error.code,
|
|
550
586
|
message: boundedEchoText(error.message),
|
|
@@ -717,19 +753,8 @@ export class CatalogService {
|
|
|
717
753
|
.map((entry) => entry.resolved?.connector.id)
|
|
718
754
|
.filter((id) => Boolean(id))),
|
|
719
755
|
];
|
|
720
|
-
const loaded = await
|
|
721
|
-
const catalogs = new Map();
|
|
722
|
-
loaded.forEach((result, index) => {
|
|
723
|
-
const connectorId = connectorIds[index];
|
|
724
|
-
if (connectorId === undefined) {
|
|
725
|
-
throw new Error("Catalog result has no corresponding connector id");
|
|
726
|
-
}
|
|
727
|
-
catalogs.set(connectorId, result.status === "fulfilled"
|
|
728
|
-
? result.value
|
|
729
|
-
: result.reason instanceof Error
|
|
730
|
-
? result.reason
|
|
731
|
-
: new Error(String(result.reason)));
|
|
732
|
-
});
|
|
756
|
+
const loaded = await runEdge(this.discoveryCatalogs(connectorIds, "connecta.describe"));
|
|
757
|
+
const catalogs = new Map(connectorIds.map((id, index) => [id, loaded[index]]));
|
|
733
758
|
return resolved.map(({ address, resolved: addressResolution }) => {
|
|
734
759
|
if (!addressResolution) {
|
|
735
760
|
const message = `Unknown address "${boundedEchoText(address)}"`;
|
|
@@ -743,8 +768,8 @@ export class CatalogService {
|
|
|
743
768
|
};
|
|
744
769
|
}
|
|
745
770
|
const catalog = catalogs.get(addressResolution.connector.id);
|
|
746
|
-
if (catalog
|
|
747
|
-
const classified = classifyCallError(catalog, "catalog_lookup_failed");
|
|
771
|
+
if (catalog && Result.isFailure(catalog)) {
|
|
772
|
+
const classified = classifyCallError(catalog.failure, "catalog_lookup_failed");
|
|
748
773
|
const message = boundedEchoText(classified.message);
|
|
749
774
|
return {
|
|
750
775
|
address: boundedEchoText(address),
|
|
@@ -759,10 +784,11 @@ export class CatalogService {
|
|
|
759
784
|
},
|
|
760
785
|
};
|
|
761
786
|
}
|
|
762
|
-
const
|
|
787
|
+
const tools = catalog?.success ?? [];
|
|
788
|
+
const tool = tools.find((item) => item.name === addressResolution.toolName);
|
|
763
789
|
if (!tool) {
|
|
764
790
|
const message = `Unknown tool "${boundedEchoText(addressResolution.toolName)}" on connector "${addressResolution.connector.id}"`;
|
|
765
|
-
const suggestions = describeSuggestions(addressResolution.connector.id, addressResolution.toolName,
|
|
791
|
+
const suggestions = describeSuggestions(addressResolution.connector.id, addressResolution.toolName, tools);
|
|
766
792
|
return {
|
|
767
793
|
address: boundedEchoText(address),
|
|
768
794
|
error: message,
|
|
@@ -779,11 +805,19 @@ export class CatalogService {
|
|
|
779
805
|
const input = tool.inputSchema ?? { type: "object" };
|
|
780
806
|
const output = this.outputSchema(addressResolution.connector.id, tool);
|
|
781
807
|
const description = summarizeDescription(tool.description, args.fullDescriptions === true);
|
|
808
|
+
const signature = format === "typescript"
|
|
809
|
+
? typescriptSignature(input, output.schema, {
|
|
810
|
+
observed: output.source === "observed",
|
|
811
|
+
description: true,
|
|
812
|
+
})
|
|
813
|
+
: undefined;
|
|
782
814
|
const compactInput = format === "compact"
|
|
783
815
|
? compactDescriptionSchema(input) : undefined;
|
|
784
816
|
const compactOutput = format === "compact" && output.schema
|
|
785
817
|
? compactDescriptionSchema(output.schema) : undefined;
|
|
786
|
-
const
|
|
818
|
+
const inputTruncated = compactInput?.truncated === true || signature?.inputTruncated === true;
|
|
819
|
+
const outputTruncated = compactOutput?.truncated === true || signature?.outputTruncated === true;
|
|
820
|
+
const requiredReasons = guideRequiredReasons(addressResolution.connector, tool, inputTruncated || outputTruncated);
|
|
787
821
|
const guideSummary = connectorGuideSummary(addressResolution.connector);
|
|
788
822
|
return {
|
|
789
823
|
address,
|
|
@@ -801,10 +835,12 @@ export class CatalogService {
|
|
|
801
835
|
guideRequiredReasons: requiredReasons,
|
|
802
836
|
}
|
|
803
837
|
: {}),
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
...(
|
|
838
|
+
...(signature
|
|
839
|
+
? { signature: signature.text }
|
|
840
|
+
: { inputSchema: compactInput?.text ?? input }),
|
|
841
|
+
...(inputTruncated ? { inputSchemaTruncated: true } : {}),
|
|
842
|
+
...(outputTruncated ? { outputSchemaTruncated: true } : {}),
|
|
843
|
+
...(output.schema && !signature
|
|
808
844
|
? {
|
|
809
845
|
outputSchema: compactOutput?.text ?? output.schema,
|
|
810
846
|
}
|