@zackbart/connecta 0.41.0 → 0.42.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/CHANGELOG.md +61 -0
- package/bin/connecta.mjs +26 -17
- package/bin/meta-tool-names.d.mts +3 -1
- package/bin/meta-tool-names.mjs +4 -1
- package/bin/version.mjs +1 -1
- package/dist/activity.d.ts +2 -1
- package/dist/activity.js +5 -5
- package/dist/advertised-schema.js +15 -0
- package/dist/agent-routes.js +31 -5
- package/dist/auth/downstream-oauth/refresh-coordinator.js +4 -1
- package/dist/auth/downstream-oauth.js +3 -0
- package/dist/auth/static-oauth.js +26 -18
- package/dist/auth-elicitation.js +118 -61
- package/dist/authorization-handoff.js +36 -3
- package/dist/catalog-cache.js +292 -24
- package/dist/catalog-freshness.js +12 -0
- package/dist/catalog-service.js +373 -70
- package/dist/catalog.js +147 -58
- package/dist/config-defaults.d.ts +2 -1
- package/dist/config-defaults.js +4 -1
- package/dist/config.d.ts +43 -17
- package/dist/config.js +26 -10
- package/dist/connectors/remote-mcp/catalog.js +52 -28
- package/dist/connectors/remote-mcp/connection.js +62 -5
- package/dist/connectors/remote-mcp.js +10 -1
- package/dist/describe-config.d.ts +3 -2
- package/dist/discovery-health.js +26 -11
- package/dist/errors.d.ts +52 -3
- package/dist/errors.js +86 -3
- package/dist/execute.js +476 -200
- package/dist/executor-admission.js +2 -0
- package/dist/executor-contract.js +6 -0
- package/dist/executor-result.js +2 -2
- package/dist/executors/quickjs-child.js +13 -4
- package/dist/executors/quickjs-runtime.d.ts +2 -0
- package/dist/executors/quickjs-runtime.js +36 -19
- package/dist/executors/quickjs.js +23 -6
- package/dist/guest-functions.js +5 -4
- package/dist/guest-runtime.js +37 -1
- package/dist/guest-types.d.ts +18 -0
- package/dist/http/client.js +7 -2
- package/dist/http/errors.js +9 -4
- package/dist/http/fields.js +17 -5
- package/dist/http/hatch.js +9 -3
- package/dist/http/paging.js +1 -1
- package/dist/http/provider.js +2 -6
- package/dist/http/vendor.js +6 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -0
- package/dist/invocation.js +98 -34
- package/dist/meta-output.js +24 -18
- package/dist/meta-tool-names.d.ts +1 -1
- package/dist/meta-tool-names.js +1 -1
- package/dist/meta-tools.js +259 -60
- package/dist/native-recovery.js +4 -1
- package/dist/native-tools.js +166 -51
- package/dist/node.js +3 -1
- package/dist/oauth-handoff.js +53 -43
- package/dist/operation-activity.js +2 -1
- package/dist/operation-vocabulary.js +6 -0
- package/dist/operator-record.d.ts +1 -1
- package/dist/operator-record.js +1 -0
- package/dist/operator-ui/generated.js +2 -2
- package/dist/program-result.js +2 -0
- package/dist/program-source.js +1 -1
- package/dist/program-writes.js +112 -19
- package/dist/provider.d.ts +0 -13
- package/dist/provider.js +0 -3
- package/dist/providers/_shared/google/kit.js +2 -2
- package/dist/providers/breeze/api.js +2 -2
- package/dist/providers/breeze/skill.generated.js +1 -1
- package/dist/providers/ccb/api.js +2 -2
- package/dist/providers/ccb/skill.generated.js +1 -1
- package/dist/providers/cloudflare/api.js +2 -2
- package/dist/providers/cloudflare/index.js +2 -0
- package/dist/providers/cloudflare/skill.generated.js +1 -1
- package/dist/providers/docs/skill.generated.js +1 -1
- package/dist/providers/drive/skill.generated.js +1 -1
- package/dist/providers/forms/index.js +1 -0
- package/dist/providers/forms/skill.generated.js +1 -1
- package/dist/providers/github/api.js +98 -6
- package/dist/providers/github/index.js +7 -2
- package/dist/providers/github/lib/auth.d.ts +3 -1
- package/dist/providers/github/lib/auth.js +43 -12
- package/dist/providers/github/lib/discovery.js +11 -1
- package/dist/providers/github/lib/operations.js +8 -0
- package/dist/providers/github/safety.js +39 -0
- package/dist/providers/github/skill.generated.js +1 -1
- package/dist/providers/github/tools.js +12 -5
- package/dist/providers/gmail/index.js +1 -0
- package/dist/providers/gmail/skill.generated.js +1 -1
- package/dist/providers/granola/skill.generated.js +1 -1
- package/dist/providers/overflow/index.js +2 -0
- package/dist/providers/overflow/skill.generated.js +1 -1
- package/dist/providers/planning-center/index.js +11 -5
- package/dist/providers/planning-center/lib/constants.d.ts +1 -1
- package/dist/providers/planning-center/skill.generated.js +1 -1
- package/dist/providers/quickbooks/index.js +2 -5
- package/dist/providers/quickbooks/skill.generated.js +1 -1
- package/dist/providers/sheets/index.js +1 -0
- package/dist/providers/sheets/skill.generated.js +1 -1
- package/dist/providers/slides/index.js +2 -2
- package/dist/providers/slides/skill.generated.js +1 -1
- package/dist/providers/stripe/skill.generated.js +1 -1
- package/dist/providers/tithely/index.js +1 -0
- package/dist/providers/tithely/skill.generated.js +1 -1
- package/dist/providers/vercel/api.js +2 -2
- package/dist/providers/vercel/skill.generated.js +1 -1
- package/dist/registry.d.ts +36 -4
- package/dist/registry.js +127 -27
- package/dist/result-preview.js +210 -0
- package/dist/result-seal.js +168 -0
- package/dist/route-names.js +13 -4
- package/dist/routes/connect.js +21 -13
- package/dist/routes/mcp.js +55 -26
- package/dist/routes/shared.d.ts +6 -0
- package/dist/runtime/call.js +15 -10
- package/dist/runtime/request-scope.js +36 -1
- package/dist/runtime/run.js +4 -1
- package/dist/sent-secrets.d.ts +20 -0
- package/dist/sent-secrets.js +49 -1
- package/dist/skills.js +100 -33
- package/dist/storage/keys.js +9 -6
- package/dist/storage/sql-native.js +1 -1
- package/dist/tool-safety.d.ts +33 -0
- package/dist/tool-safety.js +51 -15
- package/dist/types.d.ts +31 -0
- package/dist/usage-guide.js +14 -13
- package/dist/validate.js +29 -10
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worker.js +28 -8
- package/documentation/architecture.md +104 -42
- package/documentation/auth.md +46 -19
- package/documentation/code-mode.md +378 -116
- package/documentation/deploying.md +10 -9
- package/documentation/hosted-mcp-migration.md +9 -3
- package/documentation/integrating.md +27 -5
- package/documentation/meta-tools.md +655 -153
- package/documentation/operating.md +5 -3
- package/documentation/providers.md +18 -6
- package/examples/worker/README.md +3 -3
- package/guides/how-it-works.md +2 -1
- package/guides/safety-and-trust.md +1 -3
- package/package.json +1 -1
- package/templates/node/AGENTS.md +3 -3
- package/templates/node/README.md +1 -1
- package/templates/node/package.json +1 -1
package/dist/http/hatch.js
CHANGED
|
@@ -25,6 +25,8 @@ import { Integer, isMaxChars, isMinChars } from "./json-schema.js";
|
|
|
25
25
|
import { boundCursor, StandardPage } from "./paging.js";
|
|
26
26
|
import { Classification, Dispatches, IdempotencyKey, RequestSecrets, Signal } from "./services.js";
|
|
27
27
|
import { read, write } from "./tools.js";
|
|
28
|
+
/** A page that reports more data it cannot continue must never read as the complete answer. */
|
|
29
|
+
const CONTINUATION_WITHHELD = "This result is incomplete: more data exists and continuation was withheld.";
|
|
28
30
|
const indexedOperations = new WeakMap();
|
|
29
31
|
function operationsOf(index) {
|
|
30
32
|
let operations = indexedOperations.get(index);
|
|
@@ -204,7 +206,7 @@ export function hatch(options) {
|
|
|
204
206
|
}
|
|
205
207
|
return fieldsInput(fieldsNote(first ?? preferred));
|
|
206
208
|
};
|
|
207
|
-
const fieldsNote = (example) => fieldsDescription("data", example, `Copy declared paths from ${name}_api_details response.fields.
|
|
209
|
+
const fieldsNote = (example) => fieldsDescription("data", example, `Copy declared paths from ${name}_api_details response.fields. A withheld value reads "[redacted]".`);
|
|
208
210
|
const verdictOf = (op) => verdicts.get(`${op.method} ${op.path}`) ?? "refuse";
|
|
209
211
|
const refusalOf = (op) => connection.safety.refusal?.({ method: op.method, template: op.path }) ?? options.binding?.refusal?.(op);
|
|
210
212
|
const discoveryRefusals = new Map();
|
|
@@ -259,7 +261,7 @@ export function hatch(options) {
|
|
|
259
261
|
}
|
|
260
262
|
: {}),
|
|
261
263
|
warnings: Schema.optionalKey(Schema.Array(Schema.String).annotate({
|
|
262
|
-
description: `${options.binding?.warnings ? "Reviewed warnings preserved after fields selection, and " : ""}fields entries that matched nothing in this nonempty response, with the properties declared where matching stopped. At most 10 warnings of 512 characters, then an omitted count.`,
|
|
264
|
+
description: `${options.binding?.warnings ? "Reviewed warnings preserved after fields selection, and " : ""}fields entries that matched nothing in this nonempty response, with the properties declared where matching stopped${pages.size ? ", and a notice when continuation was withheld" : ""}. At most 10 warnings of 512 characters, then an omitted count.`,
|
|
263
265
|
})),
|
|
264
266
|
});
|
|
265
267
|
const hasTotals = [...pages.values()].some((adapters) => adapters.some((adapter) => adapter.total !== undefined));
|
|
@@ -268,11 +270,14 @@ export function hatch(options) {
|
|
|
268
270
|
...callEnvelope.fields,
|
|
269
271
|
page: Schema.optionalKey(Schema.Struct({
|
|
270
272
|
...StandardPage.fields,
|
|
273
|
+
hasMore: Schema.Boolean.annotate({
|
|
274
|
+
description: "True without nextCursor means this data is incomplete and continuation was withheld.",
|
|
275
|
+
}),
|
|
271
276
|
...(hasTotals ? { total: Schema.optionalKey(Integer.check(Schema.isGreaterThanOrEqualTo(0))) } : {}),
|
|
272
277
|
param: Schema.String.annotate({
|
|
273
278
|
description: options.pageCursor === "argument"
|
|
274
279
|
? "Vendor parameter restored from cursor; pass nextCursor as the top-level cursor."
|
|
275
|
-
: "Put nextCursor in
|
|
280
|
+
: "Put nextCursor unchanged in query[param] or body[param], as page.in says, and keep every other argument.",
|
|
276
281
|
}),
|
|
277
282
|
in: Schema.Literals(["query", "body"]),
|
|
278
283
|
})),
|
|
@@ -1223,6 +1228,7 @@ export function hatch(options) {
|
|
|
1223
1228
|
// Roots were checked before dispatch; the pinned index cannot say whether a
|
|
1224
1229
|
// deeper level is closed, so a nested miss is reported, never refused.
|
|
1225
1230
|
const warnings = boundWarnings([
|
|
1231
|
+
...(page?.hasMore && page.nextCursor === undefined ? [CONTINUATION_WITHHELD] : []),
|
|
1226
1232
|
...(options.binding?.warnings && "warnings" in answer ? (answer.warnings ?? []) : []),
|
|
1227
1233
|
...fieldsMisses(answered, args.fields, index
|
|
1228
1234
|
.fields(op)
|
package/dist/http/paging.js
CHANGED
|
@@ -20,7 +20,7 @@ export const StandardPage = Schema.Struct({
|
|
|
20
20
|
});
|
|
21
21
|
/** The input field that carries a cursor back. */
|
|
22
22
|
export const Cursor = Schema.String.check(Schema.isMinLength(1)).annotate({
|
|
23
|
-
description: "Opaque nextCursor from the previous page. Pass it back unchanged.",
|
|
23
|
+
description: "Opaque page.nextCursor from the previous page. Pass it back unchanged with the same arguments.",
|
|
24
24
|
});
|
|
25
25
|
/**
|
|
26
26
|
* Lookahead paging, for a vendor that returns no `has_more`: ask for one row
|
package/dist/http/provider.js
CHANGED
|
@@ -46,7 +46,7 @@ const missingGrant = {
|
|
|
46
46
|
};
|
|
47
47
|
/** An ordinary Promise connector factory; Effect remains inside the kit. */
|
|
48
48
|
export function defineApiProvider(definition) {
|
|
49
|
-
const { displayTitle, description, authScope, vendor, baseUrl, maxResponseBytes, timeoutMs, headers, admit, transport, defaultCallAdmission, pageSize: declaredPageSize, idempotencyKey, credential, oauth, oauthWrite401, grant, grantRenewal, authenticate, errors, safety, result, inBandRefusals, probe, guide, transformGuide, hatch: declaredHatch, tools, tagConnector, searchSynonyms, ...metadata } = definition;
|
|
49
|
+
const { displayTitle, description, authScope, vendor, baseUrl, maxResponseBytes, timeoutMs, headers, admit, transport, defaultCallAdmission, pageSize: declaredPageSize, idempotencyKey, credential, oauth, oauthWrite401, grant, grantRenewal, authenticate, publicIdentifierHeaders, errors, safety, result, inBandRefusals, probe, guide, transformGuide, hatch: declaredHatch, tools, tagConnector, searchSynonyms, ...metadata } = definition;
|
|
50
50
|
if (searchSynonyms !== undefined &&
|
|
51
51
|
!(Array.isArray(searchSynonyms) &&
|
|
52
52
|
searchSynonyms.length > 0 &&
|
|
@@ -95,18 +95,13 @@ export function defineApiProvider(definition) {
|
|
|
95
95
|
kind: "api",
|
|
96
96
|
kit: {
|
|
97
97
|
operations: operations(vendor),
|
|
98
|
-
...(pageSize ? { pageSize } : {}),
|
|
99
98
|
...(hatchOptions
|
|
100
99
|
? {
|
|
101
100
|
hatch: {
|
|
102
101
|
name: hatchOptions.name,
|
|
103
102
|
verdicts: hatchOptions.verdicts,
|
|
104
103
|
...(hatchOptions.fieldsRoot ? { fieldsRoot: hatchOptions.fieldsRoot } : {}),
|
|
105
|
-
...(hatchOptions.pageCursor && Object.keys(hatchOptions.pages ?? {}).length
|
|
106
|
-
? { paging: hatchOptions.pageCursor }
|
|
107
|
-
: {}),
|
|
108
104
|
},
|
|
109
|
-
refusesWithheld: true,
|
|
110
105
|
}
|
|
111
106
|
: {}),
|
|
112
107
|
...(meanings ? { errors: meanings } : {}),
|
|
@@ -134,6 +129,7 @@ export function defineApiProvider(definition) {
|
|
|
134
129
|
...(headers === undefined ? {} : { headers }),
|
|
135
130
|
...(admit === undefined ? {} : { admit }),
|
|
136
131
|
authenticate: typeof authenticate === "function" ? authenticate(options) : authenticate,
|
|
132
|
+
...(publicIdentifierHeaders === undefined ? {} : { publicIdentifierHeaders }),
|
|
137
133
|
...configured,
|
|
138
134
|
});
|
|
139
135
|
const connected = connect(vendor, oauth || machineGrant
|
package/dist/http/vendor.js
CHANGED
|
@@ -342,6 +342,7 @@ export function connect(vendor, guarded, options) {
|
|
|
342
342
|
method: declared.method,
|
|
343
343
|
template: declared.path,
|
|
344
344
|
...(sendOptions?.flags ? { flags: sendOptions.flags } : {}),
|
|
345
|
+
...(sendOptions?.context ? { context: sendOptions.context } : {}),
|
|
345
346
|
};
|
|
346
347
|
return Effect.flatMap(admitAddress({
|
|
347
348
|
params: request.params,
|
|
@@ -370,7 +371,11 @@ export function connect(vendor, guarded, options) {
|
|
|
370
371
|
request.form !== undefined ||
|
|
371
372
|
request.emptyForm))
|
|
372
373
|
return Effect.fail(new RequestRefused({ message: "A raw body cannot accompany a bulk item or another body encoding." }));
|
|
373
|
-
return Effect.flatMap(admitAddress({ path, query: request.query }), () => Effect.flatMap(options.safety.resolve(method, path), (operation) => settle({
|
|
374
|
+
return Effect.flatMap(admitAddress({ path, query: request.query }), () => Effect.flatMap(options.safety.resolve(method, path), (operation) => settle({
|
|
375
|
+
...operation,
|
|
376
|
+
...(sendOptions?.flags ? { flags: sendOptions.flags } : {}),
|
|
377
|
+
...(sendOptions?.context ? { context: sendOptions.context } : {}),
|
|
378
|
+
}, Effect.suspend(() => {
|
|
374
379
|
let built = HttpClientRequest.make(method)(path, request.query ? { urlParams: parameterPairs(request.query) } : {});
|
|
375
380
|
if (request.headers)
|
|
376
381
|
built = HttpClientRequest.setHeaders(built, request.headers);
|
package/dist/index.d.ts
CHANGED
|
@@ -41,6 +41,6 @@ export type { Registry } from "./registry.js";
|
|
|
41
41
|
export type { RemoteMcpOptions, RemoteMcpAuth, RemoteMcpRequestAuth, RemoteMcpRedirectPolicy, } from "./connectors/remote-mcp.js";
|
|
42
42
|
export type { AgentRequestPrincipal, HumanRequestPrincipal, PrincipalForwarding, PrincipalRequestToken, RequestPrincipal, RequestPrincipalPolicy, RequestToken, RequestTokenInput, } from "./request-token.js";
|
|
43
43
|
export type { ApiHandlerContext, ApiOAuthAccess, ApiOAuthClientAuthentication, ApiOAuthConfig, ApiOptions, ApiTool, } from "./connectors/api.js";
|
|
44
|
-
export type { ConnectaBranding, ConnectaTheme, Connector, ConnectorCallAdmissionInput, ConnectorCallAdmissionPolicy, ConnectorCallAdmissionRule, ConnectorRollingWindowBudget, ConnectorCredentialAccess, ConnectorCredentialConfig, ConnectorCredentialFieldConfig, ConnectorCredentialValues, AgentRouteNames, ConnectorContext, ConnectorAuthDescription, ConnectorDescription, ConnectorToolDescription, ConnectorUsageGuide, ConnectorSkill, ConnectorSkillResourceContents, DescribedEndpoint, ConnectorStatus, CredentialFailureClass, CredentialTestResult, AdmittingExecutor, AdmissionSnapshot, ExecuteResult, Executor, ExecutorLease, ExecutorProvider, InboundAuth, InboundAuthRuntimeContext, UiAuthConfig, AuthResult, AuthenticatedIdentity, IdentityReference, JsonSchema, KVStorage, Logger, ToolDef, ToolAnnotations, } from "./types.js";
|
|
44
|
+
export type { ConnectaBranding, ConnectaTheme, Connector, ConnectorCallAdmissionInput, ConnectorCallAdmissionPolicy, ConnectorCallAdmissionRule, ConnectorRollingWindowBudget, ConnectorCredentialAccess, ConnectorCredentialConfig, ConnectorCredentialFieldConfig, ConnectorCatalogPeek, ConnectorCredentialValues, AgentRouteNames, ConnectorContext, ConnectorAuthDescription, ConnectorDescription, ConnectorToolDescription, ConnectorUsageGuide, ConnectorSkill, ConnectorSkillResourceContents, DescribedEndpoint, ConnectorStatus, CredentialFailureClass, CredentialTestResult, AdmittingExecutor, AdmissionSnapshot, ExecuteResult, Executor, ExecutorLease, ExecutorProvider, InboundAuth, InboundAuthRuntimeContext, UiAuthConfig, AuthResult, AuthenticatedIdentity, IdentityReference, JsonSchema, KVStorage, Logger, ToolDef, ToolAnnotations, } from "./types.js";
|
|
45
45
|
export type { ActivityActor, ActivityCatalogChange, ActivityCallSource, ActivityOutcome, ActivityPage, ActivityReadActor, ActivityReadEvent, ActivityReader, ActivityReadGate, ActivityReadPage, ActivitySink, ActivityStore, AgentFriction, ToolCallActivityEvent, } from "./activity.js";
|
|
46
46
|
export { META_TOOL_NAMES } from "./meta-tool-names.js";
|
package/dist/index.js
CHANGED
|
@@ -211,6 +211,11 @@ export function createConnecta(config) {
|
|
|
211
211
|
const requestAdmission = new AdmissionController(resolved.admission.requests);
|
|
212
212
|
let codeAdmission;
|
|
213
213
|
let executor = resolved.executor;
|
|
214
|
+
if (executor.deadlineMs !== undefined && executor.deadlineMs >= resolved.execute.watchdogMs) {
|
|
215
|
+
logger.warn(`[connecta] The executor's ${executor.deadlineMs}ms deadline does not end before execute.watchdogMs ` +
|
|
216
|
+
`(${resolved.execute.watchdogMs}ms), so programs end at the watchdog. Raise execute.watchdogMs ` +
|
|
217
|
+
"above it if your MCP clients allow requests that long.");
|
|
218
|
+
}
|
|
214
219
|
// Read the identity off the configured executor, before any wrapper hides
|
|
215
220
|
// it behind an anonymous object literal.
|
|
216
221
|
const configuredExecutorName = executorName(executor);
|
package/dist/invocation.js
CHANGED
|
@@ -4,12 +4,12 @@ import { routePhrases } from "./agent-routes.js";
|
|
|
4
4
|
import { authCall, registerAuthMethod } from "./auth/native.js";
|
|
5
5
|
import { withAuthorizationHandoffEffect } from "./authorization-handoff.js";
|
|
6
6
|
import { hasControlCharacters } from "./tool-name.js";
|
|
7
|
-
import { cloneTool, isWriteLike, writeRefusal } from "./tool-safety.js";
|
|
7
|
+
import { cloneTool, isWriteLike, READ_PROGRAM_SOURCE, readProgramRefuses, writeRefusal } from "./tool-safety.js";
|
|
8
8
|
import { Cause, Context, Effect, Exit } from "effect";
|
|
9
9
|
import { CallAdmissionError, isCallAdmissionError } from "./call-admission.js";
|
|
10
|
-
import { boundedEchoText, classificationCode, classifyCallError, classifyWithoutAdvice, ConnectorCallError, echoedCallArgs, framingError, keyResendAdviceOf, resendAdviceOf, withResendAdvice, } from "./errors.js";
|
|
10
|
+
import { boundedEchoText, clipText, classificationCode, classifyCallError, classifyWithoutAdvice, ConnectorCallError, echoedCallArgs, framingError, keyResendAdviceOf, resendAdviceOf, withResendAdvice, } from "./errors.js";
|
|
11
11
|
import { downstreamValue } from "./mcp-result.js";
|
|
12
|
-
import { carryFailureFacts, classifiedFailure, failureRecord, logFailure, recordedToolName, } from "./operator-record.js";
|
|
12
|
+
import { carryFailureFacts, classifiedFailure, failureRecord, logFailure, recordedToolName, labelErrorClass, } from "./operator-record.js";
|
|
13
13
|
import { splitAddress } from "./registry.js";
|
|
14
14
|
import { causeError, runEdge, withDeadlineEffect } from "./runtime/run.js";
|
|
15
15
|
import { schemaExample, validateCatalogToolInput } from "./validate.js";
|
|
@@ -84,7 +84,18 @@ function isCallerCancellation(error, signal) {
|
|
|
84
84
|
* write it is a 2xx reply after which the handler may have applied it.
|
|
85
85
|
*/
|
|
86
86
|
class DownstreamToolError extends Error {
|
|
87
|
+
/** Everything it said, kept for a program's report; the message is what fits a result. */
|
|
88
|
+
#text;
|
|
89
|
+
constructor(text) {
|
|
90
|
+
super(clipText(text));
|
|
91
|
+
this.#text = text;
|
|
92
|
+
}
|
|
93
|
+
fullText() {
|
|
94
|
+
return this.#text;
|
|
95
|
+
}
|
|
87
96
|
}
|
|
97
|
+
// Records tell the tool's own answer from a transport or runtime failure.
|
|
98
|
+
labelErrorClass(DownstreamToolError, "DownstreamToolError");
|
|
88
99
|
function isTimeoutFailure(error) {
|
|
89
100
|
const code = error.details?.code;
|
|
90
101
|
return (error.code === "timeout" ||
|
|
@@ -97,10 +108,10 @@ function assertRawMcpSuccess(kind, result) {
|
|
|
97
108
|
const mcpResult = result;
|
|
98
109
|
if (!mcpResult.isError)
|
|
99
110
|
return;
|
|
100
|
-
throw new DownstreamToolError(
|
|
111
|
+
throw new DownstreamToolError(mcpResult.content
|
|
101
112
|
?.filter((block) => block.type === "text")
|
|
102
113
|
.map((block) => block.text ?? "")
|
|
103
|
-
.join("") || "Downstream tool call failed")
|
|
114
|
+
.join("\n") || "Downstream tool call failed");
|
|
104
115
|
}
|
|
105
116
|
/**
|
|
106
117
|
* Whether a failed attempt is the downstream tool's own answer. For a read:
|
|
@@ -116,6 +127,14 @@ function answeredFailure(error, write, call) {
|
|
|
116
127
|
return error instanceof DownstreamToolError || isKnownProviderFailure(error);
|
|
117
128
|
return knownCallFailure(call, error);
|
|
118
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* What a write gate decided about one consequential call. A dispatch goes on
|
|
132
|
+
* to admission and the connector; a refusal ends the call with `error`,
|
|
133
|
+
* recorded as an ordinary failed attempt unless `unrecorded` — a write
|
|
134
|
+
* refused only because its program already returned was never an attempt.
|
|
135
|
+
*/
|
|
136
|
+
/** Both program routes: no direct-call continuation applies to their calls. */
|
|
137
|
+
const isProgram = (source) => source === "execute_code" || source === READ_PROGRAM_SOURCE;
|
|
119
138
|
export { InvocationFailure } from "./invocation-failure.js";
|
|
120
139
|
const withoutExample = ({ example: _example, ...stated }) => stated;
|
|
121
140
|
/**
|
|
@@ -165,6 +184,7 @@ export class InvocationService {
|
|
|
165
184
|
const recoveryState = recoveryRecord();
|
|
166
185
|
let preInvocationAuthFailure = false;
|
|
167
186
|
let answered = false;
|
|
187
|
+
let failureText;
|
|
168
188
|
// A dispatched failure's advice to send it again, composed by enrich
|
|
169
189
|
// only once the outcome allows it (resendAdvice), and its advice to
|
|
170
190
|
// reuse an idempotency key, only where that key protects the whole
|
|
@@ -175,6 +195,10 @@ export class InvocationService {
|
|
|
175
195
|
context.sentSecrets?.include(sentSecrets);
|
|
176
196
|
// A write gate's refusal that is no attempt; see WriteGateDecision.
|
|
177
197
|
let unrecorded = false;
|
|
198
|
+
// The gate's refusal states its own deadline facts; nothing timed out here.
|
|
199
|
+
let gateRefused = false;
|
|
200
|
+
// The deadline this call runs under, once its classification is known.
|
|
201
|
+
let timeoutMs = context.timeoutMs;
|
|
178
202
|
let resolved;
|
|
179
203
|
let activityTarget;
|
|
180
204
|
// The address as written, used for activity when resolution never reached
|
|
@@ -223,8 +247,7 @@ export class InvocationService {
|
|
|
223
247
|
? { ...error, nextAction: error.nextAction ?? utilityRecovery(error.code, error.message).nextAction }
|
|
224
248
|
: error;
|
|
225
249
|
const recovery = recoveryState.facts;
|
|
226
|
-
const enteredWrite = dispatchedToConnector &&
|
|
227
|
-
((resolved !== undefined && resolved.definition.classification !== "read") || sentSourceWrite());
|
|
250
|
+
const enteredWrite = dispatchedToConnector && ((resolved !== undefined && isWriteLike(resolved.definition)) || sentSourceWrite());
|
|
228
251
|
// A known answer alone is not dispatch evidence. Require an owned,
|
|
229
252
|
// complete ledger with a positively recorded auxiliary resource read;
|
|
230
253
|
// an empty ledger, custom entry or interruption proves nothing.
|
|
@@ -243,7 +266,7 @@ export class InvocationService {
|
|
|
243
266
|
return {
|
|
244
267
|
...error,
|
|
245
268
|
code: "write_outcome_unknown",
|
|
246
|
-
message: `${error.message}
|
|
269
|
+
message: `${error.message} It was sent once; its outcome is unknown. Check the target before repeating this call.`,
|
|
247
270
|
retryable: false,
|
|
248
271
|
...(sentSourceWrite() ? { writeOutcome: "unknown" } : {}),
|
|
249
272
|
connector: target.connector.id,
|
|
@@ -286,7 +309,9 @@ export class InvocationService {
|
|
|
286
309
|
writeOutcome: "unknown",
|
|
287
310
|
...(!recovery && error.retry === undefined
|
|
288
311
|
? {
|
|
289
|
-
retry:
|
|
312
|
+
retry: error.toolAnswered
|
|
313
|
+
? "Its outcome is unknown: its handler ran before it answered, so check its target before acting. Give the user any approval link or request id in the message. Connecta will not resend it; a call the tool's words ask for is a new call."
|
|
314
|
+
: "No safe replay action exists. Re-read the target to reconcile whether the write took effect.",
|
|
290
315
|
}
|
|
291
316
|
: {}),
|
|
292
317
|
};
|
|
@@ -425,10 +450,15 @@ export class InvocationService {
|
|
|
425
450
|
},
|
|
426
451
|
connector: target.connector.id,
|
|
427
452
|
operation: `${target.connector.id}.${target.toolName}`,
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
453
|
+
// Findings naming the fix lead on their own; a search would only cost a turn.
|
|
454
|
+
...(error.validation.issues?.length && error.validation.acceptedKeys && !error.validation.truncated
|
|
455
|
+
? {}
|
|
456
|
+
: {
|
|
457
|
+
nextAction: this.catalog.searchRecovery({
|
|
458
|
+
query: target.toolName,
|
|
459
|
+
connector: target.connector.id,
|
|
460
|
+
}, "Only if the validation above is not enough: inspect the schema."),
|
|
461
|
+
}),
|
|
432
462
|
retry: `Correct the listed arguments and retry ` + `${target.connector.id}.${target.toolName}.`,
|
|
433
463
|
};
|
|
434
464
|
case "not_found":
|
|
@@ -444,7 +474,7 @@ export class InvocationService {
|
|
|
444
474
|
return error;
|
|
445
475
|
// The continuation nonce is spent. Let the input boundary supply
|
|
446
476
|
// its fresh-call action instead of generic availability advice.
|
|
447
|
-
if (context.source
|
|
477
|
+
if (!isProgram(context.source) &&
|
|
448
478
|
downstreamContinuation(this.catalog.requestScope, target.connector.id, `${target.connector.id}.${target.toolName}`))
|
|
449
479
|
return error;
|
|
450
480
|
return {
|
|
@@ -462,7 +492,7 @@ export class InvocationService {
|
|
|
462
492
|
// a write. No connector failure arrives, so the logical call's
|
|
463
493
|
// recorded requests alone decide whether a 401 left it unknown.
|
|
464
494
|
if (dispatchedToConnector &&
|
|
465
|
-
(resolved
|
|
495
|
+
(resolved === undefined || isWriteLike(resolved.definition) || sentSourceWrite()) &&
|
|
466
496
|
(error.code === "cancelled" || isTimeoutFailure(error))) {
|
|
467
497
|
const departed = settleWrite(logicalCall?.sent ?? [], undefined, true);
|
|
468
498
|
if (departed !== undefined) {
|
|
@@ -487,13 +517,13 @@ export class InvocationService {
|
|
|
487
517
|
// Read before any step below rebuilds the details: Q8's verdict is final.
|
|
488
518
|
const settled = isSettledWrite(error);
|
|
489
519
|
// Attach host deadline facts before write recovery changes the code.
|
|
490
|
-
if (isTimeoutFailure(error)) {
|
|
520
|
+
if (isTimeoutFailure(error) && !gateRefused) {
|
|
491
521
|
const elapsedMs = Date.now() - started;
|
|
492
522
|
const operation = boundedEchoText(address, 512);
|
|
493
523
|
error = {
|
|
494
524
|
...error,
|
|
495
|
-
message: `Operation "${operation}" timed out during ${stage} after ${elapsedMs}ms (effective deadline ${
|
|
496
|
-
details: { ...error.details, operation, stage, elapsedMs, ...defined({ deadlineMs:
|
|
525
|
+
message: `Operation "${operation}" timed out during ${stage} after ${elapsedMs}ms (effective deadline ${timeoutMs}ms).`,
|
|
526
|
+
details: { ...error.details, operation, stage, elapsedMs, ...defined({ deadlineMs: timeoutMs }) },
|
|
497
527
|
};
|
|
498
528
|
}
|
|
499
529
|
// Downstream diagnostics were redacted under payload rules where they entered.
|
|
@@ -506,6 +536,7 @@ export class InvocationService {
|
|
|
506
536
|
...defined({ resolved }),
|
|
507
537
|
dispatched: dispatchedToConnector,
|
|
508
538
|
...(dispatchedToConnector ? { answered } : {}),
|
|
539
|
+
...defined({ failureText }),
|
|
509
540
|
error: details,
|
|
510
541
|
});
|
|
511
542
|
// A write refused only because its program had already returned
|
|
@@ -547,6 +578,11 @@ export class InvocationService {
|
|
|
547
578
|
// expected, and a throw anywhere in it — a defect, to Effect — is
|
|
548
579
|
// classified like a failure, as the async body this replaced did.
|
|
549
580
|
const dispatch = (callSignal) => Effect.gen({ self: this }, function* () {
|
|
581
|
+
if (context.refusal) {
|
|
582
|
+
gateRefused = true;
|
|
583
|
+
return context.refusal;
|
|
584
|
+
}
|
|
585
|
+
let pastDeadline;
|
|
550
586
|
const admissionSignal = context.dispatchSignal
|
|
551
587
|
? AbortSignal.any([context.dispatchSignal, ...(callSignal ? [callSignal] : [])])
|
|
552
588
|
: callSignal;
|
|
@@ -573,17 +609,20 @@ export class InvocationService {
|
|
|
573
609
|
activityTarget = target;
|
|
574
610
|
argumentEcho = echoedCallArgs(args ?? {}, target.definition.inputSchema);
|
|
575
611
|
sentSecrets.arguments(args ?? {}, target.definition.inputSchema);
|
|
576
|
-
|
|
577
|
-
|
|
612
|
+
// Admission and presentation follow the served class. Dispatch and failure
|
|
613
|
+
// handling follow this: a source write served as a read still sends once.
|
|
614
|
+
const write = isWriteLike(target.definition);
|
|
615
|
+
if (write && context.writeTimeoutMs !== undefined)
|
|
616
|
+
timeoutMs = context.writeTimeoutMs;
|
|
578
617
|
const canonicalAddress = `${target.connector.id}.${target.toolName}`;
|
|
579
|
-
const input = context.source
|
|
618
|
+
const input = !isProgram(context.source)
|
|
580
619
|
? downstreamContinuation(this.catalog.requestScope, target.connector.id, canonicalAddress)
|
|
581
620
|
: undefined;
|
|
582
621
|
if (input)
|
|
583
622
|
recordDownstreamArgumentEcho(this.catalog.requestScope, argumentEcho);
|
|
584
623
|
const expectedDigest = replayClassificationDigest(this.catalog.requestScope, canonicalAddress);
|
|
585
624
|
if (expectedDigest !== undefined &&
|
|
586
|
-
(
|
|
625
|
+
(write ||
|
|
587
626
|
target.classificationFresh !== true ||
|
|
588
627
|
(yield* Effect.promise(() => classificationDigest(target.definition))) !== expectedDigest)) {
|
|
589
628
|
return {
|
|
@@ -594,9 +633,15 @@ export class InvocationService {
|
|
|
594
633
|
const connectorReadOnly = target.connector.readOnly === true;
|
|
595
634
|
const refusal = writeRefusal(target.definition.classification, context.source, context.readOnly || connectorReadOnly);
|
|
596
635
|
if (refusal === "read_only_endpoint") {
|
|
597
|
-
return framingError("read_only_endpoint", `Tool "${canonicalAddress}" is a write, and ${connectorReadOnly ? `connector "${target.connector.id}"` : "this endpoint"} is read-only. No write route exists ${connectorReadOnly ? "for this connection" : "on this endpoint"}.
|
|
636
|
+
return framingError("read_only_endpoint", `Tool "${canonicalAddress}" is a write, and ${connectorReadOnly ? `connector "${target.connector.id}"` : "this endpoint"} is read-only. No write route exists ${connectorReadOnly ? "for this connection" : "on this endpoint"}; tell the user. Only the operator can provide a writable connection.`);
|
|
637
|
+
}
|
|
638
|
+
// Below the sandbox: no guest code can reach past this, and catching it sends nothing.
|
|
639
|
+
if (context.source === READ_PROGRAM_SOURCE) {
|
|
640
|
+
if (readProgramRefuses(target.definition)) {
|
|
641
|
+
return framingError("destructive_tool_requires_approval", `Tool "${canonicalAddress}" can write, so ${READ_PROGRAM_SOURCE} refused it and nothing was sent. Use call_destructive_tool for this one call, or execute_code for a program that writes; the MCP host can request approval for either.`);
|
|
642
|
+
}
|
|
598
643
|
}
|
|
599
|
-
if (refusal === "destructive_tool_requires_approval") {
|
|
644
|
+
else if (refusal === "destructive_tool_requires_approval") {
|
|
600
645
|
return framingError("destructive_tool_requires_approval", `Tool "${canonicalAddress}" is a write. ${routePhrases(context).writeNeedsApproval}`);
|
|
601
646
|
}
|
|
602
647
|
// Remote MCP tools advertise their input schema in the catalog. Validate
|
|
@@ -614,10 +659,11 @@ export class InvocationService {
|
|
|
614
659
|
return classifyCallError(invalid);
|
|
615
660
|
}
|
|
616
661
|
// Source writes keep program write accounting; only effective writes spend W10 budget.
|
|
617
|
-
if (
|
|
662
|
+
if (write && context.beforeWrite) {
|
|
618
663
|
const decision = yield* context.beforeWrite(target, args ?? {});
|
|
619
664
|
if (decision.kind === "refuse") {
|
|
620
665
|
unrecorded = decision.unrecorded === true;
|
|
666
|
+
gateRefused = true;
|
|
621
667
|
return decision.error;
|
|
622
668
|
}
|
|
623
669
|
}
|
|
@@ -627,7 +673,7 @@ export class InvocationService {
|
|
|
627
673
|
const call = (permit) => Effect.gen({ self: this }, function* () {
|
|
628
674
|
const operationContext = this.registry.contextFor(target.connector.id, this.catalog.baseUrl, this.catalog.requestScope, defined({
|
|
629
675
|
signal: callSignal,
|
|
630
|
-
timeoutMs
|
|
676
|
+
timeoutMs,
|
|
631
677
|
defer: this.catalog.defer,
|
|
632
678
|
routes: context.routes,
|
|
633
679
|
}));
|
|
@@ -666,19 +712,27 @@ export class InvocationService {
|
|
|
666
712
|
const code = classifyCallError(causeError(cause, connectorContext.signal)).code;
|
|
667
713
|
preInvocationAuthFailure = code === "auth_required" || code === "downstream_oauth_required";
|
|
668
714
|
})));
|
|
669
|
-
//
|
|
715
|
+
// Reflect.apply, never the function's own `call` or `apply`
|
|
716
|
+
// property, which anyone holding the function could replace.
|
|
717
|
+
const options = { definition: cloneTool(target.definition), ...defined({ input }) };
|
|
718
|
+
const entry = callEntry(connector, callTool);
|
|
719
|
+
// The final gate. Cancellation can arrive during admission or context
|
|
720
|
+
// construction, and resolution, admission or auth can spend the deadline.
|
|
721
|
+
// Nothing is awaited from here to the connector call below, so a call
|
|
722
|
+
// refused here is proven unsent and one let through left in time (INV-9).
|
|
670
723
|
if (admissionSignal?.aborted)
|
|
671
724
|
throw admissionSignal.reason;
|
|
725
|
+
if (context.dispatchDeadline && Date.now() >= context.dispatchDeadline.at) {
|
|
726
|
+
gateRefused = true;
|
|
727
|
+
pastDeadline = context.dispatchDeadline.refusal(canonicalAddress);
|
|
728
|
+
return undefined;
|
|
729
|
+
}
|
|
672
730
|
dispatchedToConnector = true;
|
|
673
731
|
recordCallEntry(this.catalog.requestScope, {
|
|
674
732
|
address: canonicalAddress,
|
|
675
|
-
classification:
|
|
733
|
+
classification: write ? "write" : "read",
|
|
676
734
|
fresh: target.classificationFresh === true,
|
|
677
735
|
}, target.definition);
|
|
678
|
-
// Reflect.apply, never the function's own `call` or `apply`
|
|
679
|
-
// property, which anyone holding the function could replace.
|
|
680
|
-
const options = { definition: cloneTool(target.definition), ...defined({ input }) };
|
|
681
|
-
const entry = callEntry(connector, callTool);
|
|
682
736
|
if (entry)
|
|
683
737
|
return yield* entry(target.toolName, args ?? {}, options).pipe(Effect.provideContext(viewServices(connectorContext)));
|
|
684
738
|
return yield* Effect.tryPromise({
|
|
@@ -707,6 +761,8 @@ export class InvocationService {
|
|
|
707
761
|
const reply = yield* timed((elapsed) => {
|
|
708
762
|
connectorMs += elapsed;
|
|
709
763
|
}, call(permit));
|
|
764
|
+
if (pastDeadline)
|
|
765
|
+
return { pastDeadline };
|
|
710
766
|
if (target.connector.kind === "mcp" && isDownstreamInputResult(reply)) {
|
|
711
767
|
// The downstream suspended for input. A handler asks for
|
|
712
768
|
// input from inside its run, so a write may already have
|
|
@@ -747,8 +803,15 @@ export class InvocationService {
|
|
|
747
803
|
// An inner call's verdict that does not hold for this one is withdrawn.
|
|
748
804
|
if (failureWrite && !answered)
|
|
749
805
|
forgetProviderFailure(details);
|
|
806
|
+
// The tool's own words, which a program's write accounting keeps.
|
|
807
|
+
if (failureWrite && attemptError === thrown && thrown instanceof DownstreamToolError) {
|
|
808
|
+
details.toolAnswered = true;
|
|
809
|
+
failureText = thrown.fullText();
|
|
810
|
+
}
|
|
750
811
|
return details;
|
|
751
812
|
}
|
|
813
|
+
if ("pastDeadline" in attempt.value)
|
|
814
|
+
return attempt.value.pastDeadline;
|
|
752
815
|
if ("inputRequired" in attempt.value) {
|
|
753
816
|
inputRequiredValue = { value: attempt.value.value };
|
|
754
817
|
return undefined;
|
|
@@ -777,6 +840,7 @@ export class InvocationService {
|
|
|
777
840
|
? withDeadlineEffect(dispatch, {
|
|
778
841
|
...defined({
|
|
779
842
|
timeoutMs: context.timeoutMs,
|
|
843
|
+
extendMs: () => (timeoutMs ?? 0) - (context.timeoutMs ?? 0),
|
|
780
844
|
signal: context.requestSignal,
|
|
781
845
|
}),
|
|
782
846
|
timeoutError: new ConnectorCallError("timeout", `Tool call timed out after ${context.timeoutMs}ms`),
|
|
@@ -801,7 +865,7 @@ export class InvocationService {
|
|
|
801
865
|
// Q8 settles a result too: a write an undeclared 401 left unknown is no
|
|
802
866
|
// success, whatever its handler made of the 401, and its result is not
|
|
803
867
|
// processed.
|
|
804
|
-
if (dispatchedToConnector && (completed.definition
|
|
868
|
+
if (dispatchedToConnector && (isWriteLike(completed.definition) || sentSourceWrite())) {
|
|
805
869
|
const unknown = settleWriteResult(logicalCall?.sent ?? []);
|
|
806
870
|
if (unknown) {
|
|
807
871
|
failureAdvice = failureKeyAdvice = undefined;
|
|
@@ -818,7 +882,7 @@ export class InvocationService {
|
|
|
818
882
|
resultProcessingMs += elapsed;
|
|
819
883
|
}, Effect.tap(withDeadlineEffect(() => processing, {
|
|
820
884
|
...defined({
|
|
821
|
-
timeoutMs:
|
|
885
|
+
timeoutMs: timeoutMs === undefined ? undefined : Math.max(1, timeoutMs - (Date.now() - started)),
|
|
822
886
|
signal: context.requestSignal,
|
|
823
887
|
}),
|
|
824
888
|
timeoutError: new ConnectorCallError("timeout", "Result processing exceeded the tool call deadline."),
|
package/dist/meta-output.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Validator } from "@cfworker/json-schema";
|
|
2
2
|
import { CATALOG_SEARCH_RESULT_SCHEMA } from "./catalog-service.js";
|
|
3
3
|
import * as z from "zod";
|
|
4
|
-
import { advertisedSchema } from "./advertised-schema.js";
|
|
4
|
+
import { advertisedSchema, openOutputSchema } from "./advertised-schema.js";
|
|
5
5
|
const error = z
|
|
6
6
|
.object({
|
|
7
7
|
code: z.string(),
|
|
@@ -9,14 +9,13 @@ const error = z
|
|
|
9
9
|
retryable: z.boolean(),
|
|
10
10
|
})
|
|
11
11
|
.passthrough();
|
|
12
|
-
const format = z.enum(["json", "text"]);
|
|
13
12
|
const counts = z.object({
|
|
14
13
|
attempted: z.number().int().nonnegative(),
|
|
15
14
|
admitted: z.number().int().nonnegative(),
|
|
16
15
|
succeeded: z.number().int().nonnegative(),
|
|
17
16
|
failed: z.number().int().nonnegative(),
|
|
18
17
|
});
|
|
19
|
-
export const EXECUTE_OUTPUT = advertisedSchema(z
|
|
18
|
+
export const EXECUTE_OUTPUT = openOutputSchema(advertisedSchema(z
|
|
20
19
|
.object({
|
|
21
20
|
result: z.unknown().optional(),
|
|
22
21
|
error: error.optional(),
|
|
@@ -26,19 +25,14 @@ export const EXECUTE_OUTPUT = advertisedSchema(z
|
|
|
26
25
|
emittedDiscarded: z.number().int().nonnegative().optional(),
|
|
27
26
|
diagnostics: z.record(z.string(), z.unknown()).optional(),
|
|
28
27
|
})
|
|
29
|
-
.passthrough())
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
skills: z.array(z.object({ name: z.string(), uri: z.string(), description: z.string() })).optional(),
|
|
36
|
-
error: error.optional(),
|
|
37
|
-
})
|
|
38
|
-
.passthrough());
|
|
39
|
-
// Catalog publication, SDK advertisement and validation share one schema.
|
|
28
|
+
.passthrough()), {
|
|
29
|
+
type: "object",
|
|
30
|
+
required: ["hostCalls"],
|
|
31
|
+
properties: { result: {}, error: { type: "object" }, hostCalls: { type: "object" }, logs: { type: "string" } },
|
|
32
|
+
});
|
|
33
|
+
// The server validates every page against the full catalog contract; clients get the open summary.
|
|
40
34
|
const searchValidator = new Validator(CATALOG_SEARCH_RESULT_SCHEMA, "2020-12", false);
|
|
41
|
-
export const SEARCH_OUTPUT = {
|
|
35
|
+
export const SEARCH_OUTPUT = openOutputSchema({
|
|
42
36
|
"~standard": {
|
|
43
37
|
version: 1,
|
|
44
38
|
vendor: "connecta",
|
|
@@ -50,12 +44,24 @@ export const SEARCH_OUTPUT = {
|
|
|
50
44
|
output: () => CATALOG_SEARCH_RESULT_SCHEMA,
|
|
51
45
|
},
|
|
52
46
|
},
|
|
53
|
-
}
|
|
54
|
-
|
|
47
|
+
}, {
|
|
48
|
+
type: "object",
|
|
49
|
+
required: ["catalogErrors", "tools", "total", "offset", "limit", "hasMore"],
|
|
50
|
+
properties: {
|
|
51
|
+
catalogErrors: { type: "array" },
|
|
52
|
+
tools: { type: "array", items: { type: "object", required: ["name", "address"] } },
|
|
53
|
+
total: { type: "integer" },
|
|
54
|
+
offset: { type: "integer" },
|
|
55
|
+
limit: { type: "integer" },
|
|
56
|
+
hasMore: { type: "boolean" },
|
|
57
|
+
nextOffset: { type: "integer" },
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
export const AUTHORIZE_OUTPUT = openOutputSchema(advertisedSchema(z
|
|
55
61
|
.object({
|
|
56
62
|
connector: z.string().optional(),
|
|
57
63
|
recovery: z.string().optional(),
|
|
58
64
|
message: z.string().optional(),
|
|
59
65
|
error: error.optional(),
|
|
60
66
|
})
|
|
61
|
-
.passthrough());
|
|
67
|
+
.passthrough()), { type: "object", properties: { connector: { type: "string" }, message: { type: "string" } } });
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/** The
|
|
1
|
+
/** The upward meta-tool set every meta endpoint lists, shared with the CLI. */
|
|
2
2
|
export declare const META_TOOL_NAMES: readonly string[];
|
package/dist/meta-tool-names.js
CHANGED