@zackbart/connecta 0.10.6 → 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.
- package/AGENTS.md +8 -6
- package/CHANGELOG.md +40 -0
- package/README.md +5 -4
- package/bin/connecta.mjs +0 -7
- package/dist/activity.d.ts.map +1 -1
- package/dist/activity.js.map +1 -1
- package/dist/catalog-service.d.ts +2 -17
- package/dist/catalog-service.d.ts.map +1 -1
- package/dist/catalog-service.js +4 -6
- package/dist/catalog-service.js.map +1 -1
- package/dist/connectors/api.d.ts +2 -2
- package/dist/connectors/remote-mcp.d.ts +1 -1
- package/dist/errors.d.ts +1 -3
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/execute.d.ts +1 -3
- package/dist/execute.d.ts.map +1 -1
- package/dist/execute.js +7 -28
- package/dist/execute.js.map +1 -1
- package/dist/index.d.ts +15 -31
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -37
- package/dist/index.js.map +1 -1
- package/dist/invocation.js +2 -2
- package/dist/invocation.js.map +1 -1
- package/dist/meta-tools.d.ts +19 -58
- package/dist/meta-tools.d.ts.map +1 -1
- package/dist/meta-tools.js +34 -431
- package/dist/meta-tools.js.map +1 -1
- package/dist/registry.d.ts +1 -10
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +3 -15
- package/dist/registry.js.map +1 -1
- package/dist/routes/mcp.d.ts.map +1 -1
- package/dist/routes/mcp.js +19 -30
- package/dist/routes/mcp.js.map +1 -1
- package/dist/routes/shared.d.ts +5 -11
- package/dist/routes/shared.d.ts.map +1 -1
- package/dist/routes/shared.js.map +1 -1
- package/dist/server.js +5 -4
- package/dist/server.js.map +1 -1
- package/dist/skills.d.ts +8 -18
- package/dist/skills.d.ts.map +1 -1
- package/dist/skills.js +13 -60
- package/dist/skills.js.map +1 -1
- package/dist/types.d.ts +6 -20
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/code-first-exploration.md +16 -16
- package/documentation/code-mode.md +21 -35
- package/documentation/connectors.md +1 -1
- package/documentation/meta-tools.md +30 -43
- package/documentation/rich-output-design.md +4 -4
- package/examples/node/README.md +1 -2
- package/examples/node/src/index.ts +1 -3
- package/examples/worker/README.md +8 -13
- package/examples/worker/src/index.ts +6 -14
- package/examples/worker/wrangler.jsonc +3 -6
- package/package.json +1 -1
- package/src/activity.ts +5 -0
- package/src/catalog-service.ts +6 -26
- package/src/connectors/api.ts +2 -2
- package/src/connectors/remote-mcp.ts +1 -1
- package/src/errors.ts +2 -2
- package/src/execute.ts +7 -36
- package/src/index.ts +40 -69
- package/src/invocation.ts +2 -2
- package/src/meta-tools.ts +38 -565
- package/src/registry.ts +2 -33
- package/src/routes/mcp.ts +19 -30
- package/src/routes/shared.ts +4 -11
- package/src/server.ts +7 -7
- package/src/skills.ts +11 -74
- package/src/types.ts +6 -21
- package/src/version.ts +1 -1
- package/templates/node/README.md +2 -1
- package/templates/node/package.json +1 -1
- package/templates/node/src/index.ts +1 -1
package/src/registry.ts
CHANGED
|
@@ -34,8 +34,6 @@ const DEFAULT_STALE_SECONDS = 3600;
|
|
|
34
34
|
const CATALOG_CHUNK_TTL_GRACE_SECONDS = 300;
|
|
35
35
|
const DEFAULT_MAX_RESULT_BYTES = 50_000;
|
|
36
36
|
const encoder = new TextEncoder();
|
|
37
|
-
/** Independent final-envelope boundary for `batch_call`. */
|
|
38
|
-
const DEFAULT_MAX_BATCH_RESULT_BYTES = 100_000;
|
|
39
37
|
|
|
40
38
|
/**
|
|
41
39
|
* Split `"<connectorId>.<toolName>"` on the first dot. Connector ids contain
|
|
@@ -189,11 +187,6 @@ export interface RegistryOptions {
|
|
|
189
187
|
* to the default 50_000.
|
|
190
188
|
*/
|
|
191
189
|
maxResultBytes?: number;
|
|
192
|
-
/**
|
|
193
|
-
* Cap on the complete serialized batch_call envelope. Must be a whole number
|
|
194
|
-
* of bytes >= 1; anything else warns and falls back to 100_000.
|
|
195
|
-
*/
|
|
196
|
-
maxBatchResultBytes?: number;
|
|
197
190
|
}
|
|
198
191
|
|
|
199
192
|
function namespaced(storage: KVStorage, prefix: string): KVStorage {
|
|
@@ -225,8 +218,6 @@ export type ConnectorOperationOptions = Pick<
|
|
|
225
218
|
export interface RegistryView {
|
|
226
219
|
/** Deployment-wide result-size cap threaded to the meta-tools. */
|
|
227
220
|
readonly maxResultBytes: number;
|
|
228
|
-
/** Independent cap for the complete serialized batch_call envelope. */
|
|
229
|
-
readonly maxBatchResultBytes: number;
|
|
230
221
|
listConnectors(): Connector[];
|
|
231
222
|
getConnector(id: string): Connector | undefined;
|
|
232
223
|
resolveAddress(
|
|
@@ -302,8 +293,6 @@ export class Registry implements RegistryView {
|
|
|
302
293
|
private readonly persistToolCatalog: boolean;
|
|
303
294
|
/** Result-size guard cap threaded to the meta-tools. */
|
|
304
295
|
readonly maxResultBytes: number;
|
|
305
|
-
/** Final batch envelope cap threaded to the meta-tools. */
|
|
306
|
-
readonly maxBatchResultBytes: number;
|
|
307
296
|
|
|
308
297
|
constructor(
|
|
309
298
|
connectors: Connector[],
|
|
@@ -318,10 +307,6 @@ export class Registry implements RegistryView {
|
|
|
318
307
|
opts.maxResultBytes,
|
|
319
308
|
DEFAULT_MAX_RESULT_BYTES,
|
|
320
309
|
);
|
|
321
|
-
this.maxBatchResultBytes = resolveMaxResultBytes(
|
|
322
|
-
opts.maxBatchResultBytes,
|
|
323
|
-
DEFAULT_MAX_BATCH_RESULT_BYTES,
|
|
324
|
-
);
|
|
325
310
|
for (const c of connectors) {
|
|
326
311
|
if (!ID_RE.test(c.id)) {
|
|
327
312
|
throw new Error(
|
|
@@ -340,11 +325,7 @@ export class Registry implements RegistryView {
|
|
|
340
325
|
}
|
|
341
326
|
}
|
|
342
327
|
this.checkConventions(opts.logger);
|
|
343
|
-
this.checkResultCaps(
|
|
344
|
-
opts.logger,
|
|
345
|
-
opts.maxResultBytes,
|
|
346
|
-
opts.maxBatchResultBytes,
|
|
347
|
-
);
|
|
328
|
+
this.checkResultCaps(opts.logger, opts.maxResultBytes);
|
|
348
329
|
}
|
|
349
330
|
|
|
350
331
|
/**
|
|
@@ -358,7 +339,6 @@ export class Registry implements RegistryView {
|
|
|
358
339
|
private checkResultCaps(
|
|
359
340
|
logger: Logger,
|
|
360
341
|
configured: number | undefined,
|
|
361
|
-
configuredBatch: number | undefined,
|
|
362
342
|
): void {
|
|
363
343
|
if (configured !== undefined && !isValidMaxResultBytes(configured)) {
|
|
364
344
|
logger.warn(
|
|
@@ -368,17 +348,6 @@ export class Registry implements RegistryView {
|
|
|
368
348
|
`default ${DEFAULT_MAX_RESULT_BYTES} instead.`,
|
|
369
349
|
);
|
|
370
350
|
}
|
|
371
|
-
if (
|
|
372
|
-
configuredBatch !== undefined &&
|
|
373
|
-
!isValidMaxResultBytes(configuredBatch)
|
|
374
|
-
) {
|
|
375
|
-
logger.warn(
|
|
376
|
-
`[connecta] calls.maxBatchResultBytes ${configuredBatch} is not a whole ` +
|
|
377
|
-
`number of bytes >= ${MIN_MAX_RESULT_BYTES}: it would leave the final ` +
|
|
378
|
-
"batch envelope unbounded or serve an unusable page. Using the " +
|
|
379
|
-
`default ${DEFAULT_MAX_BATCH_RESULT_BYTES} instead.`,
|
|
380
|
-
);
|
|
381
|
-
}
|
|
382
351
|
for (const c of this.connectors.values()) {
|
|
383
352
|
if (
|
|
384
353
|
c.maxResultBytes !== undefined &&
|
|
@@ -1059,7 +1028,7 @@ export class Registry implements RegistryView {
|
|
|
1059
1028
|
}
|
|
1060
1029
|
}
|
|
1061
1030
|
|
|
1062
|
-
/** Best-effort connector status for
|
|
1031
|
+
/** Best-effort connector status for the operator UI. */
|
|
1063
1032
|
async statusFor(
|
|
1064
1033
|
id: string,
|
|
1065
1034
|
baseUrl: string,
|
package/src/routes/mcp.ts
CHANGED
|
@@ -192,13 +192,9 @@ async function serveMcp(
|
|
|
192
192
|
registry: RegistryView,
|
|
193
193
|
runtimeContext?: RuntimeExecutionContext,
|
|
194
194
|
): Promise<Response> {
|
|
195
|
-
// One deployment-wide value, read once here so the instructions, the
|
|
196
|
-
// registered tools, and the guidance the `skills` tool serves cannot
|
|
197
|
-
// disagree about which surface this deployment advertises.
|
|
198
|
-
const surface = opts.surface ?? "classic";
|
|
199
195
|
const createServer = (): McpServer => {
|
|
200
196
|
const server = new McpServer(opts.serverInfo, {
|
|
201
|
-
instructions: instructionsFor(
|
|
197
|
+
instructions: instructionsFor(),
|
|
202
198
|
cacheHints: {
|
|
203
199
|
"tools/list": {
|
|
204
200
|
ttlMs: 3_600_000,
|
|
@@ -223,7 +219,6 @@ async function serveMcp(
|
|
|
223
219
|
: undefined;
|
|
224
220
|
registerMetaTools(server, registry, {
|
|
225
221
|
baseUrl,
|
|
226
|
-
surface,
|
|
227
222
|
...(activity ? { activity } : {}),
|
|
228
223
|
...(opts.defaultToolTimeoutMs !== undefined
|
|
229
224
|
? { defaultToolTimeoutMs: opts.defaultToolTimeoutMs }
|
|
@@ -235,32 +230,26 @@ async function serveMcp(
|
|
|
235
230
|
? { discoveryConcurrency: opts.discoveryConcurrency }
|
|
236
231
|
: {}),
|
|
237
232
|
requestSignal: request.signal,
|
|
238
|
-
|
|
239
|
-
|
|
233
|
+
});
|
|
234
|
+
registerExecuteTool(server, registry, {
|
|
235
|
+
baseUrl,
|
|
236
|
+
executor: opts.executor,
|
|
237
|
+
logger: opts.logger,
|
|
238
|
+
...(activity ? { activity } : {}),
|
|
239
|
+
requestSignal: request.signal,
|
|
240
|
+
...(opts.discoveryConcurrency !== undefined
|
|
241
|
+
? { discoveryConcurrency: opts.discoveryConcurrency }
|
|
242
|
+
: {}),
|
|
243
|
+
...(opts.probeTimeoutMs !== undefined
|
|
244
|
+
? { probeTimeoutMs: opts.probeTimeoutMs }
|
|
245
|
+
: {}),
|
|
246
|
+
...(opts.maxEmittedBytes !== undefined
|
|
247
|
+
? { maxEmittedBytes: opts.maxEmittedBytes }
|
|
248
|
+
: {}),
|
|
249
|
+
...(opts.maxEmittedBlocks !== undefined
|
|
250
|
+
? { maxEmittedBlocks: opts.maxEmittedBlocks }
|
|
240
251
|
: {}),
|
|
241
252
|
});
|
|
242
|
-
if (opts.executor) {
|
|
243
|
-
registerExecuteTool(server, registry, {
|
|
244
|
-
baseUrl,
|
|
245
|
-
surface,
|
|
246
|
-
executor: opts.executor,
|
|
247
|
-
logger: opts.logger,
|
|
248
|
-
...(activity ? { activity } : {}),
|
|
249
|
-
requestSignal: request.signal,
|
|
250
|
-
...(opts.discoveryConcurrency !== undefined
|
|
251
|
-
? { discoveryConcurrency: opts.discoveryConcurrency }
|
|
252
|
-
: {}),
|
|
253
|
-
...(opts.probeTimeoutMs !== undefined
|
|
254
|
-
? { probeTimeoutMs: opts.probeTimeoutMs }
|
|
255
|
-
: {}),
|
|
256
|
-
...(opts.maxEmittedBytes !== undefined
|
|
257
|
-
? { maxEmittedBytes: opts.maxEmittedBytes }
|
|
258
|
-
: {}),
|
|
259
|
-
...(opts.maxEmittedBlocks !== undefined
|
|
260
|
-
? { maxEmittedBlocks: opts.maxEmittedBlocks }
|
|
261
|
-
: {}),
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
253
|
return server;
|
|
265
254
|
};
|
|
266
255
|
|
package/src/routes/shared.ts
CHANGED
|
@@ -7,7 +7,6 @@ import type { AdmissionController } from "../executor-admission.js";
|
|
|
7
7
|
import type { Registry } from "../registry.js";
|
|
8
8
|
import type {
|
|
9
9
|
ConnectaBranding,
|
|
10
|
-
ConnectaSurface,
|
|
11
10
|
Executor,
|
|
12
11
|
InboundAuth,
|
|
13
12
|
Logger,
|
|
@@ -26,9 +25,9 @@ export interface ServerOptions {
|
|
|
26
25
|
activityReadGate?: ActivityReadGate;
|
|
27
26
|
activityDeploymentId?: string;
|
|
28
27
|
deploymentInfo?: Record<string, unknown>;
|
|
29
|
-
/** Deadline for call_tool/
|
|
28
|
+
/** Deadline for call_tool/call_destructive_tool calls that pass no timeoutMs. Off when unset. */
|
|
30
29
|
defaultToolTimeoutMs?: number;
|
|
31
|
-
/** Per-connector deadline for the
|
|
30
|
+
/** Per-connector deadline for the search/describe probe fan-out. Default 30_000. */
|
|
32
31
|
probeTimeoutMs?: number;
|
|
33
32
|
/** Maximum simultaneous connector discovery operations. Default 4. */
|
|
34
33
|
discoveryConcurrency?: number;
|
|
@@ -36,14 +35,8 @@ export interface ServerOptions {
|
|
|
36
35
|
maxEmittedBytes?: number;
|
|
37
36
|
/** Block-count budget for connecta.emit per run. Default 32. */
|
|
38
37
|
maxEmittedBlocks?: number;
|
|
39
|
-
/**
|
|
40
|
-
executor
|
|
41
|
-
/**
|
|
42
|
-
* The advertised model-facing surface. createConnecta() always resolves it
|
|
43
|
-
* from the executor; absent (a direct createFetchHandler() caller) is
|
|
44
|
-
* classic, and `code-first` is only ever set alongside an `executor`.
|
|
45
|
-
*/
|
|
46
|
-
surface?: ConnectaSurface;
|
|
38
|
+
/** Required sandbox backing the execute_code meta-tool. */
|
|
39
|
+
executor: Executor;
|
|
47
40
|
/** Global FIFO boundary for all non-preflight `/mcp` requests. */
|
|
48
41
|
requestAdmission: AdmissionController;
|
|
49
42
|
/** Encrypted connector-credential storage backing the Credentials page. */
|
package/src/server.ts
CHANGED
|
@@ -122,10 +122,12 @@ export function createFetchHandler(
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
if (path === "/health") {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
125
|
+
// The executor is required, so code admission always has a shape to
|
|
126
|
+
// report: either the executor's own pool or the fallback controller
|
|
127
|
+
// wrapped around it at construction.
|
|
128
|
+
const codeAdmission = isAdmittingExecutor(opts.executor)
|
|
129
|
+
? opts.executor.admissionSnapshot?.()
|
|
130
|
+
: undefined;
|
|
129
131
|
return Response.json({
|
|
130
132
|
status: "ok",
|
|
131
133
|
connectors: registry.listConnectors().length,
|
|
@@ -133,9 +135,7 @@ export function createFetchHandler(
|
|
|
133
135
|
admission: {
|
|
134
136
|
policy: "global-fifo",
|
|
135
137
|
requests: opts.requestAdmission.snapshot(),
|
|
136
|
-
code:
|
|
137
|
-
? (codeAdmission ?? { managedByExecutor: true })
|
|
138
|
-
: null,
|
|
138
|
+
code: codeAdmission ?? { managedByExecutor: true },
|
|
139
139
|
downstreamCalls: {
|
|
140
140
|
policy: "connector-partitioned-per-runtime",
|
|
141
141
|
connectors: registry.callAdmissionSnapshot(),
|
package/src/skills.ts
CHANGED
|
@@ -1,47 +1,10 @@
|
|
|
1
|
-
import type { Connector
|
|
1
|
+
import type { Connector } from "./types.js";
|
|
2
2
|
|
|
3
3
|
export const CONNECTA_INSTRUCTIONS =
|
|
4
|
-
'Connecta exposes integrations behind meta-tools. Unknown address: use search_tools with 2–4 distinctive action/object terms, no initial limit, and includeSchemas="compact"; describe_tools only if that shape is ambiguous or exact JSON constraints are needed. Use call_tool for one explicitly read-only call, batch_call for 2–10 independent read-only calls, and execute_code (when available) only for dependencies, loops, joins, or substantial reduction — searching inside that one run rather than searching first. Use call_destructive_tool individually for unannotated, write-capable, or destructive tools. authorize_connector follows auth_required; get_result follows truncation. If this routing is unfamiliar, fetch skills({ name: "usage" }).';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* The instructions a code-first deployment loads (#224). It never names
|
|
8
|
-
* `list_connectors`, `describe_tools`, or `batch_call` — not even to say they
|
|
9
|
-
* are gone. Always-loaded text describes the surface that exists; a sentence
|
|
10
|
-
* about three tools this deployment does not have is context paid for the past,
|
|
11
|
-
* and a model that names one anyway gets an unknown-tool error, which is a
|
|
12
|
-
* cheaper correction than the tokens the disclaimer costs every request.
|
|
13
|
-
*/
|
|
14
|
-
export const CODE_FIRST_INSTRUCTIONS =
|
|
15
4
|
'Connecta exposes integrations behind seven meta-tools, and execute_code is the primary one: write an async arrow function and use connecta.search (empty query browses every catalog), connecta.describe, connecta.call, and connecta.batch inside it for discovery, two or more calls, dependent steps, loops, joins, and reducing large results before they reach you. For a single read at an unknown address, search_tools with 2–4 distinctive action/object terms and includeSchemas="compact", then one call_tool — a lone cold call is cheaper direct than through a program. Use call_destructive_tool individually for unannotated, write-capable, or destructive tools; authorize_connector follows auth_required; get_result follows truncation. If this routing is unfamiliar, fetch skills({ name: "usage" }).';
|
|
16
5
|
|
|
17
6
|
export const USAGE_SKILL = `# Connecta usage
|
|
18
7
|
|
|
19
|
-
## Choose the smallest execution tool
|
|
20
|
-
|
|
21
|
-
Use exact addresses returned by discovery; never invent one. Search with 2–4 distinctive action/object terms rather than the full request, and omit \`limit\` initially so the default page stays small.
|
|
22
|
-
|
|
23
|
-
- Unknown address: \`search_tools({ query, includeSchemas: "compact" })\`; every match then includes its input shape plus any declared output shape and annotations.
|
|
24
|
-
- Compact shape still ambiguous: \`describe_tools({ addresses: [...] })\`; use \`format: "json"\` only for exact constraints.
|
|
25
|
-
- One explicitly read-only call: \`call_tool\`.
|
|
26
|
-
- Two to ten independent explicitly read-only calls: \`batch_call\`.
|
|
27
|
-
- Dependent read-only calls, loops, joins, branching, or large-result reduction: \`execute_code\` when available.
|
|
28
|
-
- Any unannotated, write-capable, or destructive call: \`call_destructive_tool\`, individually and only after reviewing its schema and consequences.
|
|
29
|
-
- Truncated result: retry with \`fields\` when possible; otherwise page it with \`get_result\`.
|
|
30
|
-
- \`auth_required\`: use \`authorize_connector\`, give its recovery handoff to the operator, then retry the original call.
|
|
31
|
-
|
|
32
|
-
Use \`list_connectors({ probe: false })\` for a fast observed-health inventory; use \`probe: true\` only to diagnose live health or authorization.
|
|
33
|
-
|
|
34
|
-
## Code mode
|
|
35
|
-
|
|
36
|
-
Unknown addresses plus dependent calls: search inside the run, not in an outer \`search_tools\`. Parallelize independent calls with \`Promise.all\` or \`connecta.batch\`.
|
|
37
|
-
|
|
38
|
-
Connector namespace calls and \`connecta.call\` use the same read-only gate and throw on downstream errors. Catch only failures the workflow can handle; let authorization failures return to the agent for recovery.
|
|
39
|
-
|
|
40
|
-
Skip code mode for one call, calls suited to \`batch_call\`, or tools lacking \`readOnlyHint: true\`. Return only the needed reduction.
|
|
41
|
-
`;
|
|
42
|
-
|
|
43
|
-
export const CODE_FIRST_USAGE_SKILL = `# Connecta usage
|
|
44
|
-
|
|
45
8
|
## The surface
|
|
46
9
|
|
|
47
10
|
Seven tools: \`execute_code\`, \`search_tools\`, \`call_tool\`, \`call_destructive_tool\`, \`authorize_connector\`, \`get_result\`, \`skills\`. Broad discovery and multi-call work live inside a program rather than in top-level tools.
|
|
@@ -76,21 +39,12 @@ One async arrow function. The only capabilities are one global per connector (\`
|
|
|
76
39
|
export const CONNECTOR_GUIDES_SECTION = `
|
|
77
40
|
## Per-connector guides
|
|
78
41
|
|
|
79
|
-
Some connectors here ship their own usage guide — preferred tools, address quirks, pagination conventions, rate-limit etiquette, query patterns. \`skills({})\` lists each one as \`connector:<connectorId>\`; fetch it with \`skills({ name: "connector:<connectorId>" })\`. \`search_tools\` and \`describe_tools\` set \`guide\` on matches whose connector has one. Read a connector's guide before working with it for the first time in a task.
|
|
80
|
-
`;
|
|
81
|
-
|
|
82
|
-
/** The same section, naming only surfaces a code-first deployment has. */
|
|
83
|
-
const CODE_FIRST_CONNECTOR_GUIDES_SECTION = `
|
|
84
|
-
## Per-connector guides
|
|
85
|
-
|
|
86
42
|
Some connectors here ship their own usage guide — preferred tools, address quirks, pagination conventions, rate-limit etiquette, query patterns. \`skills({})\` lists each one as \`connector:<connectorId>\`; fetch it with \`skills({ name: "connector:<connectorId>" })\`. \`search_tools\`, \`connecta.search\`, and \`connecta.describe\` set \`guide\` on matches whose connector has one. Read a connector's guide before working with it for the first time in a task.
|
|
87
43
|
`;
|
|
88
44
|
|
|
89
|
-
/** The always-loaded MCP `instructions` string
|
|
90
|
-
export function instructionsFor(
|
|
91
|
-
return
|
|
92
|
-
? CODE_FIRST_INSTRUCTIONS
|
|
93
|
-
: CONNECTA_INSTRUCTIONS;
|
|
45
|
+
/** The always-loaded MCP `instructions` string. */
|
|
46
|
+
export function instructionsFor(): string {
|
|
47
|
+
return CONNECTA_INSTRUCTIONS;
|
|
94
48
|
}
|
|
95
49
|
|
|
96
50
|
/** True when at least one of `connectors` carries a usage guide. */
|
|
@@ -101,27 +55,15 @@ export function hasConnectorGuides(connectors: readonly Connector[]): boolean {
|
|
|
101
55
|
}
|
|
102
56
|
|
|
103
57
|
/** The built-in usage guide, plus the guides section when there is one to point at. */
|
|
104
|
-
function usageSkill(
|
|
105
|
-
connectors
|
|
106
|
-
|
|
107
|
-
): string {
|
|
108
|
-
const base =
|
|
109
|
-
surface === "code-first" ? CODE_FIRST_USAGE_SKILL : USAGE_SKILL;
|
|
110
|
-
if (!hasConnectorGuides(connectors)) return base;
|
|
111
|
-
return (
|
|
112
|
-
base +
|
|
113
|
-
(surface === "code-first"
|
|
114
|
-
? CODE_FIRST_CONNECTOR_GUIDES_SECTION
|
|
115
|
-
: CONNECTOR_GUIDES_SECTION)
|
|
116
|
-
);
|
|
58
|
+
function usageSkill(connectors: readonly Connector[]): string {
|
|
59
|
+
if (!hasConnectorGuides(connectors)) return USAGE_SKILL;
|
|
60
|
+
return USAGE_SKILL + CONNECTOR_GUIDES_SECTION;
|
|
117
61
|
}
|
|
118
62
|
|
|
119
63
|
const AVAILABLE_SKILLS = [
|
|
120
64
|
{
|
|
121
65
|
name: "usage",
|
|
122
66
|
description:
|
|
123
|
-
"How to choose among Connecta discovery, direct, batch, destructive, and code-mode tools.",
|
|
124
|
-
codeFirstDescription:
|
|
125
67
|
"How to route work between one execute_code program and Connecta's explicit call, authorization, and result tools.",
|
|
126
68
|
content: usageSkill,
|
|
127
69
|
},
|
|
@@ -212,14 +154,10 @@ export interface SkillListing {
|
|
|
212
154
|
* carries a usage guide. Derived from the connector list passed in — the single
|
|
213
155
|
* place guide visibility is decided.
|
|
214
156
|
*/
|
|
215
|
-
export function listSkills(
|
|
216
|
-
connectors: readonly Connector[],
|
|
217
|
-
surface: ConnectaSurface = "classic",
|
|
218
|
-
): SkillListing[] {
|
|
157
|
+
export function listSkills(connectors: readonly Connector[]): SkillListing[] {
|
|
219
158
|
const listing: SkillListing[] = AVAILABLE_SKILLS.map((skill) => ({
|
|
220
159
|
name: skill.name,
|
|
221
|
-
description:
|
|
222
|
-
surface === "code-first" ? skill.codeFirstDescription : skill.description,
|
|
160
|
+
description: skill.description,
|
|
223
161
|
}));
|
|
224
162
|
for (const connector of connectors) {
|
|
225
163
|
const guide = connectorGuide(connector);
|
|
@@ -244,14 +182,13 @@ export type SkillLookup =
|
|
|
244
182
|
export function resolveSkill(
|
|
245
183
|
name: string,
|
|
246
184
|
connectors: readonly Connector[],
|
|
247
|
-
surface: ConnectaSurface = "classic",
|
|
248
185
|
): SkillLookup {
|
|
249
186
|
const builtIn = AVAILABLE_SKILLS.find((skill) => skill.name === name);
|
|
250
187
|
if (builtIn) {
|
|
251
|
-
return { found: true, content: builtIn.content(connectors
|
|
188
|
+
return { found: true, content: builtIn.content(connectors) };
|
|
252
189
|
}
|
|
253
190
|
const available = () =>
|
|
254
|
-
listSkills(connectors
|
|
191
|
+
listSkills(connectors)
|
|
255
192
|
.map((skill) => skill.name)
|
|
256
193
|
.join(", ");
|
|
257
194
|
if (name.startsWith(CONNECTOR_SKILL_PREFIX)) {
|
package/src/types.ts
CHANGED
|
@@ -35,8 +35,8 @@ export interface ToolDef {
|
|
|
35
35
|
/**
|
|
36
36
|
* Standard MCP tool behavior hints plus provider-specific extensions.
|
|
37
37
|
* Connecta fails closed: only readOnlyHint === true (without a contradictory
|
|
38
|
-
* destructiveHint) may use call_tool
|
|
39
|
-
*
|
|
38
|
+
* destructiveHint) may use call_tool or execute_code. Every other tool must
|
|
39
|
+
* cross the call_destructive_tool approval boundary.
|
|
40
40
|
*/
|
|
41
41
|
annotations?: ToolAnnotations;
|
|
42
42
|
}
|
|
@@ -198,7 +198,7 @@ export interface Connector {
|
|
|
198
198
|
description?: string;
|
|
199
199
|
/**
|
|
200
200
|
* Max inline result size (bytes) for this connector's tools before
|
|
201
|
-
* call_tool
|
|
201
|
+
* call_tool truncates and stashes the full text for get_result
|
|
202
202
|
* paging. Overrides `ConnectaConfig.calls.maxResultBytes`;
|
|
203
203
|
* omit to inherit it (which itself defaults to 50_000). Must be a whole
|
|
204
204
|
* number of bytes >= 1; anything else warns at startup and is ignored, so
|
|
@@ -207,8 +207,8 @@ export interface Connector {
|
|
|
207
207
|
maxResultBytes?: number;
|
|
208
208
|
/**
|
|
209
209
|
* Optional per-runtime admission policy for downstream tool calls. It covers
|
|
210
|
-
* call_tool,
|
|
211
|
-
* catalog/status/auth operations.
|
|
210
|
+
* call_tool, call_destructive_tool, and every execute_code host call, but
|
|
211
|
+
* not catalog/status/auth operations.
|
|
212
212
|
*/
|
|
213
213
|
callAdmission?: ConnectorCallAdmissionPolicy;
|
|
214
214
|
/**
|
|
@@ -255,7 +255,7 @@ export interface Connector {
|
|
|
255
255
|
* request-local reuse remains in force until the request boundary.
|
|
256
256
|
*/
|
|
257
257
|
closeScope?(ctx: ConnectorContext): Promise<void>;
|
|
258
|
-
/** Optional connector-level health/auth status for
|
|
258
|
+
/** Optional connector-level health/auth status for the operator UI. */
|
|
259
259
|
status?(ctx: ConnectorContext): Promise<ConnectorStatus>;
|
|
260
260
|
/**
|
|
261
261
|
* Optional: start (or with force, restart from scratch) a downstream OAuth
|
|
@@ -309,21 +309,6 @@ export interface Connector {
|
|
|
309
309
|
): Promise<Response | null>;
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
-
/**
|
|
313
|
-
* Which model-facing surface a deployment advertises. The `executor` decides
|
|
314
|
-
* it; this type is how a deployment overrides that.
|
|
315
|
-
*
|
|
316
|
-
* - `code-first`: seven tools, the default wherever an executor is configured.
|
|
317
|
-
* `list_connectors`, `describe_tools`, and `batch_call` are not top-level
|
|
318
|
-
* tools; their behavior lives in `connecta.search`, `connecta.describe`, and
|
|
319
|
-
* `connecta.batch` inside a program.
|
|
320
|
-
* - `classic`: the nine base meta-tools, plus `execute_code` when an executor
|
|
321
|
-
* is configured. Without an executor it is what a deployment necessarily
|
|
322
|
-
* serves and the eval gate's control arm; with one it is the ten-tool shape
|
|
323
|
-
* the gate's incremental arm measures, and the only thing `surface` is for.
|
|
324
|
-
*/
|
|
325
|
-
export type ConnectaSurface = "classic" | "code-first";
|
|
326
|
-
|
|
327
312
|
/** Result of one sandboxed code execution. */
|
|
328
313
|
export interface ExecuteResult {
|
|
329
314
|
result: unknown;
|
package/src/version.ts
CHANGED
package/templates/node/README.md
CHANGED
|
@@ -13,7 +13,8 @@ Then point an MCP client at `http://localhost:8787/mcp` with
|
|
|
13
13
|
## Deployment contract
|
|
14
14
|
|
|
15
15
|
- Edit `src/index.ts` for connectors, auth, storage, and the public URL.
|
|
16
|
-
- Keep `executor: quickJsExecutor()`
|
|
16
|
+
- Keep the required `executor: quickJsExecutor()` configuration; a deployment
|
|
17
|
+
without an executor refuses to boot.
|
|
17
18
|
- Keep secrets in environment variables or an external secret store.
|
|
18
19
|
- Add application code only inside deliberate `api()` connector handlers.
|
|
19
20
|
- Do not copy Connecta package internals into this deployment.
|
|
@@ -21,7 +21,7 @@ const connecta = createConnecta({
|
|
|
21
21
|
storage: fileStorage("./.connecta-state.json"),
|
|
22
22
|
auth: bearerToken(token, { subjectId: "operator" }),
|
|
23
23
|
publicUrl: `http://localhost:${port}`,
|
|
24
|
-
//
|
|
24
|
+
// Required: model-written programs run in a bounded QuickJS child.
|
|
25
25
|
executor: quickJsExecutor(),
|
|
26
26
|
connectors: [
|
|
27
27
|
api("time", {
|