@zackbart/connecta 0.16.0 → 0.17.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 +12 -5
- package/CHANGELOG.md +289 -0
- package/README.md +6 -1
- package/dist/catalog-service.d.ts +4 -0
- package/dist/catalog-service.js +49 -5
- package/dist/catalog.d.ts +11 -0
- package/dist/catalog.js +134 -12
- package/dist/errors.d.ts +28 -2
- package/dist/errors.js +1 -0
- package/dist/execute.d.ts +5 -0
- package/dist/execute.js +229 -161
- package/dist/invocation.js +3 -1
- package/dist/meta-tools.d.ts +4 -0
- package/dist/meta-tools.js +46 -14
- package/dist/operator-ui/generated.d.ts +1 -1
- package/dist/operator-ui/generated.js +1 -1
- package/dist/operator-ui/model.d.ts +3 -1
- package/dist/providers/cloudflare.js +13 -25
- package/dist/providers/mixpanel.d.ts +3 -5
- package/dist/providers/mixpanel.js +73 -5
- package/dist/providers/stripe.d.ts +2 -2
- package/dist/providers/stripe.js +13 -11
- package/dist/registry.d.ts +32 -9
- package/dist/registry.js +217 -33
- package/dist/routes/mcp.js +6 -0
- package/dist/skills.d.ts +4 -0
- package/dist/skills.js +157 -18
- package/dist/types.d.ts +14 -2
- package/dist/ui.js +4 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/architecture.md +7 -4
- package/documentation/cloudflare.md +40 -8
- package/documentation/code-first-exploration.md +2 -2
- package/documentation/code-mode.md +45 -53
- package/documentation/connector-guides.md +24 -19
- package/documentation/connectors.md +13 -1
- package/documentation/meta-tools.md +33 -18
- package/documentation/mixpanel.md +20 -0
- package/documentation/notion.md +7 -2
- package/documentation/operations.md +74 -29
- package/documentation/operator-ui.md +12 -2
- package/documentation/provider-audit.md +4 -4
- package/documentation/provider-conventions.md +68 -19
- package/documentation/stripe.md +45 -14
- package/documentation/upgrading.md +478 -0
- package/ethos.md +4 -4
- package/examples/worker/README.md +13 -6
- package/package.json +7 -2
- package/templates/node/AGENTS.md +5 -0
- package/templates/node/package.json +1 -1
package/dist/catalog.js
CHANGED
|
@@ -2,6 +2,7 @@ const DEFAULT_DESCRIPTION_LENGTH = 240;
|
|
|
2
2
|
const DISCOVERY_DESCRIPTION_LENGTH = 160;
|
|
3
3
|
export const MAX_COMPACT_DISCOVERY_SCHEMA_BYTES = 1_024;
|
|
4
4
|
const MAX_COMPACT_DISCOVERY_ENUM_BYTES = MAX_COMPACT_DISCOVERY_SCHEMA_BYTES / 4;
|
|
5
|
+
const MAX_COMPACT_DISCOVERY_CONSTRAINT_BYTES = MAX_COMPACT_DISCOVERY_SCHEMA_BYTES / 4;
|
|
5
6
|
const schemaEncoder = new TextEncoder();
|
|
6
7
|
const COMPACT_DISCOVERY_TRUNCATION = " /* truncated */";
|
|
7
8
|
export function summarizeDescription(text, full) {
|
|
@@ -166,6 +167,26 @@ function matchingTokenCandidates(term) {
|
|
|
166
167
|
}
|
|
167
168
|
return candidates;
|
|
168
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* Whether one query term matches a whole token of arbitrary text, under the
|
|
172
|
+
* same inflection rules the tool index uses.
|
|
173
|
+
*
|
|
174
|
+
* Connector identity — an `id` or a `title` — is deliberately not a document in
|
|
175
|
+
* that index: making it one would move ranking for every query that already
|
|
176
|
+
* matches tools. This lets a caller ask the index's question of a string that
|
|
177
|
+
* never became a document, which is what the no-match analysis needs to tell
|
|
178
|
+
* "nothing like this exists here" from "that word is a connector".
|
|
179
|
+
*/
|
|
180
|
+
export function matchesLexicalTerm(text, term) {
|
|
181
|
+
const tokens = new Set(lexicalTokens(text));
|
|
182
|
+
if (tokens.size === 0)
|
|
183
|
+
return false;
|
|
184
|
+
for (const candidate of matchingTokenCandidates(term)) {
|
|
185
|
+
if (tokens.has(candidate))
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
169
190
|
/**
|
|
170
191
|
* Compute query-specific document frequencies across every available catalog.
|
|
171
192
|
* The caller does this once per search and shares the result with each
|
|
@@ -303,7 +324,8 @@ function declaresShape(s) {
|
|
|
303
324
|
s.const !== undefined ||
|
|
304
325
|
s.items !== undefined ||
|
|
305
326
|
s.properties !== undefined ||
|
|
306
|
-
s.type !== undefined
|
|
327
|
+
s.type !== undefined ||
|
|
328
|
+
constraintEntries(s).length > 0);
|
|
307
329
|
}
|
|
308
330
|
/**
|
|
309
331
|
* Parenthesize a top-level union so it doesn't read as part of a surrounding
|
|
@@ -346,6 +368,56 @@ function renderEnum(values, byteLimit, onTruncated) {
|
|
|
346
368
|
}
|
|
347
369
|
return rendered;
|
|
348
370
|
}
|
|
371
|
+
function safeConstraintValue(value) {
|
|
372
|
+
return JSON.stringify(value).replaceAll("*/", "*\\/");
|
|
373
|
+
}
|
|
374
|
+
function constraintEntries(schema) {
|
|
375
|
+
const entries = [];
|
|
376
|
+
const number = (keyword, label) => {
|
|
377
|
+
const value = schema[keyword];
|
|
378
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
379
|
+
entries.push(`${label} ${value}`);
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
const integer = (keyword, label) => {
|
|
383
|
+
const value = schema[keyword];
|
|
384
|
+
if (typeof value === "number" && Number.isInteger(value) && value >= 0) {
|
|
385
|
+
entries.push(`${label} ${value}`);
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
number("minimum", ">=");
|
|
389
|
+
number("exclusiveMinimum", ">");
|
|
390
|
+
number("maximum", "<=");
|
|
391
|
+
number("exclusiveMaximum", "<");
|
|
392
|
+
number("multipleOf", "multiple of");
|
|
393
|
+
integer("minLength", "length >=");
|
|
394
|
+
integer("maxLength", "length <=");
|
|
395
|
+
if (typeof schema.format === "string") {
|
|
396
|
+
entries.push(`format ${safeConstraintValue(schema.format)}`);
|
|
397
|
+
}
|
|
398
|
+
if (typeof schema.pattern === "string") {
|
|
399
|
+
entries.push(`pattern ${safeConstraintValue(schema.pattern)}`);
|
|
400
|
+
}
|
|
401
|
+
return entries;
|
|
402
|
+
}
|
|
403
|
+
function renderConstraints(base, schema, byteLimit, onTruncated) {
|
|
404
|
+
const entries = constraintEntries(schema);
|
|
405
|
+
if (entries.length === 0)
|
|
406
|
+
return base;
|
|
407
|
+
const kept = [];
|
|
408
|
+
for (const entry of entries) {
|
|
409
|
+
const candidate = ` /* ${[...kept, entry].join("; ")} */`;
|
|
410
|
+
if (byteLimit !== undefined &&
|
|
411
|
+
schemaEncoder.encode(candidate).length > byteLimit) {
|
|
412
|
+
onTruncated?.();
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
kept.push(entry);
|
|
416
|
+
}
|
|
417
|
+
return kept.length === 0
|
|
418
|
+
? base
|
|
419
|
+
: `${grouped(base)} /* ${kept.join("; ")} */`;
|
|
420
|
+
}
|
|
349
421
|
function renderSchema(schema, defs, seen, depth, options) {
|
|
350
422
|
if (depth > 4)
|
|
351
423
|
return "…";
|
|
@@ -385,24 +457,36 @@ function renderSchema(schema, defs, seen, depth, options) {
|
|
|
385
457
|
seen.add(name);
|
|
386
458
|
const rendered = renderSchema(target, defs, seen, depth, options);
|
|
387
459
|
seen.delete(name);
|
|
388
|
-
return
|
|
460
|
+
return options.renderConstraints
|
|
461
|
+
? renderConstraints(rendered, s, options.constraintByteLimit, options.onConstraintTruncated)
|
|
462
|
+
: rendered;
|
|
389
463
|
}
|
|
390
464
|
const union = (s.oneOf ?? s.anyOf);
|
|
391
465
|
if (Array.isArray(union)) {
|
|
392
|
-
|
|
466
|
+
const rendered = union
|
|
393
467
|
.map((u) => renderSchema(u, defs, seen, depth + 1, options))
|
|
394
468
|
.join(" | ") ||
|
|
395
|
-
"unknown"
|
|
469
|
+
"unknown";
|
|
470
|
+
return options.renderConstraints
|
|
471
|
+
? renderConstraints(rendered, s, options.constraintByteLimit, options.onConstraintTruncated)
|
|
472
|
+
: rendered;
|
|
396
473
|
}
|
|
397
474
|
if (Array.isArray(s.enum)) {
|
|
398
|
-
|
|
475
|
+
const rendered = renderEnum(s.enum, options.enumByteLimit, options.onEnumTruncated);
|
|
476
|
+
return options.renderConstraints
|
|
477
|
+
? renderConstraints(rendered, s, options.constraintByteLimit, options.onConstraintTruncated)
|
|
478
|
+
: rendered;
|
|
399
479
|
}
|
|
400
480
|
// Checked before type/properties so a discriminator like
|
|
401
481
|
// { type: "string", const: "emoji" } renders as "emoji" rather than string.
|
|
402
482
|
// JSON.stringify(undefined) returns undefined (not a string), so an explicit
|
|
403
483
|
// `const: undefined` must fall through to the regular type rendering.
|
|
404
|
-
if (s.const !== undefined)
|
|
405
|
-
|
|
484
|
+
if (s.const !== undefined) {
|
|
485
|
+
const rendered = JSON.stringify(s.const);
|
|
486
|
+
return options.renderConstraints
|
|
487
|
+
? renderConstraints(rendered, s, options.constraintByteLimit, options.onConstraintTruncated)
|
|
488
|
+
: rendered;
|
|
489
|
+
}
|
|
406
490
|
const type = s.type;
|
|
407
491
|
if (type === "array" || s.items) {
|
|
408
492
|
const items = s.items
|
|
@@ -434,10 +518,20 @@ function renderSchema(schema, defs, seen, depth, options) {
|
|
|
434
518
|
})
|
|
435
519
|
.join(", ")} }`;
|
|
436
520
|
}
|
|
437
|
-
if (typeof type === "string")
|
|
438
|
-
return
|
|
439
|
-
|
|
440
|
-
|
|
521
|
+
if (typeof type === "string") {
|
|
522
|
+
return options.renderConstraints
|
|
523
|
+
? renderConstraints(type, s, options.constraintByteLimit, options.onConstraintTruncated)
|
|
524
|
+
: type;
|
|
525
|
+
}
|
|
526
|
+
if (Array.isArray(type)) {
|
|
527
|
+
const rendered = type.join(" | ");
|
|
528
|
+
return options.renderConstraints
|
|
529
|
+
? renderConstraints(rendered, s, options.constraintByteLimit, options.onConstraintTruncated)
|
|
530
|
+
: rendered;
|
|
531
|
+
}
|
|
532
|
+
if (options.renderConstraints && constraintEntries(s).length > 0) {
|
|
533
|
+
return renderConstraints("unknown", s, options.constraintByteLimit, options.onConstraintTruncated);
|
|
534
|
+
}
|
|
441
535
|
return JSON.stringify(schema);
|
|
442
536
|
}
|
|
443
537
|
const compactSchemas = new WeakMap();
|
|
@@ -455,6 +549,7 @@ export function compactSchema(schema) {
|
|
|
455
549
|
rendered = renderSchema(schema, defs, new Set(), 0, {
|
|
456
550
|
propertyDescriptions: true,
|
|
457
551
|
requiredFirst: false,
|
|
552
|
+
renderConstraints: true,
|
|
458
553
|
});
|
|
459
554
|
}
|
|
460
555
|
catch {
|
|
@@ -514,6 +609,7 @@ export function compactDiscoverySchema(schema) {
|
|
|
514
609
|
};
|
|
515
610
|
let rendered;
|
|
516
611
|
let enumTruncated = false;
|
|
612
|
+
let constraintTruncated = false;
|
|
517
613
|
try {
|
|
518
614
|
rendered = renderSchema(schema, defs, new Set(), 0, {
|
|
519
615
|
propertyDescriptions: false,
|
|
@@ -525,15 +621,41 @@ export function compactDiscoverySchema(schema) {
|
|
|
525
621
|
onEnumTruncated: () => {
|
|
526
622
|
enumTruncated = true;
|
|
527
623
|
},
|
|
624
|
+
renderConstraints: true,
|
|
625
|
+
constraintByteLimit: MAX_COMPACT_DISCOVERY_CONSTRAINT_BYTES,
|
|
626
|
+
onConstraintTruncated: () => {
|
|
627
|
+
constraintTruncated = true;
|
|
628
|
+
},
|
|
528
629
|
});
|
|
529
630
|
}
|
|
530
631
|
catch {
|
|
531
632
|
rendered = JSON.stringify(schema);
|
|
532
633
|
}
|
|
634
|
+
if (schemaEncoder.encode(rendered).length >
|
|
635
|
+
MAX_COMPACT_DISCOVERY_SCHEMA_BYTES) {
|
|
636
|
+
try {
|
|
637
|
+
rendered = renderSchema(schema, defs, new Set(), 0, {
|
|
638
|
+
propertyDescriptions: false,
|
|
639
|
+
requiredFirst: true,
|
|
640
|
+
enumByteLimit: MAX_COMPACT_DISCOVERY_ENUM_BYTES,
|
|
641
|
+
onEnumTruncated: () => {
|
|
642
|
+
enumTruncated = true;
|
|
643
|
+
},
|
|
644
|
+
renderConstraints: false,
|
|
645
|
+
});
|
|
646
|
+
constraintTruncated = true;
|
|
647
|
+
}
|
|
648
|
+
catch {
|
|
649
|
+
rendered = JSON.stringify(schema);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
533
652
|
const bytes = schemaEncoder.encode(rendered);
|
|
534
653
|
let result;
|
|
535
654
|
if (bytes.length <= MAX_COMPACT_DISCOVERY_SCHEMA_BYTES) {
|
|
536
|
-
result = {
|
|
655
|
+
result = {
|
|
656
|
+
text: rendered,
|
|
657
|
+
truncated: enumTruncated || constraintTruncated,
|
|
658
|
+
};
|
|
537
659
|
}
|
|
538
660
|
else {
|
|
539
661
|
result = {
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Machine-readable classification of a failed connector tool call.
|
|
3
|
+
*
|
|
4
|
+
* A code earns its place by changing what the caller does next, never by
|
|
5
|
+
* naming a cause — the rule provider conventions call H11.
|
|
6
|
+
*/
|
|
7
|
+
export type ConnectorCallErrorCode = "timeout" | "auth_required" | "rate_limited" | "unavailable" | "invalid_args"
|
|
8
|
+
/**
|
|
9
|
+
* The downstream answered, and the thing addressed is not there.
|
|
10
|
+
*
|
|
11
|
+
* Its own code because the next move is none of the others': not a retry,
|
|
12
|
+
* not `authorize_connector`, not a reshaped argument object, but
|
|
13
|
+
* re-addressing — look the identifier up again, or accept the absence and
|
|
14
|
+
* carry on. Inside `execute_code` a program reads that difference from a
|
|
15
|
+
* caught error's `code` or a `connecta.batch` entry's `errorDetails.code` —
|
|
16
|
+
* continue past this one, abort on `connector_call_failed`. Message prose
|
|
17
|
+
* cannot be classified.
|
|
18
|
+
*
|
|
19
|
+
* Use it only where the provider distinguishes absence from a permission
|
|
20
|
+
* gap. A status that means both "it is not there" and "you cannot see it" —
|
|
21
|
+
* Notion's `object_not_found` is the worked example — stays
|
|
22
|
+
* `connector_call_failed` with a message that states the ambiguity, because
|
|
23
|
+
* inventing certainty here is how an agent concludes a page was deleted when
|
|
24
|
+
* it was simply never shared. Addresses connecta itself cannot resolve are
|
|
25
|
+
* already framed as `unknown_address` or `unknown_tool` and never reach a
|
|
26
|
+
* connector, so this code is always about a resource the downstream owns.
|
|
27
|
+
*/
|
|
28
|
+
| "not_found" | "input_required_unsupported" | "connector_call_failed";
|
|
3
29
|
/** One bounded, payload-free explanation of an input-schema mismatch. */
|
|
4
30
|
export interface ArgumentValidationIssue {
|
|
5
31
|
/** JSON Pointer into the submitted arguments; "/" means the root value. */
|
package/dist/errors.js
CHANGED
package/dist/execute.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/server";
|
|
2
2
|
import type { ActivityRequestContext } from "./activity.js";
|
|
3
|
+
import type { DeferredWork } from "./connector-scope.js";
|
|
3
4
|
import { type ToolResult } from "./meta-tools.js";
|
|
4
5
|
import { InvocationFailure } from "./invocation.js";
|
|
5
6
|
import type { RegistryView } from "./registry.js";
|
|
@@ -157,6 +158,8 @@ export declare function buildSandboxProviders(registry: RegistryView, baseUrl: s
|
|
|
157
158
|
* blocks nobody will ever return.
|
|
158
159
|
*/
|
|
159
160
|
emitCollector?: EmitCollector;
|
|
161
|
+
/** Runtime-owned tail for stale catalog refreshes. */
|
|
162
|
+
defer?: DeferredWork;
|
|
160
163
|
}): Promise<ExecutorProvider[]>;
|
|
161
164
|
/** The execute_code handler. Exported for direct testing. */
|
|
162
165
|
export declare function createExecuteTool(registry: RegistryView, baseUrl: string, executor: Executor, logger: Logger, activity?: ActivityRequestContext, config?: {
|
|
@@ -164,6 +167,7 @@ export declare function createExecuteTool(registry: RegistryView, baseUrl: strin
|
|
|
164
167
|
probeTimeoutMs?: number;
|
|
165
168
|
maxEmittedBytes?: number;
|
|
166
169
|
maxEmittedBlocks?: number;
|
|
170
|
+
defer?: DeferredWork;
|
|
167
171
|
}): ({ code, diagnostics: diagnosticsRequested }: {
|
|
168
172
|
code: string;
|
|
169
173
|
diagnostics?: boolean;
|
|
@@ -189,5 +193,6 @@ export declare function registerExecuteTool(server: McpServer, registry: Registr
|
|
|
189
193
|
maxEmittedBytes?: number;
|
|
190
194
|
/** Block-count budget for connecta.emit. Default 32. */
|
|
191
195
|
maxEmittedBlocks?: number;
|
|
196
|
+
defer?: DeferredWork;
|
|
192
197
|
}): void;
|
|
193
198
|
export {};
|