@zackbart/connecta 0.22.3 → 0.23.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 +42 -0
- package/README.md +1 -1
- package/dist/catalog-service.d.ts +1 -6
- package/dist/catalog-service.js +3 -53
- package/dist/errors.d.ts +1 -1
- package/dist/execute.d.ts +5 -52
- package/dist/execute.js +40 -347
- package/dist/executors/quickjs-protocol.d.ts +0 -7
- package/dist/executors/quickjs-protocol.js +2 -10
- package/dist/executors/quickjs.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/invocation.d.ts +0 -33
- package/dist/invocation.js +54 -121
- package/dist/meta-tools.d.ts +3 -6
- package/dist/meta-tools.js +6 -17
- package/dist/registry.js +4 -0
- package/dist/routes/mcp.js +0 -48
- package/dist/server.d.ts +1 -2
- package/dist/server.js +1 -19
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +55 -19
- package/dist/types.d.ts +1 -15
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/architecture.md +7 -11
- package/documentation/auth.md +4 -5
- package/documentation/call-admission.md +10 -11
- package/documentation/code-mode.md +65 -260
- package/documentation/connectors.md +7 -5
- package/documentation/meta-tools.md +31 -14
- package/documentation/operations.md +7 -9
- package/documentation/provider-conventions.md +2 -2
- package/documentation/upgrading.md +58 -8
- package/ethos.md +14 -13
- package/package.json +1 -1
- package/templates/node/package.json +1 -1
- package/dist/apps-shell.d.ts +0 -37
- package/dist/apps-shell.js +0 -174
package/dist/skills.js
CHANGED
|
@@ -1,59 +1,58 @@
|
|
|
1
|
-
export const CONNECTA_INSTRUCTIONS = 'Choose a route before discovery. A known-address read needs only call_tool. Unknown-address read-only work starts with
|
|
1
|
+
export const CONNECTA_INSTRUCTIONS = 'Choose a route before discovery. A known-address read needs only call_tool. Unknown-address read-only work starts with execute_code to discover, call, and return the answer; use the same route for reduction, multiple or dependent calls, loops, joins, or branches. Keep discovery and calls together when schemas suffice; do not return catalog matches alone. Inspect unfamiliar result shapes with a small sample before proceeding. Only readOnlyHint: true tools run there. Keep catalog inspection and unannotated, write-capable, or destructive work top level: search_tools then call_destructive_tool when a call is needed. After auth_required use authorize_connector. After a truncated direct result use get_result. Guidance is on demand: fetch skills({ name: "usage" }) only when these instructions and the tool description are insufficient or a run needs repair.';
|
|
2
2
|
const USAGE_SKILL_BASE = `# Connecta usage
|
|
3
3
|
|
|
4
4
|
## The surface
|
|
5
5
|
|
|
6
6
|
Seven tools: \`execute_code\`, \`search_tools\`, \`call_tool\`, \`call_destructive_tool\`, \`authorize_connector\`, \`get_result\`, \`skills\`. Read-only discovery and multi-call work live in a program. Top-level search remains for catalog inspection and approval-required work.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Follow the MCP instructions for routing. Read at most once for syntax or repair.
|
|
9
9
|
|
|
10
10
|
## Inside a program
|
|
11
11
|
|
|
12
|
-
Write one plain-JavaScript async arrow function
|
|
12
|
+
Write one plain-JavaScript async arrow function, without TypeScript or imports. Return reduced JSON-shaped data.
|
|
13
13
|
|
|
14
14
|
The minimum guest API is:
|
|
15
15
|
|
|
16
|
-
- \`<connectorId>.<toolName>(args)\` calls a sanitized shortcut. Non-identifier characters become \`_\`; leading digits gain \`_\`; reserved words gain a trailing \`_\`.
|
|
17
16
|
- \`connecta.call("connector.tool", args)\` uses the canonical address and returns the unwrapped value.
|
|
18
17
|
- \`connecta.search(args)\` returns \`{ tools, total, offset, limit, hasMore }\`; \`connecta.describe(args)\` returns \`{ tools }\`.
|
|
19
|
-
- \`
|
|
20
|
-
- \`console.log(...)\` is captured. \`connecta.emit(block)\`
|
|
18
|
+
- Use \`Promise.all\` for independent calls, or \`Promise.allSettled\` to keep successes and failures.
|
|
19
|
+
- \`console.log(...)\` is captured. \`connecta.emit(block)\` produces rich output.
|
|
21
20
|
|
|
22
21
|
## Discover and select
|
|
23
22
|
|
|
24
|
-
Search
|
|
23
|
+
Search and call in one run when schemas suffice. For unfamiliar result formats, return a small sample and continue; do not guess a parser. Use 2–4 distinctive action/object terms; search distinct operations separately.
|
|
25
24
|
|
|
26
|
-
For top-level catalog inspection or approval-required discovery, omit \`limit\` initially (the default is
|
|
25
|
+
For top-level catalog inspection or approval-required discovery, omit \`limit\` initially (the default is 8), then page with a limit up to 50 if needed. Empty or whitespace-only queries browse all tools. A non-empty query with no ASCII terms returns no matches; mixed input searches with its ASCII terms. \`includeSchemas: "compact"\` adds bounded input and available output shapes. An \`outputSchemaSource: "observed"\` shape is a hint, not a contract. Plain objects expose \`inputKeys\`, \`requiredInputKeys\`, and \`outputKeys\`; truncation flags mark incomplete shapes; matches also carry declared annotations.
|
|
27
26
|
|
|
28
27
|
- \`connecta.search({})\` loads all catalogs. Pass \`connector: "<id>"\` when the integration is obvious. Use \`safety: "readOnly"\` for program calls. These inputs filter discovery; they grant no authority.
|
|
29
|
-
-
|
|
28
|
+
- Use \`includeSchemas: "json"\` for programmatic schema inspection; compact schemas are text, not objects with \`.properties\`. Check connectorTitle for the account/environment, then address, purpose, annotations, inputs, and outputs. Never select only because a result ranks first or has fewer required inputs.
|
|
30
29
|
- Supply every \`requiredInputKey\` from the task or a prior result. For dependencies, match the earlier \`outputKey\` to the later required key. An empty required-key list does not permit invented arguments. Missing \`outputKeys\` means inspect \`outputSchema\`.
|
|
31
30
|
- Use \`connecta.describe({ address })\` or \`{ addresses }\` when a compact schema is truncated or insufficient. Use \`format: "json"\` only for exact constraints. Write the property names the schema displays; never guess positions or aliases.
|
|
32
|
-
- Reduce through available output keys. Treat an observed key as a hint, since later results may omit it or add others. Do not guess collection roots such as \`items\` or \`results\`. If a match
|
|
31
|
+
- Reduce through available output keys. Treat an observed key as a hint, since later results may omit it or add others. Do not guess collection roots such as \`items\` or \`results\`. If a match is missing, re-search or describe. If a result shape is unclear, return a small sample for inspection before continuing.
|
|
33
32
|
- Match provider identifiers and names exactly after resolving them from source data or a connector guide. A broad regular expression that merely finds a plausible value is not identity resolution.
|
|
34
|
-
- Preserve the schema's JSON types exactly: a numeric id is a number, not a numeric-looking string.
|
|
33
|
+
- Preserve the schema's JSON types exactly: a numeric id is a number, not a numeric-looking string.
|
|
35
34
|
- Validate tabular headers, row arrays, and row widths before mapping them. Never let a header or partial row become data.
|
|
36
35
|
|
|
37
36
|
Only tools explicitly annotated \`readOnlyHint: true\` are reachable. The catalog, credential, admission, and read-only gates run below the sandbox; code cannot widen its authority.
|
|
38
37
|
|
|
39
38
|
## Errors and repair
|
|
40
39
|
|
|
41
|
-
Caught Connecta errors expose \`message\`, \`code\`, \`retryable\`, and \`details\`.
|
|
40
|
+
Caught Connecta errors expose \`message\`, \`code\`, \`retryable\`, and \`details\`. Promise rejections retain these fields. Branch on fields, never prose. After a shared argument failure, repair one call before repeating it across other records. Do not retry \`retryable: false\`, and do not retry \`rate_limited\` immediately because portable code has no timer.
|
|
42
41
|
|
|
43
42
|
- \`destructive_tool_requires_approval\`: stop the program and use the returned canonical address with top-level \`call_destructive_tool\`.
|
|
44
43
|
- \`auth_required\`: let the failure reach the model, then use top-level \`authorize_connector\`, give its handoff to the operator, and retry after recovery.
|
|
45
44
|
- A truncated direct-call result: follow its \`get_result\` action. A truncated program result has no page handle; filter, map, or slice inside a new program.
|
|
46
45
|
- Unknown addresses and tools carry scoped search recovery. Use it inside the current run. Do not invent an address.
|
|
47
46
|
|
|
48
|
-
For a direct call, \`resultMode: "value"\` unwraps the result. \`timeoutMs\` sets its deadline.
|
|
47
|
+
For a direct call, \`resultMode: "value"\` unwraps the result. \`timeoutMs\` sets its deadline. Every call makes one attempt; use the returned error classification and retry hint to decide whether to reissue. \`diagnostics: true\` adds timing.
|
|
49
48
|
|
|
50
49
|
\`get_result({ id, offset?, maxBytes? })\` returns \`{ text, offset, nextOffset?, totalBytes }\` for a direct-call result. Both sizes are byte counts: \`maxBytes\` must be a whole number at least 1 and defaults to the deployment cap; \`offset\` must be a whole number at least 0 and defaults to 0. An offset inside a multi-byte character moves back to its first byte, and the response reports the served offset. Follow \`nextOffset\` to reassemble pages. An unknown or expired id is an error.
|
|
51
50
|
|
|
52
|
-
Limits: 20 host calls per run
|
|
51
|
+
Limits: 20 host calls per run and a 15-second deadline per host call.
|
|
53
52
|
|
|
54
53
|
## Runtime portability
|
|
55
54
|
|
|
56
|
-
Portable code uses
|
|
55
|
+
Portable code uses standard JavaScript builtins, \`connecta\`, and \`console.*\`. QuickJS blocks imports and lacks fetch, process, timers, crypto, and WebSocket. Dynamic Workers must use only \`{ loader }\`; bindings, modules, or globalOutbound grant ambient authority. With loader only, environment maps are empty; node:fs/http/https are absent; outbound fetch, WebSocket, node:net, and node:tls are denied; DNS is unresolved. Runtime builtins remain through \`import()\` and \`process.getBuiltinModule()\`, including node:path and cloudflare:workers; this set can drift. Timers, process, crypto, WebSocket, and data: fetch remain. Avoid every runtime-only capability because QuickJS fails.
|
|
57
56
|
|
|
58
57
|
## Examples
|
|
59
58
|
|
|
@@ -61,13 +60,29 @@ One read-only call at a known address:
|
|
|
61
60
|
|
|
62
61
|
\`async () => await connecta.call("crm.get_account", { id: "acct_42" })\`
|
|
63
62
|
|
|
64
|
-
Dependent
|
|
63
|
+
Dependent lookup: verify connector \`ci\`, run 42, and these schema fields first.
|
|
65
64
|
|
|
66
|
-
|
|
65
|
+
\`\`\`js
|
|
66
|
+
async () => {
|
|
67
|
+
const find = async name => {
|
|
68
|
+
const page = await connecta.search({ connector: "ci", query: name, safety: "readOnly", includeSchemas: "compact" });
|
|
69
|
+
if (page.queryAnalysis?.catalogError) throw new Error(JSON.stringify(page.queryAnalysis.catalogError));
|
|
70
|
+
return page.tools.find(tool => tool.name === name);
|
|
71
|
+
};
|
|
72
|
+
const runTool = await find("get_run");
|
|
73
|
+
if (!runTool) return { gap: "Run lookup not resolved" };
|
|
74
|
+
const run = await connecta.call(runTool.address, { runId: 42 });
|
|
75
|
+
if (!run.failedJobId) return { status: run.status, gap: "No failed job identified" };
|
|
76
|
+
const logsTool = await find("get_job_logs");
|
|
77
|
+
if (!logsTool) return { status: run.status, gap: "Job logs not resolved" };
|
|
78
|
+
const logs = await connecta.call(logsTool.address, { jobId: run.failedJobId });
|
|
79
|
+
return logs.filter(row => row.level === "error").map(({ timestamp, message }) => ({ timestamp, message }));
|
|
80
|
+
}
|
|
81
|
+
\`\`\`
|
|
67
82
|
|
|
68
|
-
##
|
|
83
|
+
## Media output
|
|
69
84
|
|
|
70
|
-
\`connecta.emit\` accepts text, image, or audio blocks and delivers them only on success.
|
|
85
|
+
\`connecta.emit\` accepts text, image, or audio blocks and delivers them only on success. Its byte and block budgets are separate from the JSON return budget. Return data for the client to render as a view.
|
|
71
86
|
|
|
72
87
|
`;
|
|
73
88
|
/** Deployment-scoped guide routing appended to the shared usage guide. */
|
|
@@ -95,12 +110,33 @@ export function hasConnectorGuides(connectors) {
|
|
|
95
110
|
function usageSkill(_connectors) {
|
|
96
111
|
return USAGE_SKILL;
|
|
97
112
|
}
|
|
113
|
+
const INVESTIGATE_SKILL = `# Investigate across services
|
|
114
|
+
|
|
115
|
+
## Plan the investigation
|
|
116
|
+
|
|
117
|
+
Start from the user's question and the evidence that would answer it. Select the app, account, and environment from connector titles, purposes, and relevant guides before looking up records. Reuse verified ids within the task; never carry an id across connectors just because its name matches.
|
|
118
|
+
|
|
119
|
+
- Purchase verification: resolve the same customer and environment across payment, subscription access, and analytics. Check each separately; a recorded payment does not prove access, and a missing analytics event does not prove payment failure.
|
|
120
|
+
- Experiment checks: confirm the project, experiment, time window, and exposure population before comparing outcomes. Return the requested comparison and any missing evidence; do not expand into an unrelated analytics audit.
|
|
121
|
+
- Customer or deployment investigations: locate the exact customer or deployment first, then follow only the records needed to explain the reported symptom. Use provider links or ids so the answer can be checked.
|
|
122
|
+
|
|
123
|
+
Establish capability limits early. A partial search is not proof that a tool is absent, and an unavailable catalog is not an empty dataset. Try a scoped search for the missing operation, inspect its guide when relevant, and distinguish unsupported work from missing data or authorization. If the required evidence is unavailable, return what was verified and the specific gap instead of approximating a different question through repeated calls.
|
|
124
|
+
|
|
125
|
+
A host transport error that requires reconnecting this MCP server cannot be repaired by a downstream tool. Reconnect in the host; do not repeatedly call \`authorize_connector\` through the failed connection.
|
|
126
|
+
|
|
127
|
+
Return the answer first, then the evidence and any unresolved gap. Include the app/environment, time window, and source ids or links needed to check it. Separate observed facts from inferences. Stop when the requested evidence is sufficient.
|
|
128
|
+
`;
|
|
98
129
|
const AVAILABLE_SKILLS = [
|
|
99
130
|
{
|
|
100
131
|
name: "usage",
|
|
101
132
|
description: "How to route work between one execute_code program and Connecta's explicit call, authorization, and result tools.",
|
|
102
133
|
content: usageSkill,
|
|
103
134
|
},
|
|
135
|
+
{
|
|
136
|
+
name: "investigate",
|
|
137
|
+
description: "Plan purchase verification, experiment checks, and customer or deployment investigations across services; resolve scope and capability limits before querying.",
|
|
138
|
+
content: () => INVESTIGATE_SKILL,
|
|
139
|
+
},
|
|
104
140
|
];
|
|
105
141
|
/**
|
|
106
142
|
* Namespace for operator-authored per-connector guides. Built-in skill names
|
package/dist/types.d.ts
CHANGED
|
@@ -312,19 +312,6 @@ export interface Connector {
|
|
|
312
312
|
* server's RFC 9207 `iss` response parameter for SDK validation.
|
|
313
313
|
*/
|
|
314
314
|
finishAuth?(code: string, ctx: ConnectorContext, callbackParams?: URLSearchParams): Promise<void>;
|
|
315
|
-
/**
|
|
316
|
-
* Optional: serve a connector-owned HTTP route — for example a signed
|
|
317
|
-
* download link minted by one of the connector's tools. Called only after
|
|
318
|
-
* every built-in route misses, so a connector can never shadow `/mcp`,
|
|
319
|
-
* `/`, `/credentials`, `/activity`, `/health`, or the credential API. The
|
|
320
|
-
* first connector to return a Response wins, in registration order; return
|
|
321
|
-
* null to decline. See documentation/architecture.md route 9.
|
|
322
|
-
*
|
|
323
|
-
* These routes are PUBLIC: connecta applies no auth gate to them. A
|
|
324
|
-
* connector that serves data here MUST authenticate the request itself — for
|
|
325
|
-
* example with a signed capability token in the URL.
|
|
326
|
-
*/
|
|
327
|
-
handleRequest?(request: Request, ctx: ConnectorContext): Promise<Response | null>;
|
|
328
315
|
}
|
|
329
316
|
export interface ConnectorUsageGuide {
|
|
330
317
|
/** Markdown returned verbatim by `skills({ name: "connector:<id>" })`. */
|
|
@@ -355,8 +342,7 @@ export interface ExecutorProvider {
|
|
|
355
342
|
fns: Record<string, (...args: unknown[]) => Promise<unknown>>;
|
|
356
343
|
/**
|
|
357
344
|
* Optional trusted sandbox-side setup run after provider globals exist.
|
|
358
|
-
* Connecta uses this to
|
|
359
|
-
* materializing one host closure per tool. This is host-authored code, never
|
|
345
|
+
* Connecta uses this to restore typed host errors. This is host-authored code, never
|
|
360
346
|
* model input. See documentation/code-mode.md#what-an-executor-must-implement.
|
|
361
347
|
*/
|
|
362
348
|
prelude?: string;
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
|
@@ -71,11 +71,10 @@ read top to bottom.
|
|
|
71
71
|
| 3 | `/.well-known/*` | Auth providers' `handleMetadata`, open. 404 when none handles it. |
|
|
72
72
|
| 4 | `/health` | Open JSON: status, connector count, `serverInfo`, the configured executor's sanitized name when it has one, catalog-drift counts, admission snapshots, reserved route names, and `deployment` when `deploymentInfo` is set. Payload-free by construction, and it never joins the MCP queue. |
|
|
73
73
|
| 5 | `/oauth/callback/<connectorId>` | Downstream-OAuth completion, open, `verifyState` before `finishAuth`. Personal flows first resolve the short-lived state hash to the principal partition. |
|
|
74
|
-
| 6 | `/favicon.*`, `/ui` → `/`, the operator shells, `/ui/data` | The operator surface ([operator UI](./operator-ui.md)). The shells are open and data-free; `/ui/data` behind them is gated.
|
|
74
|
+
| 6 | `/favicon.*`, `/ui` → `/`, the operator shells, `/ui/data` | The operator surface ([operator UI](./operator-ui.md)). The shells are open and data-free; `/ui/data` behind them is gated. |
|
|
75
75
|
| 7 | `/ui/activity` | Gated, plus the optional `activity.readGate`. `GET` only; 404 with no `activity.store.list`. |
|
|
76
76
|
| 8 | `/mcp` | **Admission before auth**, then the auth gate, then a fresh MCP server. |
|
|
77
|
-
| 9 |
|
|
78
|
-
| 10 | — | 404. |
|
|
77
|
+
| 9 | — | 404. Custom HTTP routes belong to the deployment. |
|
|
79
78
|
|
|
80
79
|
Every response leaves through `withSecurityHeaders`: `nosniff`, a no-referrer
|
|
81
80
|
policy, HSTS on HTTPS, and — on the operator shells — a nonce-based script CSP
|
|
@@ -83,7 +82,7 @@ and framing denial. `test/server-route-contracts.test.ts` pins this ordering
|
|
|
83
82
|
and the exact refusal bodies; it exists because the ordering is invisible in
|
|
84
83
|
any one file and a reordering reads like a harmless refactor.
|
|
85
84
|
|
|
86
|
-
`/mcp` itself is
|
|
85
|
+
`/mcp` itself is five steps, in this order and for these reasons:
|
|
87
86
|
|
|
88
87
|
1. **Admit.** One permit from the deployment-wide FIFO pool, taken before auth
|
|
89
88
|
so an unauthenticated flood costs a permit rather than a Clerk lookup
|
|
@@ -102,8 +101,7 @@ any one file and a reordering reads like a harmless refactor.
|
|
|
102
101
|
than silently serving the full registry. Retiring a scoping boundary into
|
|
103
102
|
fail-open is the one outcome worse than the 404.
|
|
104
103
|
5. **Serve.** A fresh `McpServer` per request, the seven meta-tools registered
|
|
105
|
-
against the registry
|
|
106
|
-
`resources/list` deliberately answering with nothing), and the response
|
|
104
|
+
against the registry and the response
|
|
107
105
|
handed back.
|
|
108
106
|
|
|
109
107
|
## Layers below the meta-tools
|
|
@@ -115,7 +113,7 @@ owns or hands out, and a change usually belongs in exactly one of them:
|
|
|
115
113
|
| --- | --- |
|
|
116
114
|
| `src/registry.ts` | The connector set, identity-scoped views, personal storage partitions, address resolution, catalog TTL/persistence/completeness, refresh single-flight, connector health, per-connector call limiters, and drift. Construction-time refusals live here. |
|
|
117
115
|
| `src/catalog-service.ts` | Request-local tool listing, search, and describe. It coalesces reads inside one request and opts agent reads into the runtime's deferred catalog channel when one exists. |
|
|
118
|
-
| `src/invocation.ts` | One tool call: argument validation, call admission,
|
|
116
|
+
| `src/invocation.ts` | One tool call: argument validation, call admission, one-attempt timeout, provider retry hints, result unwrapping, size capping, and the activity record. |
|
|
119
117
|
| `src/catalog.ts` | Ranking, description summarizing, and the compact schema renderer discovery shows. |
|
|
120
118
|
| `src/result-shapes.ts` | Bounded runtime-only inference and merging for output shapes learned from successful read-only calls whose providers declared none. |
|
|
121
119
|
|
|
@@ -162,8 +160,7 @@ src/
|
|
|
162
160
|
server.ts route ordering, HTTPS upgrade, security wrapper
|
|
163
161
|
routes/ one file per surface; shared.ts holds the auth gate
|
|
164
162
|
meta-tools.ts the six non-execute meta-tools over the registry
|
|
165
|
-
execute.ts execute_code, the sandbox host bridge,
|
|
166
|
-
apps-shell.ts the one build-time MCP Apps template
|
|
163
|
+
execute.ts execute_code, the sandbox host bridge, emitted media
|
|
167
164
|
skills.ts MCP instructions, the usage skill, connector guides
|
|
168
165
|
registry.ts connector set, addresses, health, call limiters
|
|
169
166
|
catalog-service.ts request-local catalog access, search, and describe
|
|
@@ -194,8 +191,7 @@ src/
|
|
|
194
191
|
authenticated subject. Anything cached per request still dies with it.
|
|
195
192
|
Putting a downstream client or credential on the wrong side of those lines
|
|
196
193
|
is the highest-severity mistake available here.
|
|
197
|
-
- **Route order is behavior.** Moving a
|
|
198
|
-
hands a connector the ability to shadow it. Moving a mutation route below the
|
|
194
|
+
- **Route order is behavior.** Moving a mutation route below the
|
|
199
195
|
wildcard `OPTIONS` opts it into CORS preflight.
|
|
200
196
|
- **Admission runs before auth, on purpose.** Reordering them to "authenticate
|
|
201
197
|
first" makes the cheapest possible attack the most expensive request.
|
package/documentation/auth.md
CHANGED
|
@@ -133,14 +133,13 @@ through the
|
|
|
133
133
|
|
|
134
134
|
Worker-level Access runs before every connecta route. Consequently:
|
|
135
135
|
|
|
136
|
-
- `/health`, operator pages, downstream OAuth callbacks,
|
|
137
|
-
routes, and `/mcp` all require Access unless a more-specific hostname/path
|
|
136
|
+
- `/health`, operator pages, downstream OAuth callbacks, and `/mcp` all require Access unless a more-specific hostname/path
|
|
138
137
|
policy says otherwise;
|
|
139
138
|
- a static connecta bearer and a `cta_…` token are not standalone edge
|
|
140
139
|
credentials, because Cloudflare rejects them before connecta sees them; and
|
|
141
|
-
-
|
|
142
|
-
|
|
143
|
-
|
|
140
|
+
- custom public webhooks belong to the deployment outside Connecta and need
|
|
141
|
+
their own Access routing policy. Keep Connecta's OAuth discovery paths
|
|
142
|
+
protected when Managed OAuth is enabled.
|
|
144
143
|
|
|
145
144
|
The [Worker example](../examples/worker/) carries the complete deployment shape
|
|
146
145
|
and the [upgrade guide](./upgrading.md#0200--0212) gives the reversible Clerk
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Downstream call admission
|
|
2
2
|
|
|
3
3
|
One admitted MCP request can fan out into many downstream calls. A program
|
|
4
|
-
calls tools from loops, from `connecta.
|
|
4
|
+
calls tools from loops, from parallel `connecta.call` calls, and from branches the caller
|
|
5
5
|
never saw. The deployment-wide request pool
|
|
6
6
|
([request admission](./request-admission.md)) bounds the envelope; it cannot
|
|
7
7
|
see anything inside it. A provider that publishes "60 requests per minute"
|
|
@@ -76,16 +76,15 @@ not be a way to reset a live budget. Exhausted partition capacity is
|
|
|
76
76
|
|
|
77
77
|
The registry owns the limiter, and `InvocationService.invoke` acquires a permit
|
|
78
78
|
immediately before `Connector.callTool` and releases it in `finally`. Both call
|
|
79
|
-
paths
|
|
80
|
-
|
|
79
|
+
paths, top-level `call_tool` and program calls through `connecta.call`,
|
|
80
|
+
reach that same seam, so a program cannot buy itself a
|
|
81
81
|
second limit by taking the other route.
|
|
82
82
|
|
|
83
|
-
- **A retry is another
|
|
84
|
-
entry
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
outcome and the attempt count.
|
|
83
|
+
- **A caller retry is another call.** It reacquires and can consume another
|
|
84
|
+
budget entry. Connecta returns retry hints without waiting or retrying.
|
|
85
|
+
- **A proactive short-window `rate_limited` refusal** returns its retry hint
|
|
86
|
+
without waiting or dispatching. Activity records one failed admission attempt;
|
|
87
|
+
a caller may reissue after the window.
|
|
89
88
|
- **A queued cancellation consumes nothing.** It is removed from the queue with
|
|
90
89
|
no rolling-window entry charged.
|
|
91
90
|
- **Caller cancellation is terminal.** It is non-retryable, releases its
|
|
@@ -114,7 +113,7 @@ from "we are throttling ourselves".
|
|
|
114
113
|
## Enforcement scope
|
|
115
114
|
|
|
116
115
|
This is deliberately **per-runtime**. It completely contains fan-out inside one
|
|
117
|
-
request, including
|
|
116
|
+
request, including parallel `connecta.call` calls in one Worker isolate. A rolling
|
|
118
117
|
budget is exact inside one Node process or Worker isolate, and best-effort
|
|
119
118
|
across isolates, replicas, and restarts.
|
|
120
119
|
|
|
@@ -139,5 +138,5 @@ typed error code.
|
|
|
139
138
|
| Invariant | Suite |
|
|
140
139
|
| --- | --- |
|
|
141
140
|
| Independent partitions, exact rolling-window reset and retry, queued cancellation charging no budget, synchronous cancel during partition derivation, validated values snapshotted rather than read from mutable config, bounded partition state and contained `partitionKey` failures, empty and multi-rule policies refused | `test/call-admission.test.ts` (controller) |
|
|
142
|
-
| One base-registry limiter shared by direct and program calls,
|
|
141
|
+
| One base-registry limiter shared by direct and program calls, promise concurrency with input order preserved, cancellation threading, no dispatch or retry or health poisoning after cancellation, retry hints returned without waiting or poisoning health, payload-free `/health` aggregates | `test/call-admission.test.ts` (integration, Node + Workers) |
|
|
143
142
|
| Where provider budgets are allowed to come from at all | [provider conventions P12](./provider-conventions.md#p12--declare-an-admission-budget-only-when-the-provider-documents-a-number), [provider audit](https://github.com/zackbart/connecta/blob/main/records/provider-audit.md) |
|