@zackbart/connecta 0.28.1 → 0.30.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 +855 -5
- package/README.md +125 -116
- package/bin/connecta.mjs +121 -139
- package/bin/meta-tool-names.d.mts +2 -0
- package/bin/meta-tool-names.mjs +9 -0
- package/bin/version.mjs +3 -0
- package/dist/access-tokens.js +53 -63
- package/dist/activity-request.js +8 -0
- package/dist/activity.d.ts +76 -42
- package/dist/activity.js +110 -42
- package/dist/argument-redaction.js +230 -0
- package/dist/auth/clerk-sdk/client.d.ts +65 -0
- package/dist/auth/clerk-sdk/client.js +5 -0
- package/dist/auth/clerk-sdk/generated.js +1845 -0
- package/dist/auth/clerk-transport.js +19 -0
- package/dist/auth/clerk.d.ts +17 -7
- package/dist/auth/clerk.js +189 -107
- package/dist/auth/cloudflare-access.js +25 -26
- package/dist/auth/downstream-client-metadata.d.ts +29 -0
- package/dist/auth/downstream-client-metadata.js +133 -0
- package/dist/auth/downstream-oauth.js +1584 -1580
- package/dist/auth/downstream-revocation.js +106 -0
- package/dist/auth/oauth-token-response.js +231 -0
- package/dist/auth/oauth-v2-migration.js +116 -0
- package/dist/auth/static-oauth.js +93 -71
- package/dist/auth-elicitation.js +288 -0
- package/dist/authorization-handoff.js +111 -0
- package/dist/branding.d.ts +8 -16
- package/dist/branding.js +26 -59
- package/dist/byte-read-response.js +39 -0
- package/dist/call-admission.js +12 -16
- package/dist/catalog-cache.js +739 -0
- package/dist/catalog-drift.d.ts +50 -15
- package/dist/catalog-drift.js +365 -128
- package/dist/catalog-fingerprint.js +2 -4
- package/dist/catalog-freshness.js +13 -0
- package/dist/catalog-limits.js +2 -2
- package/dist/catalog-service.js +409 -225
- package/dist/catalog.js +43 -84
- package/dist/concurrency.js +3 -4
- package/dist/config-defaults.d.ts +39 -0
- package/dist/config-defaults.js +46 -0
- package/dist/config-schema.d.ts +181 -0
- package/dist/config-schema.js +435 -0
- package/dist/config-value-sources.js +102 -0
- package/dist/config.d.ts +633 -0
- package/dist/config.js +508 -0
- package/dist/connector-access.d.ts +1 -0
- package/dist/connector-access.js +13 -15
- package/dist/connector-caller.d.ts +8 -0
- package/dist/connector-caller.js +15 -6
- package/dist/connector-scope.js +1 -1
- package/dist/connectors/api-connector.d.ts +59 -7
- package/dist/connectors/api-connector.js +106 -19
- package/dist/connectors/api.js +4 -1
- package/dist/connectors/guarded-fetch.d.ts +144 -0
- package/dist/connectors/guarded-fetch.js +87 -38
- package/dist/connectors/negotiation-cache.js +46 -0
- package/dist/connectors/option-shapes.js +27 -0
- package/dist/connectors/remote-mcp.d.ts +30 -4
- package/dist/connectors/remote-mcp.js +1774 -320
- package/dist/connectors/resource-uri.js +335 -0
- package/dist/credential-contract.d.ts +10 -0
- package/dist/credential-rules.js +1 -3
- package/dist/credential-url.js +108 -0
- package/dist/credentials.d.ts +6 -1
- package/dist/credentials.js +27 -18
- package/dist/d1.d.ts +130 -0
- package/dist/d1.js +290 -0
- package/dist/describe-config.d.ts +165 -0
- package/dist/describe-config.js +315 -0
- package/dist/described.js +106 -0
- package/dist/downstream-input-context.js +128 -0
- package/dist/downstream-input.js +325 -0
- package/dist/errors.d.ts +132 -31
- package/dist/errors.js +175 -87
- package/dist/execute.js +798 -318
- package/dist/executor-admission.d.ts +1 -0
- package/dist/executor-admission.js +11 -15
- package/dist/executor-contract.d.ts +20 -0
- package/dist/executor-contract.js +48 -0
- package/dist/executor-result.js +30 -13
- package/dist/executors/quickjs-child.js +15 -9
- package/dist/executors/quickjs-protocol.js +5 -6
- package/dist/executors/quickjs-runtime.js +152 -59
- package/dist/executors/quickjs.js +49 -39
- package/dist/favicon.js +1 -2
- package/dist/fix-prompt.js +1 -3
- package/dist/guest-runtime.js +238 -0
- package/dist/guest-types.d.ts +218 -0
- package/dist/guest-types.js +1 -0
- package/dist/html-security.js +24 -0
- package/dist/identity.js +1 -3
- package/dist/inbound-credential.js +52 -0
- package/dist/index.d.ts +24 -256
- package/dist/index.js +65 -478
- package/dist/invocation-auth.js +69 -0
- package/dist/invocation.js +262 -79
- package/dist/json-schema.d.ts +1 -1
- package/dist/mcp-client-context.js +35 -0
- package/dist/mcp-result.js +11 -7
- package/dist/meta-output.js +61 -0
- package/dist/meta-tool-names.d.ts +2 -0
- package/dist/meta-tool-names.js +3 -0
- package/dist/meta-tools.js +419 -272
- package/dist/module-contracts.d.ts +8 -23
- package/dist/node.d.ts +0 -2
- package/dist/node.js +2 -2
- package/dist/oauth-callback-outcome.js +1 -3
- package/dist/oauth-handoff.js +194 -0
- package/dist/oauth-sealing.js +20 -0
- package/dist/operator-record.d.ts +137 -0
- package/dist/operator-record.js +420 -0
- package/dist/operator-ui/assets.js +31 -0
- package/dist/operator-ui/contract.d.ts +72 -0
- package/dist/operator-ui/contract.js +1 -0
- package/dist/operator-ui/fix-prompts.d.ts +18 -0
- package/dist/operator-ui/generated.js +5 -4
- package/dist/operator-ui/model.d.ts +12 -87
- package/dist/operator-ui/model.js +2 -9
- package/dist/operator-ui/setup-commands.js +1 -3
- package/dist/operator-ui/view.d.ts +323 -0
- package/dist/operator-ui/view.js +62 -189
- package/dist/page-styles.js +2 -3
- package/dist/program-result.js +5 -0
- package/dist/program-source.js +14 -2
- package/dist/{exempt-writes.js → program-writes.js} +60 -19
- package/dist/provider.d.ts +142 -0
- package/dist/provider.js +187 -0
- package/dist/providers/_shared/google/result-size.js +57 -0
- package/dist/providers/_shared/google/service-account.d.ts +58 -0
- package/dist/providers/_shared/google/service-account.js +500 -0
- package/dist/providers/_shared/google/workspace.d.ts +276 -0
- package/dist/providers/_shared/google/workspace.js +518 -0
- package/dist/providers/_shared/request-token.js +83 -0
- package/dist/providers/{basecamp.d.ts → basecamp/index.d.ts} +6 -28
- package/dist/providers/basecamp/index.js +997 -0
- package/dist/providers/basecamp/skill.generated.js +9 -0
- package/dist/providers/{breeze.d.ts → breeze/index.d.ts} +2 -2
- package/dist/providers/{breeze.js → breeze/index.js} +184 -140
- package/dist/providers/breeze/skill.generated.js +9 -0
- package/dist/providers/{ccb.d.ts → ccb/index.d.ts} +2 -2
- package/dist/providers/{ccb.js → ccb/index.js} +271 -116
- package/dist/providers/ccb/skill.generated.js +9 -0
- package/dist/providers/{cloudflare.d.ts → cloudflare/index.d.ts} +8 -7
- package/dist/providers/{cloudflare.js → cloudflare/index.js} +171 -738
- package/dist/providers/cloudflare/skill.generated.js +10 -0
- package/dist/providers/docs/index.d.ts +54 -0
- package/dist/providers/docs/index.js +1237 -0
- package/dist/providers/docs/skill.generated.js +9 -0
- package/dist/providers/drive/index.d.ts +53 -0
- package/dist/providers/drive/index.js +1523 -0
- package/dist/providers/drive/skill.generated.js +9 -0
- package/dist/providers/forms/index.d.ts +54 -0
- package/dist/providers/forms/index.js +1217 -0
- package/dist/providers/forms/skill.generated.js +11 -0
- package/dist/providers/github/auth.d.ts +32 -0
- package/dist/providers/github/auth.js +361 -0
- package/dist/providers/github/hosted.js +218 -0
- package/dist/providers/github/index.d.ts +13 -0
- package/dist/providers/github/index.js +140 -0
- package/dist/providers/github/key.js +100 -0
- package/dist/providers/github/rest.js +321 -0
- package/dist/providers/github/scope.d.ts +29 -0
- package/dist/providers/github/scope.js +124 -0
- package/dist/providers/github/skill.generated.js +8 -0
- package/dist/providers/gmail/index.d.ts +51 -0
- package/dist/providers/gmail/index.js +1436 -0
- package/dist/providers/gmail/skill.generated.js +9 -0
- package/dist/providers/infisical/index.d.ts +7 -0
- package/dist/providers/infisical/index.js +713 -0
- package/dist/providers/infisical/skill.generated.js +8 -0
- package/dist/providers/{linear.d.ts → linear/index.d.ts} +11 -14
- package/dist/providers/linear/index.js +352 -0
- package/dist/providers/linear/skill.generated.js +8 -0
- package/dist/providers/{mixpanel.d.ts → mixpanel/index.d.ts} +5 -10
- package/dist/providers/mixpanel/index.js +416 -0
- package/dist/providers/mixpanel/skill.generated.js +9 -0
- package/dist/providers/{notion.d.ts → notion/index.d.ts} +8 -8
- package/dist/providers/{notion.js → notion/index.js} +226 -239
- package/dist/providers/notion/skill.generated.js +10 -0
- package/dist/providers/{overflow.d.ts → overflow/index.d.ts} +2 -2
- package/dist/providers/{overflow.js → overflow/index.js} +74 -111
- package/dist/providers/overflow/skill.generated.js +8 -0
- package/dist/providers/{planning-center.d.ts → planning-center/index.d.ts} +2 -2
- package/dist/providers/{planning-center.js → planning-center/index.js} +264 -104
- package/dist/providers/planning-center/skill.generated.js +10 -0
- package/dist/providers/{revenuecat.d.ts → revenuecat/index.d.ts} +5 -10
- package/dist/providers/revenuecat/index.js +557 -0
- package/dist/providers/revenuecat/skill.generated.js +11 -0
- package/dist/providers/sheets/index.d.ts +54 -0
- package/dist/providers/sheets/index.js +1237 -0
- package/dist/providers/sheets/skill.generated.js +10 -0
- package/dist/providers/slides/index.d.ts +53 -0
- package/dist/providers/slides/index.js +2645 -0
- package/dist/providers/slides/skill.generated.js +9 -0
- package/dist/providers/{stripe.d.ts → stripe/index.d.ts} +5 -12
- package/dist/providers/stripe/index.js +266 -0
- package/dist/providers/stripe/skill.generated.js +11 -0
- package/dist/providers/{tithely.d.ts → tithely/index.d.ts} +2 -2
- package/dist/providers/{tithely.js → tithely/index.js} +60 -91
- package/dist/providers/tithely/skill.generated.js +8 -0
- package/dist/providers/{vercel.d.ts → vercel/index.d.ts} +8 -8
- package/dist/providers/vercel/index.js +1038 -0
- package/dist/providers/vercel/mcp-ownership.js +212 -0
- package/dist/providers/vercel/skill.generated.js +11 -0
- package/dist/registry.d.ts +110 -171
- package/dist/registry.js +588 -927
- package/dist/request-state.js +21 -0
- package/dist/resource-read.js +103 -0
- package/dist/result-shapes.js +17 -49
- package/dist/retired-toolkits.js +1 -1
- package/dist/routes/access-tokens.js +3 -6
- package/dist/routes/activity-context.js +21 -0
- package/dist/routes/activity-disclosure.js +40 -0
- package/dist/routes/activity.js +59 -21
- package/dist/routes/actor-labels.js +3 -50
- package/dist/routes/connect.js +221 -0
- package/dist/routes/credentials.js +15 -27
- package/dist/routes/mcp.js +365 -130
- package/dist/routes/oauth-client-metadata.js +15 -0
- package/dist/routes/oauth-management.js +45 -107
- package/dist/routes/oauth.js +110 -57
- package/dist/routes/operator.js +3 -3
- package/dist/routes/shared.d.ts +25 -64
- package/dist/routes/shared.js +160 -80
- package/dist/routes/skills.js +30 -0
- package/dist/routes/ui-config.js +225 -0
- package/dist/routes/ui-data.js +40 -35
- package/dist/routes/ui.js +66 -56
- package/dist/runtime/admission.js +4 -2
- package/dist/runtime/call-admission.js +3 -1
- package/dist/runtime/connector-scope.js +1 -4
- package/dist/runtime/run.js +10 -39
- package/dist/runtime/services.js +12 -117
- package/dist/runtime/shared-read.js +1 -3
- package/dist/runtime/storage.js +8 -1
- package/dist/sent-secrets.d.ts +93 -0
- package/dist/sent-secrets.js +1013 -0
- package/dist/server.js +28 -71
- package/dist/skills.js +416 -174
- package/dist/sqlite.d.ts +48 -0
- package/dist/sqlite.js +181 -0
- package/dist/storage/keys.js +443 -0
- package/dist/storage/memory.js +16 -4
- package/dist/storage/sql.d.ts +66 -0
- package/dist/storage/sql.js +543 -0
- package/dist/timeout.js +4 -2
- package/dist/tool-name.js +17 -0
- package/dist/tool-safety.d.ts +9 -35
- package/dist/tool-safety.js +20 -40
- package/dist/types.d.ts +336 -56
- package/dist/types.js +0 -1
- package/dist/ui.d.ts +7 -19
- package/dist/ui.js +76 -90
- package/dist/url-safety.js +3 -6
- package/dist/usage-guide.js +146 -0
- package/dist/validate.d.ts +7 -0
- package/dist/validate.js +309 -47
- package/dist/version.d.ts +1 -7
- package/dist/version.js +3 -7
- package/dist/worker.d.ts +11 -0
- package/dist/worker.js +435 -0
- package/documentation/README.md +63 -0
- package/documentation/architecture.md +696 -231
- package/documentation/auth.md +1069 -546
- package/documentation/code-mode.md +662 -356
- package/documentation/deploying.md +146 -0
- package/documentation/integrating.md +159 -0
- package/documentation/meta-tools.md +570 -216
- package/documentation/operating.md +135 -0
- package/documentation/operator-tests.md +97 -0
- package/documentation/operator-ui.md +132 -0
- package/documentation/provider-migration-0.29.md +65 -0
- package/examples/worker/AGENTS.md +34 -12
- package/examples/worker/README.md +293 -255
- package/examples/worker/kv-to-d1.wrangler.jsonc +26 -0
- package/examples/worker/scripts/copy-kv-to-d1.mjs +162 -0
- package/examples/worker/src/connecta.config.ts +151 -0
- package/examples/worker/src/index.ts +14 -197
- package/examples/worker/wrangler.jsonc +15 -35
- package/package.json +126 -54
- package/templates/node/.dockerignore +1 -2
- package/templates/node/.env.example +20 -21
- package/templates/node/AGENTS.md +21 -17
- package/templates/node/Dockerfile +3 -5
- package/templates/node/README.md +140 -58
- package/templates/node/docker-compose.yml +11 -12
- package/templates/node/package.json +4 -2
- package/templates/node/src/connecta.config.ts +119 -0
- package/templates/node/src/index.ts +9 -154
- package/templates/node/src/provision-token.ts +17 -0
- package/AGENTS.md +0 -170
- package/dist/artifacts/connector.d.ts +0 -58
- package/dist/artifacts/connector.js +0 -730
- package/dist/artifacts/document.js +0 -86
- package/dist/artifacts/guide.js +0 -140
- package/dist/artifacts/html-scan.js +0 -329
- package/dist/artifacts/json.js +0 -78
- package/dist/artifacts/kv-store.d.ts +0 -20
- package/dist/artifacts/kv-store.js +0 -140
- package/dist/artifacts/markdown.js +0 -478
- package/dist/artifacts/module.d.ts +0 -37
- package/dist/artifacts/module.js +0 -66
- package/dist/artifacts/operations.d.ts +0 -197
- package/dist/artifacts/operations.js +0 -1002
- package/dist/artifacts/refresh.d.ts +0 -55
- package/dist/artifacts/refresh.js +0 -236
- package/dist/artifacts/routes.js +0 -206
- package/dist/artifacts/types.d.ts +0 -214
- package/dist/artifacts/types.js +0 -22
- package/dist/artifacts/validate.d.ts +0 -62
- package/dist/artifacts/validate.js +0 -651
- package/dist/artifacts.d.ts +0 -6
- package/dist/artifacts.js +0 -9
- package/dist/auth/bearer.d.ts +0 -11
- package/dist/auth/bearer.js +0 -50
- package/dist/providers/basecamp.js +0 -445
- package/dist/providers/linear.js +0 -217
- package/dist/providers/mixpanel.js +0 -247
- package/dist/providers/revenuecat.js +0 -317
- package/dist/providers/stripe.js +0 -253
- package/dist/providers/vercel.js +0 -1253
- package/dist/storage/file.d.ts +0 -15
- package/dist/storage/file.js +0 -455
- package/ethos.md +0 -93
- package/examples/worker/src/cloudflare-kv.ts +0 -43
- package/examples/worker/src/d1-activity-row.ts +0 -155
- package/examples/worker/src/d1-activity.ts +0 -147
- package/examples/worker/src/d1-storage.ts +0 -138
- package/examples/worker/src/r2-artifact-blobs.ts +0 -29
- package/templates/node/src/file-activity.ts +0 -182
|
@@ -1,23 +1,41 @@
|
|
|
1
1
|
# Code mode — the guest API contract
|
|
2
2
|
|
|
3
|
-
The
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
names the reason; a third executor is implementable from this document alone.
|
|
12
|
-
[`ethos.md`](../ethos.md) carries the verdicts behind the shape,
|
|
3
|
+
The `execute_code` contract: capabilities, results, failures, retries, limits,
|
|
4
|
+
and activity. Specified in prose first, implemented second.
|
|
5
|
+
|
|
6
|
+
Two executors implement it: QuickJS in a Node child process and `workerExecutor()`
|
|
7
|
+
from `@zackbart/connecta/worker` around upstream `DynamicWorkerExecutor` on Workers.
|
|
8
|
+
Divergence is a bug unless explained in [Executor exceptions](#executor-exceptions);
|
|
9
|
+
a third executor is implementable from this document alone.
|
|
10
|
+
[`PRINCIPLES.md`](https://github.com/zackbart/connecta/blob/main/PRINCIPLES.md) states the invariants,
|
|
13
11
|
[`meta-tools.md`](./meta-tools.md) owns the top-level tool contract, and clause
|
|
14
12
|
identifiers (`A1`, `E3`, …) are stable and cited by [Verification](#verification).
|
|
15
13
|
|
|
14
|
+
## Task routes
|
|
15
|
+
|
|
16
|
+
For normal endpoint work, start with [Operating an endpoint](./operating.md).
|
|
17
|
+
Use this reference for exact guest behavior or executor implementation.
|
|
18
|
+
[Agent index](./README.md) routes other work.
|
|
19
|
+
|
|
20
|
+
| Task | Sections |
|
|
21
|
+
| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
22
|
+
| Wire a shipped or custom executor | [Deploy-time capability](#deploy-time-capability), [executor requirements](#what-an-executor-must-implement), [exceptions](#executor-exceptions) |
|
|
23
|
+
| Write a portable program | [Program form](#the-program), [addresses](#addressing), [guest functions](#the-surface) |
|
|
24
|
+
| Discover and call tools | [Search](#connectasearch), [describe](#connectadescribe), [call](#connectacall), [parallel calls](#parallel-calls) |
|
|
25
|
+
| Page results, load skills or read resources | [Result and skill](#connectaresult-and-connectaskill), [read](#connectaread), [projection](#results-and-projection) |
|
|
26
|
+
| Emit incremental output | [emit](#connectaemit), [emitted output](#emitted-output) |
|
|
27
|
+
| Handle errors, writes, or cancellation | [Errors](#errors), [retries](#retry-semantics), [limits](#cancellation-and-limits), [writes](#writes), [activity](#activity) |
|
|
28
|
+
| Change the contract or check executor parity | [Verification](#verification), then the tests indexed by clause |
|
|
29
|
+
|
|
30
|
+
Clause IDs remain stable, including retired IDs. Check current behavior against
|
|
31
|
+
source and the verification table; do not reuse a retired clause to introduce
|
|
32
|
+
new behavior.
|
|
33
|
+
|
|
16
34
|
## Deploy-time capability
|
|
17
35
|
|
|
18
36
|
The `executor` passed to `createConnecta()` is required. `tools/list` is exactly
|
|
19
|
-
|
|
20
|
-
`authorize_connector
|
|
37
|
+
six — `execute_code`, `search_tools`, `call_tool`, `call_destructive_tool`,
|
|
38
|
+
`authorize_connector` and `skills`. Construction fails when the
|
|
21
39
|
executor is missing, and the removed `surface` option is rejected rather than
|
|
22
40
|
ignored ([#273](https://github.com/zackbart/connecta/issues/273)), as are the
|
|
23
41
|
pause-only `execute.resumableWrites` and `execute.pausedRunTtlSeconds`
|
|
@@ -33,26 +51,37 @@ import { quickJsExecutor } from "@zackbart/connecta/quickjs";
|
|
|
33
51
|
createConnecta({ executor: quickJsExecutor() /* connectors, auth, storage… */ });
|
|
34
52
|
```
|
|
35
53
|
|
|
36
|
-
`quickJsExecutor()` runs each program in a disposable child
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
[Node template](../templates/node/README.md) carries the complete setup.
|
|
54
|
+
`quickJsExecutor()` runs each program in a disposable child process, with CPU,
|
|
55
|
+
wall-time, memory, stack, queue, result, log, and IPC bounds on the executor.
|
|
56
|
+
Keep `@zackbart/connecta/quickjs` external in server bundles so the child entry
|
|
57
|
+
stays on disk. The [Node template](../templates/node/README.md) has the full setup.
|
|
41
58
|
|
|
42
|
-
On
|
|
43
|
-
Workers require the Workers Paid plan:
|
|
59
|
+
On Workers the Worker Loader is the sandbox; Dynamic Workers require the Paid plan:
|
|
44
60
|
|
|
45
61
|
```ts
|
|
46
|
-
|
|
62
|
+
import { workerExecutor } from "@zackbart/connecta/worker";
|
|
63
|
+
|
|
64
|
+
createConnecta({ executor: workerExecutor({ loader: env.LOADER }) });
|
|
47
65
|
```
|
|
48
66
|
|
|
49
|
-
The
|
|
50
|
-
|
|
51
|
-
|
|
67
|
+
The adapter uses only `loader` and an optional `timeout`. Its admission defaults
|
|
68
|
+
are two active runs, eight queued runs, and a five-second queue deadline, settable
|
|
69
|
+
through `admission`. Lease release disposes RPC and loader handles independently
|
|
70
|
+
of guest settlement. `bindings`, `modules`, or `globalOutbound` violate `P2`.
|
|
71
|
+
The [Worker example](../examples/worker/README.md#code-mode) has the full setup.
|
|
72
|
+
|
|
73
|
+
Replace `import { DynamicWorkerExecutor } from "@cloudflare/codemode";` with
|
|
74
|
+
`import { workerExecutor } from "@zackbart/connecta/worker";` and use the wiring above.
|
|
75
|
+
Keep the peer. Unbranded executors throw, including bundled upstream copies.
|
|
76
|
+
Shipped executors carry a non-enumerable `Symbol.for("connecta.executor")` version/lifecycle brand.
|
|
77
|
+
Custom sandboxes import `customExecutor` from `@zackbart/connecta`, then configure
|
|
78
|
+
`executor: customExecutor(myExecutor, { lifecycle: "self-managed" })`. They own guest termination
|
|
79
|
+
and cleanup at budget exhaustion, cancellation, and deadlines; the wrapper only delegates methods.
|
|
52
80
|
|
|
53
81
|
## What an executor must implement
|
|
54
82
|
|
|
55
|
-
The
|
|
83
|
+
The Promise provider/result seam lives in `src/types.ts`. Custom implementations
|
|
84
|
+
also need the lifecycle wrapper above; structural compatibility alone is insufficient.
|
|
56
85
|
|
|
57
86
|
```ts
|
|
58
87
|
interface Executor {
|
|
@@ -70,6 +99,8 @@ interface ExecutorProvider {
|
|
|
70
99
|
interface ExecuteResult {
|
|
71
100
|
result: unknown; // the program's resolved value
|
|
72
101
|
error?: string; // set instead of result when the run failed
|
|
102
|
+
failure?: { name: string; line?: number; call?: CallErrorDetails;
|
|
103
|
+
timeout?: { elapsedMs: number; deadlineMs: number } };
|
|
73
104
|
logs?: string[]; // captured console output, in call order
|
|
74
105
|
}
|
|
75
106
|
```
|
|
@@ -78,34 +109,38 @@ Connecta passes exactly one provider, named `connecta`. An executor must:
|
|
|
78
109
|
|
|
79
110
|
1. **Expose each provider as a guest global** whose properties are its `fns`,
|
|
80
111
|
called with the program's arguments and awaited. Connecta supplies `search`,
|
|
81
|
-
`describe`, `call`, and `emit`.
|
|
112
|
+
`describe`, `call`, `read`, `result`, `skill`, and `emit`.
|
|
82
113
|
2. **Evaluate `prelude` after the provider globals exist and before the
|
|
83
|
-
program.** It is trusted host code
|
|
84
|
-
|
|
114
|
+
program.** It is trusted host code that installs the immutable namespace
|
|
115
|
+
and waits for emission acknowledgements. Capture runner intrinsics first;
|
|
116
|
+
privileged initialization must be single-use.
|
|
85
117
|
3. **Marshal values as JSON** both directions (`P3`), and reject a host call
|
|
86
118
|
whose function is not an own property of `fns` — the guest can ask for
|
|
87
119
|
inherited members too.
|
|
88
|
-
4. **Return, never throw, for a failed program
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
120
|
+
4. **Return, never throw, for a failed program.** Set `error` and leave
|
|
121
|
+
`result` undefined. Rebuild a rejected host `InvocationFailure` as a guest
|
|
122
|
+
Error with `code`, `retryable`, and `details`, and retain its identity in
|
|
123
|
+
executor-owned state. If that same Error escapes the program, return its
|
|
124
|
+
typed details in `failure.call`. A wrapped or copied Error is `program_error`.
|
|
125
|
+
Construct outcomes through the host-owned RPC return or QuickJS host bridge,
|
|
126
|
+
never by parsing guest stdout, prints, returned values, or thrown look-alikes.
|
|
127
|
+
No secret held in the guest realm authenticates anything. Guest module
|
|
128
|
+
specifiers must not resolve runner internals, including dynamic imports.
|
|
129
|
+
For compilation failures, return `failure: { name, line? }`. For a sandbox
|
|
130
|
+
timeout, add `failure.timeout: { elapsedMs, deadlineMs }`.
|
|
92
131
|
5. **Capture `console.log`, `console.warn`, and `console.error`** into `logs` in
|
|
93
132
|
call order (`R5`), bounding what it retains.
|
|
94
|
-
6. **Bound the guest**: wall clock, memory, stack, and CPU (`L3`, `L5`),
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
optional `name` — else a class's constructor name, which a minifier may rewrite
|
|
106
|
-
— is the executor name `/health` and `connecta doctor` report.
|
|
107
|
-
[Emitted output](#emitted-output) asks nothing of an executor: `connecta.emit`
|
|
108
|
-
is just another provider function (`M8`).
|
|
133
|
+
6. **Bound the guest**: wall clock, memory, stack, and CPU (`L3`, `L5`), within
|
|
134
|
+
`P2`/`X5`. Settle `execute()` on your own deadline; connecta stops waiting
|
|
135
|
+
at `execute.watchdogMs` and reports the sandbox unresponsive (`L3`).
|
|
136
|
+
7. **Grant no ambient authority.** Never use `eval` or `node:vm`: sandboxing
|
|
137
|
+
supplements connecta's boundary; every capability arrives through `fns`.
|
|
138
|
+
|
|
139
|
+
Optional `AdmittingExecutor.acquire()` returns a once-executed lease for bounded
|
|
140
|
+
admission (`L7`); otherwise connecta uses `withExecutorAdmission`. `close()` handles
|
|
141
|
+
shutdown. `/health` and `connecta doctor` report `name`, falling back to the
|
|
142
|
+
constructor name, which minifiers may rewrite. [Emission](#emitted-output) is
|
|
143
|
+
another provider function (`M8`).
|
|
109
144
|
|
|
110
145
|
## The program
|
|
111
146
|
|
|
@@ -120,7 +155,7 @@ statements, and bare statement bodies are outside host recovery. QuickJS may
|
|
|
120
155
|
wrap a bare body when driven directly; that is outside the portable contract.
|
|
121
156
|
|
|
122
157
|
**P2.** The only capabilities in the contract are `connecta.search`,
|
|
123
|
-
`connecta.describe`, `connecta.call`, `connecta.emit`, and `console.log` /
|
|
158
|
+
`connecta.describe`, `connecta.call`, `connecta.read`, `connecta.result`, `connecta.skill`, `connecta.emit`, and `console.log` /
|
|
124
159
|
`console.warn` / `console.error`, captured and returned. Anything else a runtime
|
|
125
160
|
exposes is outside the portable contract and must not be used. QuickJS grants
|
|
126
161
|
none of it. A loader-only Dynamic Worker denies external egress and filesystem
|
|
@@ -163,10 +198,10 @@ belonged to shortcut dispatch and stay retired; nothing reuses those ids.
|
|
|
163
198
|
|
|
164
199
|
## The surface
|
|
165
200
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
fails
|
|
201
|
+
Seven functions: `search`, `describe`, `call`, `read`, `result`, `skill`, and `emit`.
|
|
202
|
+
All return awaitable values; emission also works without `await`. The namespace
|
|
203
|
+
has no inherited members. Unknown properties are undefined, and calling them
|
|
204
|
+
fails as a guest `TypeError`. The host also dispatches only own members of `fns`.
|
|
170
205
|
|
|
171
206
|
### connecta.search
|
|
172
207
|
|
|
@@ -178,15 +213,17 @@ const page = await connecta.search({
|
|
|
178
213
|
limit: 8, // 1–100, default 8
|
|
179
214
|
offset: 0,
|
|
180
215
|
fullDescriptions: false,
|
|
181
|
-
includeSchemas: "
|
|
216
|
+
includeSchemas: "json", // default; or "compact" / "typescript"
|
|
182
217
|
includeSchemaKeys: true, // default true in code mode
|
|
183
218
|
});
|
|
184
219
|
```
|
|
185
220
|
|
|
186
|
-
**S1.** Returns
|
|
187
|
-
`
|
|
188
|
-
|
|
189
|
-
`
|
|
221
|
+
**S1.** Returns the same flat page as top-level `search_tools`:
|
|
222
|
+
`{ catalogErrors, tools, total, offset, limit, hasMore }`, plus `nextOffset`
|
|
223
|
+
when more remains and `matchMode: "partial"` when no tool matched every term.
|
|
224
|
+
Read `catalogErrors` and any `absence` before selecting a tool. Catalog failures
|
|
225
|
+
carry recovery actions at the top of the page; an absent service returns no
|
|
226
|
+
lookalikes. Both paths use only the caller's endpoint/pool and grants. Ranking is
|
|
190
227
|
[lexical discovery](./meta-tools.md#lexical-discovery)'s, and rows expose
|
|
191
228
|
neither lexical scores nor per-result coverage. An empty or whitespace-only
|
|
192
229
|
query browses; non-empty input with no ASCII lexical terms returns no tools plus
|
|
@@ -201,16 +238,20 @@ bounded `guideSummary`, requested or not. An output shape learned under `S9`
|
|
|
201
238
|
also carries `outputSchemaSource: "observed"`; provider declarations carry no
|
|
202
239
|
source marker.
|
|
203
240
|
|
|
241
|
+
Programs default to `includeSchemas: "json"`: `inputSchema` and available
|
|
242
|
+
`outputSchema` are JSON Schema values, labeled `schemaFormat: "json"`.
|
|
243
|
+
Explicit `includeSchemas: "compact"` returns strings labeled
|
|
244
|
+
`schemaFormat: "text"`; TypeScript signatures carry the same text label.
|
|
204
245
|
Compact shapes omit property prose and put required fields first, under these
|
|
205
246
|
bounds:
|
|
206
247
|
|
|
207
|
-
| Bound
|
|
208
|
-
|
|
|
209
|
-
| `execute_code` source | ≤ 65,536 UTF-8 bytes, checked before executor admission; over-limit source returns `invalid_args`
|
|
210
|
-
| Rendered shape
|
|
211
|
-
| Work per shape
|
|
212
|
-
| Each enum node
|
|
213
|
-
| Resolved `$ref` text
|
|
248
|
+
| Bound | Value |
|
|
249
|
+
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
250
|
+
| `execute_code` source | ≤ 65,536 UTF-8 bytes, checked before executor admission; over-limit source returns `invalid_args` |
|
|
251
|
+
| Rendered shape | 1,024 UTF-8 bytes each |
|
|
252
|
+
| Work per shape | 2,000 visits across schema nodes, property and required names, literal values, any constraint-free retry, and its key-only fallback |
|
|
253
|
+
| Each enum node | 256 of those bytes |
|
|
254
|
+
| Resolved `$ref` text | reused within one walk |
|
|
214
255
|
|
|
215
256
|
About three near-cap enum nodes therefore coexist while the final quarter stays
|
|
216
257
|
for surrounding syntax, and above 1,024 bytes the global fallback applies.
|
|
@@ -229,7 +270,7 @@ use `format: "json"` or JSON search.
|
|
|
229
270
|
`includeSchemas: "typescript"` spends those same bounds on a different
|
|
230
271
|
rendering: one `signature` string in place of `inputSchema` and
|
|
231
272
|
`outputSchema`, reading `(args: { runId: number }) => Promise<Run>` for the
|
|
232
|
-
value `connecta.call` returns. It is documentation for the program's author —
|
|
273
|
+
`data` value `connecta.call` returns. It is documentation for the program's author —
|
|
233
274
|
the program itself is still JavaScript, and a type annotation copied into it
|
|
234
275
|
is a syntax error (`P5`). Truncation keeps compact's flags and
|
|
235
276
|
turns what compact would print as a name or raw JSON into a marked `unknown`;
|
|
@@ -239,14 +280,10 @@ its degradation rules are specified once, under
|
|
|
239
280
|
signature is byte-identical to the one `search_tools` returns.
|
|
240
281
|
|
|
241
282
|
**S1a.** `connector` loads only the named catalog; omit it only when the
|
|
242
|
-
integration is ambiguous
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
whose calls a program has refused (`E4`) unless config exempts them (`W12`),
|
|
247
|
-
which a row marks with `approval: "exempt"` without moving it out of that
|
|
248
|
-
class; omitted or `"all"` preserves the complete catalog. These filters grant
|
|
249
|
-
no authority and change no admission decision.
|
|
283
|
+
integration is ambiguous. `safety: "readOnly"` selects stored read verdicts;
|
|
284
|
+
`"approvalRequired"` selects stored write verdicts; omitted or `"all"` selects
|
|
285
|
+
both. Search and describe rows carry `classification`. These filters grant no
|
|
286
|
+
authority and change no pool trust or call admission decision.
|
|
250
287
|
|
|
251
288
|
**S2.** A requested object schema carries `inputKeys`, `requiredInputKeys`
|
|
252
289
|
(declared properties only), and `outputKeys`: the names the rendered schema
|
|
@@ -278,12 +315,14 @@ hint and the stable `code`, `retryable`, and `details` fields (`E1`).
|
|
|
278
315
|
const one = await connecta.describe({ address: "ci.get_run" });
|
|
279
316
|
const many = await connecta.describe({
|
|
280
317
|
addresses: ["ci.get_run", "ci.get_job_logs"], // ≤ 100
|
|
281
|
-
format: "
|
|
318
|
+
format: "json", // default; or "compact" / "typescript"
|
|
282
319
|
fullDescriptions: false,
|
|
283
320
|
});
|
|
284
321
|
```
|
|
285
322
|
|
|
286
|
-
**S4.**
|
|
323
|
+
**S4.** Defaults to JSON Schema values with `schemaFormat: "json"`.
|
|
324
|
+
Explicit compact schemas and TypeScript signatures have `schemaFormat: "text"`.
|
|
325
|
+
Returns `{ tools }` in order, one entry per address; one bad address
|
|
287
326
|
never fails the whole call. An unknown address or failed catalog returns `error`
|
|
288
327
|
plus typed `errorDetails` (`code`, `message`, `retryable`). Misses carry a
|
|
289
328
|
route-aware `nextAction`, a close miss may add three canonical `suggestions`,
|
|
@@ -302,15 +341,38 @@ says so inside its `Promise<…>`.
|
|
|
302
341
|
|
|
303
342
|
### connecta.call
|
|
304
343
|
|
|
344
|
+
The published `GuestApi` type describes the supplied global for editors.
|
|
345
|
+
The executable usage guide checks its API notation against those declarations;
|
|
346
|
+
programs still use plain JavaScript.
|
|
347
|
+
|
|
305
348
|
```js
|
|
306
|
-
const run = await connecta.call("ci.get_run", { runId: 42 });
|
|
349
|
+
const { data: run, format } = await connecta.call("ci.get_run", { runId: 42 });
|
|
350
|
+
// Equivalent: connecta.call({ address: "ci.get_run", args: { runId: 42 }, timeoutMs: 30_000 })
|
|
307
351
|
```
|
|
308
352
|
|
|
309
|
-
**S5.** Takes a canonical address
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
353
|
+
**S5.** Takes a canonical address, optional arguments, and optional
|
|
354
|
+
`{ timeoutMs }`; the object form is `{ address, args?, timeoutMs? }`. A malformed
|
|
355
|
+
signature fails with `invalid_args` and both exact signatures, before discovery.
|
|
356
|
+
Normally returns `{ data, format: "json" | "text" }`. Oversized values may return
|
|
357
|
+
a `format: "paged"` handle for `connecta.result`, as described in `L6` below.
|
|
358
|
+
MCP `toolResult` or
|
|
359
|
+
`structuredContent` is JSON; all-text content is JSON when it parses, otherwise
|
|
360
|
+
text. API string values are text, other API values are JSON. Check `format`
|
|
361
|
+
before treating `data` as an object. A downstream `isError` throws.
|
|
362
|
+
|
|
363
|
+
An inline MCP result containing image, audio, resource, or resource_link blocks
|
|
364
|
+
also exposes `content?: GuestNativeBlock[]`, even when `data` comes from
|
|
365
|
+
`structuredContent` or `toolResult`. `data` keeps its existing shape.
|
|
366
|
+
`connecta.emit(result)` forwards all native blocks; iterating `result.content`
|
|
367
|
+
and calling `connecta.emit(block)` forwards selected blocks. Both forward the
|
|
368
|
+
host-retained originals, so guest edits do not change native output. Results
|
|
369
|
+
over the 1 MiB inline cap return paging handles without native content; page
|
|
370
|
+
and reduce them as described in `L6`. If only the native presentation is too
|
|
371
|
+
large or its transfer fails, `data` stays intact and `contentResult` carries
|
|
372
|
+
its paging handle or an unavailable-paging notice for presentation that exceeds
|
|
373
|
+
bounded traversal limits or is cyclic. When a result ID exists,
|
|
374
|
+
`connecta.result(result.contentResult)` pages the original MCP envelope;
|
|
375
|
+
`emit(result)` refuses with `result_too_large`.
|
|
314
376
|
|
|
315
377
|
**S6.** Every call goes through the same catalog, fail-closed read-only
|
|
316
378
|
predicate, admission, credential containment, timeout classification, health
|
|
@@ -320,6 +382,32 @@ program does decides it. The sandbox is an additional containment layer, not a
|
|
|
320
382
|
second implementation of the boundary, and nothing a program does widens what
|
|
321
383
|
it can reach.
|
|
322
384
|
|
|
385
|
+
### connecta.result and connecta.skill
|
|
386
|
+
|
|
387
|
+
`await connecta.result(handleOrId, { page?, offset?, maxBytes? })` reads a stashed direct-call
|
|
388
|
+
or program-call result bound to the admitted subject, principal, endpoint/pool, request origin,
|
|
389
|
+
connector, and tool. It returns
|
|
390
|
+
`{ resultId, offset, bytes, totalBytes, hasMore, nextOffset?, format: "text", text }`.
|
|
391
|
+
Offsets and sizes are UTF-8 bytes. Pages obey the original call's inline cap
|
|
392
|
+
and a 32 KiB bridge ceiling. `page` is zero-based and mutually exclusive with
|
|
393
|
+
`offset`; keep `maxBytes` fixed while incrementing pages. Nominal page windows
|
|
394
|
+
are at least four bytes wide and align both edges to UTF-8 boundaries.
|
|
395
|
+
Follow `nextOffset`, reassemble inside the program, and return a reduced value.
|
|
396
|
+
Before returning a page, the host rechecks current authentication, connector/tool
|
|
397
|
+
grants, pool membership, and endpoint trust against both the original and current
|
|
398
|
+
tool classification. A read-only endpoint cannot page a write result, so a
|
|
399
|
+
direct write there returns an inline truncation notice without stashing the
|
|
400
|
+
result or advertising a paging action. Binding
|
|
401
|
+
mismatches, revoked access, and old entries without bindings are `not_found`, as
|
|
402
|
+
are unknown or expired ids; a storage failure is `unavailable`. IDs are random UUIDs.
|
|
403
|
+
The `get_result` meta-tool is removed.
|
|
404
|
+
|
|
405
|
+
`await connecta.skill(name)` resolves the same URI or compatibility name as
|
|
406
|
+
top-level `skills`, within the admitted connector view. It reads the registry
|
|
407
|
+
behind native `skills/get` and `resources/read`, including opted-in downstream
|
|
408
|
+
skills. It returns
|
|
409
|
+
`{ name, format: "text", text }`; an unknown name is `not_found`.
|
|
410
|
+
|
|
323
411
|
### Parallel calls
|
|
324
412
|
|
|
325
413
|
**S7.** Use `Promise.all` for independent calls when any failure should fail the
|
|
@@ -331,7 +419,7 @@ as sequential calls. There is no separate batch size or result contract.
|
|
|
331
419
|
`details`. Project those fields before returning — an `Error` object is not a
|
|
332
420
|
JSON result contract.
|
|
333
421
|
|
|
334
|
-
**S9.** A successful
|
|
422
|
+
**S9.** A successful call classified as a read whose provider declared no
|
|
335
423
|
`outputSchema` passively learns one from the unwrapped result. The observation
|
|
336
424
|
keeps field names and broad JSON types only — no arguments, scalar values, raw
|
|
337
425
|
results, code, credentials, or errors — and property names may be user-authored.
|
|
@@ -350,10 +438,75 @@ successful call. No discovery read, timer, refresh, background job, or storage
|
|
|
350
438
|
adapter executes or persists work for this cache: the result-sampling refusal in
|
|
351
439
|
[#282](https://github.com/zackbart/connecta/issues/282) stands.
|
|
352
440
|
|
|
441
|
+
### connecta.read
|
|
442
|
+
|
|
443
|
+
```js
|
|
444
|
+
const resource = await connecta.read(
|
|
445
|
+
"resource://docs/" + encodeURIComponent("docs://manual/start"),
|
|
446
|
+
);
|
|
447
|
+
return resource.contents.map(content => content.text);
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
**S10.** Reads a downstream resource through a configured connector that
|
|
451
|
+
implements `readResource`. The routing URI is exactly
|
|
452
|
+
`resource://<connectorId>/<encodeURIComponent(downstreamUri)>`, at most 8,192
|
|
453
|
+
UTF-8 bytes. The downstream URI must have a scheme and no control characters.
|
|
454
|
+
Encode it once, including any path, query and fragment. Bare URLs, malformed
|
|
455
|
+
encoding, routing userinfo, ports and extra routing query or fragment fields
|
|
456
|
+
fail with `invalid_args`. Remote MCP connectors first load the complete,
|
|
457
|
+
paginated resources and URI-template inventories through the same host-auth
|
|
458
|
+
partitioned catalog cache. The decoded URI must exactly match an advertised
|
|
459
|
+
resource or match an advertised URI template. An unmatched URI fails with a
|
|
460
|
+
fixed `not_found` message before any downstream read. Template matching keeps
|
|
461
|
+
the scheme and authority fixed and supports bounded RFC 6570 scalar and list
|
|
462
|
+
expansions, including prefix modifiers and safe multi-segment `{+path}` and
|
|
463
|
+
`{/p*}` paths. Variables cannot supply authority, backslashes, dot segments,
|
|
464
|
+
a scheme change, query delimiters, controls or Unicode format characters,
|
|
465
|
+
including through repeated percent encoding. Initial percent encoding and
|
|
466
|
+
UTF-8 decoding stay strict. Later decoding layers preserve literal percent
|
|
467
|
+
signs produced by `%25` while checking every remaining `%HH` escape. The
|
|
468
|
+
matcher scans forward to the
|
|
469
|
+
leftmost following literal without backtracking. Adjacent expressions and
|
|
470
|
+
literals that the preceding expression can contain are refused with
|
|
471
|
+
`resource_template_ambiguous`. Matching all templates is capped at 262144
|
|
472
|
+
combined template and URI characters per read, with
|
|
473
|
+
`resource_match_budget_exceeded` beyond that bound. Operator status retains
|
|
474
|
+
each typed refusal once, without URI or template text. Mixed exploded
|
|
475
|
+
composites remain unsupported.
|
|
476
|
+
Connecta passes an admitted decoded URI as an opaque MCP `resources/read`
|
|
477
|
+
argument to the configured endpoint. It never fetches that
|
|
478
|
+
URI or creates a connector from it.
|
|
479
|
+
|
|
480
|
+
Resources are protocol reads in both `read-only` and `trusted` pools. A read
|
|
481
|
+
requires a grant to the whole connector through the endpoint/pool and identity
|
|
482
|
+
intersection. Exact-tool grants, including guarded grants, authorize no
|
|
483
|
+
resources. An absent, hidden, tool-restricted or resource-incapable connector
|
|
484
|
+
fails with `unknown_address`. The URI and extra arguments cannot select a
|
|
485
|
+
different credential owner or downstream subject. Personal credentials come
|
|
486
|
+
from the admitted principal, just as they do for tool calls.
|
|
487
|
+
|
|
488
|
+
The return is the downstream JSON `{ contents }` result, with text or base64
|
|
489
|
+
blob entries and available metadata. It is not unwrapped or JSON-parsed.
|
|
490
|
+
Every read spends one shared host call and uses the connector's call admission
|
|
491
|
+
with `toolName: "resources/read"` and `args: { uri: downstreamUri }`. One deadline
|
|
492
|
+
covers admission and dispatch; cancellation ends the wait and releases its
|
|
493
|
+
permit. Reads share the execution's downstream request scope. They make one
|
|
494
|
+
attempt, bypass response caching, and never start authorization. A downstream
|
|
495
|
+
resource miss is `not_found`; a mid-call input request is
|
|
496
|
+
`input_required_unsupported`. Other failures use the existing typed error
|
|
497
|
+
contract, including credential recovery. Values and failures cross the same
|
|
498
|
+
credential redaction boundary as `call`. Diagnostics use the fixed operation
|
|
499
|
+
name `read`; resource URIs and bodies enter no activity or diagnostic record.
|
|
500
|
+
This function exposes no resource listing, template discovery, subscriptions
|
|
501
|
+
or upward proxy to programs. Native upward skill resources are separate
|
|
502
|
+
[Phase 3](https://github.com/zackbart/connecta/issues/707) work.
|
|
503
|
+
|
|
353
504
|
### connecta.emit
|
|
354
505
|
|
|
355
506
|
```js
|
|
356
|
-
await connecta.
|
|
507
|
+
const badge = await connecta.call("assets.get_badge_image", {});
|
|
508
|
+
connecta.emit(badge);
|
|
509
|
+
// Or: for (const block of badge.content ?? []) connecta.emit(block);
|
|
357
510
|
```
|
|
358
511
|
|
|
359
512
|
The rich-output channel, delivered after the JSON envelope on success. Its
|
|
@@ -362,53 +515,65 @@ clauses are [Emitted output](#emitted-output) (`M1`–`M10`).
|
|
|
362
515
|
## Errors
|
|
363
516
|
|
|
364
517
|
**E1.** There are three error channels. Connecta failures are typed whether
|
|
365
|
-
caught or uncaught.
|
|
518
|
+
caught or uncaught. Host-call budget exhaustion ends the host run and blocks host
|
|
519
|
+
access (`L4`); Workers guest computation may continue briefly until teardown (`X3`).
|
|
366
520
|
|
|
367
|
-
| Channel
|
|
368
|
-
|
|
|
369
|
-
| A caught Connecta host failure
|
|
370
|
-
| An uncaught **tool or discovery** failure, as the model sees it | `{ error: { code, message, retryable, … } }` with `isError`
|
|
371
|
-
| Program or execution failure (`E5`, `E6`, a bridge bound in `L6`)
|
|
521
|
+
| Channel | Shape | Typed? |
|
|
522
|
+
| ------------------------------------------------------------------------- | ------------------------------------------------------------------ | ------ |
|
|
523
|
+
| A caught Connecta host failure | `Error` with `message`, `code`, `retryable`, `data`, and `details` | yes |
|
|
524
|
+
| An uncaught **tool, resource or discovery** failure, as the model sees it | `{ error: { code, message, retryable, … } }` with `isError` | yes |
|
|
525
|
+
| Program or execution failure (`E5`, `E6`, a bridge bound in `L6`) | `{ error: { code, message, retryable, details? } }` | yes |
|
|
372
526
|
|
|
373
|
-
Both executor bridges
|
|
374
|
-
|
|
375
|
-
authenticated frame (`X11`). `message` stays human text, capped at 2,000
|
|
527
|
+
Both executor bridges rebuild typed host rejections as guest Errors and retain
|
|
528
|
+
their identity in executor-owned state (`X11`). `message` stays human text, capped at 2,000
|
|
376
529
|
JSON-serialized characters including quotes and an `…` marker when clipped.
|
|
377
|
-
`code` and `retryable` are the stable branch fields; `details`
|
|
378
|
-
classification
|
|
530
|
+
`code` and `retryable` are the stable branch fields; `data` and `details` carry the same host
|
|
531
|
+
classification, which fits 3,700 serialized characters. Optional recovery metadata
|
|
379
532
|
that would exceed that bound is omitted whole, preserving `code`, `message`,
|
|
380
533
|
`retryable`, and `retryAfterMs`, because a clipped recovery address or argument
|
|
381
|
-
describes a different call. This covers `call`, `search`, `describe`, `emit`, and
|
|
382
|
-
|
|
534
|
+
describes a different call. This covers `call`, `read`, `search`, `describe`, `result`, `skill`, `emit`, and
|
|
535
|
+
write and emitted-output budgets. Program-authored errors use `program_error`; code must never
|
|
383
536
|
parse error prose. An `unavailable` classification may add `details.host`, an
|
|
384
537
|
HTTP(S) origin of at most 253 UTF-8 bytes, and `details.code`, a validated
|
|
385
538
|
network errno, undici transport code, or `timeout` of at most 32 bytes; neither
|
|
386
539
|
enters activity.
|
|
387
540
|
|
|
541
|
+
On hosts without URL elicitation, `connecta.call` auth failures carry `recovery`,
|
|
542
|
+
`nextAction`, and the handoff in `error.data`, also exposed as `error.details`.
|
|
543
|
+
An OAuth handoff includes `authorizationUrl` and `instructions`; operator
|
|
544
|
+
credential recovery includes `operatorUrl`, declared credential fields, and
|
|
545
|
+
instructions. `connecta.search` catalog errors and `connecta.describe`
|
|
546
|
+
`errorDetails` carry the same fields. When an auth error includes a handoff, give
|
|
547
|
+
it to the user or operator. One program run reuses one handoff per connector,
|
|
548
|
+
including concurrent call and catalog errors. Errors never request a forced
|
|
549
|
+
restart. Use `authorize_connector` for an explicit connection or a fresh link.
|
|
550
|
+
URL-elicitation hosts retain their existing flow.
|
|
551
|
+
|
|
388
552
|
**E2.** The taxonomy: `retryable` is what connecta reports, `Y3` what a program
|
|
389
553
|
may do. A provider maps each downstream failure to the code that tells the
|
|
390
554
|
caller what to do next, and never invents a cause it was not told.
|
|
391
555
|
|
|
392
|
-
| Code
|
|
393
|
-
|
|
|
394
|
-
| `unknown_address`
|
|
395
|
-
| `unknown_tool`
|
|
396
|
-
| `destructive_tool_requires_approval` |
|
|
397
|
-
| `auth_required`
|
|
398
|
-
| `invalid_args`
|
|
399
|
-
| `not_found`
|
|
400
|
-
| `conflict`
|
|
401
|
-
| `input_required_unsupported`
|
|
402
|
-
| `rate_limited`
|
|
403
|
-
| `unavailable`
|
|
404
|
-
| `timeout`
|
|
405
|
-
| `
|
|
406
|
-
| `
|
|
407
|
-
| `
|
|
408
|
-
| `
|
|
409
|
-
| `
|
|
410
|
-
| `
|
|
411
|
-
| `
|
|
556
|
+
| Code | Raised when | `retryable` |
|
|
557
|
+
| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
|
|
558
|
+
| `unknown_address` | no visible connector owns the tool address or grants the resource reader | false |
|
|
559
|
+
| `unknown_tool` | the connector has no such tool | false |
|
|
560
|
+
| `destructive_tool_requires_approval` | a program in a read-only pool attempted a write (`E4`) | false |
|
|
561
|
+
| `auth_required` | the credential is missing, expired, or rejected | false |
|
|
562
|
+
| `invalid_args` | arguments or discovery bounds were rejected | false |
|
|
563
|
+
| `not_found` | the downstream answered and the resource is not there — the one code that says skip this id rather than stop, raised only where the provider tells absence from a permission gap | false |
|
|
564
|
+
| `conflict` | the write named a base version someone else already moved past; nothing changed. `details.current` says where things stand (at most 20 whole-number entries) — re-read, reapply, retry with that base | false |
|
|
565
|
+
| `input_required_unsupported` | a downstream asked for input; use `nextAction` for the equivalent direct call | false |
|
|
566
|
+
| `rate_limited` | the downstream reported a rate limit | true |
|
|
567
|
+
| `unavailable` | the downstream is down or unreachable; optional sanitized `details.host` and `details.code` describe the transport failure without paths, queries, credentials, or provider prose | true |
|
|
568
|
+
| `timeout` | a call or sandbox deadline expired; details name operation, stage, elapsedMs, and deadlineMs | per operation |
|
|
569
|
+
| `program_error` | guest JavaScript failed; `details.name`, `line`, and a fixed repair hint describe it | false |
|
|
570
|
+
| `cancelled` | the run ended while this call was in flight (`E5`) | false |
|
|
571
|
+
| `connector_call_failed` | anything else the connector threw | per message |
|
|
572
|
+
| `catalog_lookup_failed` | the connector's catalog could not be loaded | per cause |
|
|
573
|
+
| `result_processing_failed` | the result could not be prepared | per message |
|
|
574
|
+
| `result_too_large` | a discovery response exceeded its byte bound | false |
|
|
575
|
+
| `budget_exceeded` | the run exhausted a host-call, write, or emitted-output budget | false |
|
|
576
|
+
| `write_outcome_unknown` | a trusted-pool write was sent and no answer came back; it is never sent again (`W9`) | false |
|
|
412
577
|
|
|
413
578
|
**E3.** `auth_required` carries the same recovery envelope as `call_tool`:
|
|
414
579
|
`connector`, `operation`, `recovery` (`oauth`, `operator_config`, or
|
|
@@ -416,17 +581,18 @@ caller what to do next, and never invents a cause it was not told.
|
|
|
416
581
|
sentence. A program cannot recover credentials — only an operator can — so stop
|
|
417
582
|
and let the failure reach the model.
|
|
418
583
|
|
|
419
|
-
**E4.**
|
|
420
|
-
program unless
|
|
584
|
+
**E4.** A tool classified as a write never runs in a
|
|
585
|
+
program unless the pool is trusted (`W12`). It is refused with
|
|
421
586
|
`destructive_tool_requires_approval` before validation and before anything is
|
|
422
587
|
sent, `nextAction` carrying its canonical address to `call_destructive_tool`
|
|
423
|
-
|
|
424
|
-
|
|
588
|
+
and a schema-filtered snapshot within the 512-byte echo budget. `argsRedacted`
|
|
589
|
+
marks partial or withheld arguments; use the original arguments if this flag is
|
|
590
|
+
set or `args` is absent. Snapshots are never clipped. The host's prompt on that
|
|
425
591
|
call is the approval, and the only one: generated code can neither mint the
|
|
426
592
|
capability nor approve its own write, and the model's short `reason` grants no
|
|
427
593
|
authority and never goes downstream.
|
|
428
594
|
|
|
429
|
-
**E5.** Failures of the
|
|
595
|
+
**E5.** Failures of the _execution_, not of a call, never appear inside the
|
|
430
596
|
guest: admission rejection (`executor_overloaded`, retryable, with
|
|
431
597
|
`retryAfterMs`), cancellation (`executor_cancelled`), shutdown
|
|
432
598
|
(`executor_closed`), deadline expiry, an executor that never settles (`L3`),
|
|
@@ -436,19 +602,33 @@ is cancelled fails with `cancelled`, catchable on the way out but never worth
|
|
|
436
602
|
acting on (`Y3`). When shutdown tears down a program that had already started,
|
|
437
603
|
accepted blocks are reported as discarded under `M4`; a failure before execution
|
|
438
604
|
started carries no discard fields. A returned `error` field is a failure even
|
|
439
|
-
when empty
|
|
440
|
-
`Error: Execution failed without an error message.`
|
|
441
|
-
|
|
442
|
-
**E6.**
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
605
|
+
when empty. An empty string reports `program_error` with
|
|
606
|
+
`Program Error: Execution failed without an error message.`
|
|
607
|
+
|
|
608
|
+
**E6.** A guest `TypeError`, `ReferenceError`, syntax error, invented API, or
|
|
609
|
+
program-authored throw is `program_error`. `details.name` is a bounded engine
|
|
610
|
+
error name; `details.line` is the source line when the runtime supplies one,
|
|
611
|
+
otherwise null. Fixed hints repair imports/require/filesystem access, shadowed
|
|
612
|
+
`connecta`, and invented globals such as `callTool` and `mixpanel`.
|
|
613
|
+
|
|
614
|
+
An unchanged uncaught host error retains its classification through Error
|
|
615
|
+
identity. A new error containing its message is a new program error. Copied
|
|
616
|
+
public `code`/`details`, printed text, and returned outcome-shaped objects carry
|
|
617
|
+
no authority. Host-call counts stay in host state. The guest JSON codec, Object
|
|
618
|
+
prototype, and Promise prototype are immutable. Promise race and species are
|
|
619
|
+
protected too. Host completion uses captured intrinsics so guest edits cannot
|
|
620
|
+
change bridge decoding or async return adoption. Worker guest modules contain
|
|
621
|
+
only the user callback and an import helper limited to runtime builtins.
|
|
622
|
+
Relative and other guest module imports cannot reach runner code. Trusted
|
|
623
|
+
wrappers and preludes remain outside the guest's lexical scope, and privileged
|
|
624
|
+
initialization is single-use. A separate private runner module captures and
|
|
625
|
+
freezes its references before the guest module evaluates, including the guest
|
|
626
|
+
namespace initializer. The entrypoint imports that runner before its guest
|
|
627
|
+
dependency. Before loading, the adapter parses the assembled guest export and
|
|
628
|
+
requires exactly one expression with no additional statements. Normalized
|
|
629
|
+
multi-statement bodies remain one async arrow expression.
|
|
630
|
+
Program diagnostic fields are bounded before transport, including escaped text;
|
|
631
|
+
a large custom error name cannot turn a failure into a truncated success.
|
|
452
632
|
|
|
453
633
|
**E7.** `retryable` for `unknown_address`, `unknown_tool`, and
|
|
454
634
|
`destructive_tool_requires_approval` is pinned false, never inferred from an
|
|
@@ -479,32 +659,45 @@ fields. Program-authored projection saved bytes; host heuristics could drop
|
|
|
479
659
|
deliberately returned fields. Helpers need [#222](https://github.com/zackbart/connecta/issues/222)
|
|
480
660
|
evidence that programs fail to project.
|
|
481
661
|
|
|
482
|
-
**R2.** The boundary is 24,000 serialized characters (~6k tokens)
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
**
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
662
|
+
**R2.** The boundary is 24,000 serialized characters (~6k tokens), shared with
|
|
663
|
+
emitted text. An oversized return is stashed as compact JSON through the same
|
|
664
|
+
result store as direct calls. The returned notice carries `truncated`, `resultId`,
|
|
665
|
+
`totalBytes`, `hint`, `nextOffset: 0`, and an executable `nextAction` that pages
|
|
666
|
+
with `connecta.result`. It also retains `totalChars` and a bounded `preview`.
|
|
667
|
+
The recovery action and hint precede the preview, so clients that spill results
|
|
668
|
+
after the first 2,000 characters retain the handle and the instruction.
|
|
669
|
+
Small returns pass through unchanged; Connecta does not select fields.
|
|
670
|
+
|
|
671
|
+
**R3.** Truncation is a _successful_ result. The program completed and its full
|
|
672
|
+
return can be read without running it again. Prefer filtering or reducing reads
|
|
673
|
+
before returning them. If the run completed a write, the notice opens with
|
|
674
|
+
"This write already ran: do not call it again to see its result."
|
|
675
|
+
This warning uses host accounting for writes completed in this run. Paging an
|
|
676
|
+
earlier write result does not count as a new write.
|
|
677
|
+
|
|
678
|
+
**R4.** Program returns share direct-call stash envelopes, 15-minute expiry,
|
|
679
|
+
aggregate capacity charges, and credential redaction before persistence.
|
|
680
|
+
Their pages bind the admitted subject, principal, endpoint/pool, origin, and
|
|
681
|
+
all contributing tool calls, resource and skill reads, and catalog metadata.
|
|
682
|
+
Downstream skill and resource dependencies require a whole-connector grant.
|
|
683
|
+
Local guides and catalog dependencies require visibility of the contributing connector or tool, even
|
|
684
|
+
when the metadata describes a write on a read-only endpoint.
|
|
685
|
+
Caught call failures retain that connector visibility when catalog loading or
|
|
686
|
+
tool resolution fails. Recovery messages listing configured connectors or
|
|
687
|
+
local guides retain visibility of those contributors too.
|
|
688
|
+
Each page rechecks current auth,
|
|
689
|
+
grants, pool membership, and trust. Reading a stash inside a program carries
|
|
690
|
+
its dependencies forward to any new return stash. The page cap is the smallest
|
|
691
|
+
of the deployment cap and contributing connectors' effective `maxResultBytes`.
|
|
692
|
+
Read-only endpoints cannot page write results. A UUID is a handle, never a grant.
|
|
693
|
+
|
|
694
|
+
If paging is unavailable because the stash is full, storage fails, or text
|
|
695
|
+
cannot round-trip as UTF-8, the successful return keeps the existing bounded
|
|
696
|
+
`{ truncated, preview, totalChars, hint }` fallback. Its hint explains that
|
|
697
|
+
paging is unavailable and retains the instruction to filter/map/slice. A write's
|
|
698
|
+
hint still says it already ran. Never rerun a write to recover its output.
|
|
699
|
+
JSON serialization preserves lone surrogates as escapes, so ordinary
|
|
700
|
+
JSON-returning programs can page them losslessly.
|
|
508
701
|
|
|
509
702
|
**R5.** `console.log`, `console.warn`, and `console.error` are captured in call
|
|
510
703
|
order and returned as one `logs` string, capped at 4,000 characters with a
|
|
@@ -512,18 +705,22 @@ truncation marker. Logs survive program failure through either a returned error
|
|
|
512
705
|
result or a thrown error carrying `logs: string[]`. QuickJS streams captured
|
|
513
706
|
entries to its parent and preserves the received prefix on cancellation,
|
|
514
707
|
shutdown, deadline termination, child crashes, and IPC failures (`X4`). How a
|
|
515
|
-
non-string argument renders is not contract (`X4`).
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
708
|
+
non-string argument renders is not contract (`X4`). At terminal host-call
|
|
709
|
+
budget exhaustion, QuickJS returns its streamed prefix; a Dynamic Worker
|
|
710
|
+
has no host log stream and cannot supply logs from its suspended guest (`L4`).
|
|
711
|
+
|
|
712
|
+
**R6.** Every run returns `hostCalls: { attempted, admitted, succeeded, failed }`,
|
|
713
|
+
including admission failure, cancellation, budget refusal, and code-size refusal.
|
|
714
|
+
Calls include search, describe, call, result, and skill. `emit` has separate budgets.
|
|
715
|
+
An abandoned host call counts as failed when the run ends; guest catches do not
|
|
716
|
+
change the counts. These numbers are outside the program's returned `result`.
|
|
717
|
+
`diagnostics: true` adds the existing payload-free timing block. Emitting adds
|
|
718
|
+
`emitted: N` and its content blocks.
|
|
522
719
|
|
|
523
720
|
**R7.** Diagnostic timing separates admission, provider setup, total executor
|
|
524
721
|
wall time, catalog work, and connector work. Catalog and connector values are
|
|
525
722
|
cumulative, so parallel work can exceed executor wall time. Each used operation
|
|
526
|
-
kind (`search`, `describe`, `call`) gets one aggregate with count, failures,
|
|
723
|
+
kind (`search`, `describe`, `call`, `read`) gets one aggregate with count, failures,
|
|
527
724
|
duration, returned serialized bytes, and catalog/connector time.
|
|
528
725
|
|
|
529
726
|
**R8.** Diagnostics contain measurements and fixed operation names only: no
|
|
@@ -533,13 +730,37 @@ request; it is not activity, a session, or a stream.
|
|
|
533
730
|
|
|
534
731
|
## Emitted output
|
|
535
732
|
|
|
733
|
+
Guest-authored images accept only `image/png`, `image/jpeg`, `image/gif`, or `image/webp`
|
|
734
|
+
and nonempty canonical base64. Whitespace, URL-safe alphabets, bad padding,
|
|
735
|
+
and nonzero pad bits are rejected before collection. Size budgets still apply.
|
|
736
|
+
|
|
536
737
|
MCP-native output a return value cannot carry: base64 is not projectable, so a
|
|
537
|
-
block that
|
|
538
|
-
|
|
738
|
+
block that fits the inline call limit (`S5`, `L6`) can use the separate
|
|
739
|
+
emission transport budget instead of the `R2` return guard.
|
|
740
|
+
The earlier alternatives are in [decision history](https://github.com/zackbart/connecta/blob/main/decisions/0001-ethos-verdict-table.md)
|
|
539
741
|
([#267](https://github.com/zackbart/connecta/issues/267),
|
|
540
742
|
[#270](https://github.com/zackbart/connecta/issues/270)).
|
|
541
743
|
|
|
542
|
-
**M1.** `connecta.emit(
|
|
744
|
+
**M1.** `connecta.emit(result)` accepts a rich result from this program's
|
|
745
|
+
`connecta.call` and forwards its original native content blocks, including
|
|
746
|
+
resources, resource links, annotations and `_meta`. `connecta.emit(block)` also
|
|
747
|
+
accepts individual entries of that result's `content`. The trusted guest
|
|
748
|
+
prelude maps these objects to opaque request-local references; the host checks
|
|
749
|
+
those references and emits owned deep snapshots of retained native blocks taken
|
|
750
|
+
before result paging can yield. Oversized structured data returns its paging
|
|
751
|
+
handle before native presentation is inspected. Presentation traversal stops at
|
|
752
|
+
64 levels, 32,768 values, or the larger of the default and configured emission
|
|
753
|
+
byte budgets. Only envelopes within the 1 MiB inline cap retain block snapshots.
|
|
754
|
+
Cycles, non-JSON values, and traversal limits refuse presentation with an
|
|
755
|
+
unavailable-paging notice; structured data remains usable. That notice has no
|
|
756
|
+
result ID and reports `totalBytes: 0` because traversal could not measure a
|
|
757
|
+
complete JSON value.
|
|
758
|
+
Connector mutations after retention cannot change guest output, accepted blocks,
|
|
759
|
+
or their byte and text charges, including nested resource fields and metadata.
|
|
760
|
+
Copies and guest-authored blocks keep the strict validation below. No program
|
|
761
|
+
can mint a native URI.
|
|
762
|
+
|
|
763
|
+
Guest-authored `connecta.emit(block)` accepts exactly one block: `{ type: "text",
|
|
543
764
|
text }` or `{ type: "image" | "audio", data /* base64 */, mimeType }`, every
|
|
544
765
|
field a string, no extra fields, no `annotations`, no `_meta`, no sugar forms.
|
|
545
766
|
An invalid block throws catchably and nothing is accepted — rejected, not
|
|
@@ -552,34 +773,44 @@ a successful result, appended to `content` after the JSON envelope, which gains
|
|
|
552
773
|
response (`R6`). `structuredContent` stays the envelope alone — emission is
|
|
553
774
|
presentation, not a second data channel.
|
|
554
775
|
|
|
555
|
-
**M3.**
|
|
556
|
-
|
|
557
|
-
|
|
776
|
+
**M3.** Text emission shares `R2`'s 24,000 serialized-character cap. Its
|
|
777
|
+
serialized block size reduces the return budget, and oversized text fails with
|
|
778
|
+
`result_too_large`. Image/audio blocks use the separate transport budget and
|
|
779
|
+
reach the model as real MCP media content, including when `emit` is not awaited.
|
|
780
|
+
Native embedded resource text also shares the result cap; resource blobs count
|
|
781
|
+
against the serialized-byte emission budget.
|
|
782
|
+
The trusted runner waits for emission acknowledgments before returning success.
|
|
783
|
+
An unobserved emission failure fails the run; an awaited failure remains catchable.
|
|
784
|
+
Rejections propagated through `then` or `finally` can be caught later in that
|
|
785
|
+
chain. A separate unhandled branch still fails the run.
|
|
558
786
|
|
|
559
787
|
**M4.** A failed program delivers no blocks. The error result reports
|
|
560
|
-
`emittedDiscarded: N` when N > 0
|
|
561
|
-
trailing line on the plain-text paths — never silently.
|
|
788
|
+
`emittedDiscarded: N` when N > 0 as a field on the structured envelope.
|
|
562
789
|
|
|
563
790
|
**M5.** Two budgets (`ConnectaConfig.execute.maxEmittedBytes` /
|
|
564
791
|
`.maxEmittedBlocks`, defaults 4,000,000 serialized bytes and 32 blocks) fail
|
|
565
792
|
loudly at the `emit` call, naming the budget and the room remaining; nothing is
|
|
566
|
-
partially accepted and prior blocks stand.
|
|
793
|
+
partially accepted and prior blocks stand. Forwarding a whole native result
|
|
794
|
+
checks every block before accepting any of them. Accepted and rejected emission attempts
|
|
795
|
+
also have a terminal limit of four times the configured block cap (at least 128),
|
|
796
|
+
which bounds retained host failures and guest acknowledgement state without
|
|
797
|
+
discarding an older error identity. No result stash for emitted blocks: the program
|
|
567
798
|
learns while it can still choose differently. The byte default is a transport
|
|
568
799
|
bound, not a context bound — emitted media reaches the model as media, not
|
|
569
800
|
base64 text.
|
|
570
801
|
|
|
571
802
|
**M6.** No provenance is claimed: every emitted block is program output, trusted
|
|
572
|
-
exactly as much as the return value.
|
|
573
|
-
downstream block,
|
|
803
|
+
exactly as much as the return value. Native forwarding preserves the raw
|
|
804
|
+
downstream block through a host-issued reference, within `S5`, `L6` and `M5`.
|
|
574
805
|
|
|
575
806
|
**M7.** `emit` alone spends no host-call budget (`L4`); `search`, `describe`,
|
|
576
|
-
and `
|
|
807
|
+
`call`, `read`, `result`, and `skill` share it. Text also observes `R2`.
|
|
577
808
|
|
|
578
|
-
**M8.**
|
|
579
|
-
blocks cross
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
emission for free.
|
|
809
|
+
**M8.** `emit` is a provider function. Guest-authored blocks cross as arguments;
|
|
810
|
+
native blocks cross once as call output and emissions send only their references.
|
|
811
|
+
Native call output uses the same bounded stash transfers as `L6`. `ExecuteResult` remains compatible with upstream codemode's types;
|
|
812
|
+
construction requires the Worker adapter or explicit custom opt-in. Any executor
|
|
813
|
+
that bridges provider calls gets emission for free.
|
|
583
814
|
|
|
584
815
|
**M9.** Request-local and unstreamed: blocks exist only in the finished
|
|
585
816
|
response, and `emit` resolving means "accepted," never "delivered."
|
|
@@ -607,7 +838,7 @@ host-call budget, so an unchecked loop converts a transient failure into
|
|
|
607
838
|
Dynamic-Worker-only wait would spend the run's wall clock on code that fails
|
|
608
839
|
on QuickJS. Return the failure and let the model, which can wait, re-issue
|
|
609
840
|
with `retryAfterMs` in hand.
|
|
610
|
-
- a cancelled or timed-out
|
|
841
|
+
- a cancelled or timed-out _execution_: it is already over (`L1`).
|
|
611
842
|
|
|
612
843
|
**Y4.** A provider's `retryAfterMs` is returned unchanged; the caller decides
|
|
613
844
|
whether and when to reissue, and a later call gets its own deadline and
|
|
@@ -620,14 +851,21 @@ poll, no cancellation exception to catch, and no guarantee that a `finally`
|
|
|
620
851
|
block runs — a cancelled QuickJS child is terminated outright. Write programs
|
|
621
852
|
that need no cleanup.
|
|
622
853
|
|
|
623
|
-
**L2.**
|
|
624
|
-
|
|
625
|
-
`
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
854
|
+
**L2.** Cancellation aborts in-flight host calls and admits no further calls,
|
|
855
|
+
including discovery. The response returns `executor_cancelled` without awaiting
|
|
856
|
+
a wedged executor or `acquire()` that ignores its signal. It releases the lease;
|
|
857
|
+
a late-granted lease releases on arrival. Nothing request-bound survives the
|
|
858
|
+
request. Whether guest computation stops is the executor's (`X3`).
|
|
859
|
+
|
|
860
|
+
Programs and direct calls use the same invocation deadline and stages. A call's
|
|
861
|
+
`timeoutMs` wins, then `calls.defaultTimeoutMs`, then `execute.hostCallTimeoutMs`
|
|
862
|
+
(default 15,000). A guest may request a longer individual call, but the sandbox
|
|
863
|
+
and request ceilings still bound the whole run. Timeout details are agent-facing;
|
|
864
|
+
INV-6 operator records retain only checked classifications and numeric facts.
|
|
865
|
+
A dispatched write timeout becomes `write_outcome_unknown` and retains its
|
|
866
|
+
deadline details even when the program catches the failure. The final program
|
|
867
|
+
error includes the first timeout in `details`; multiple write timeouts also
|
|
868
|
+
appear in `timeouts`, bounded to ten entries.
|
|
631
869
|
|
|
632
870
|
**L3.** Every execution runs under a wall-clock deadline that includes time
|
|
633
871
|
spent waiting on host calls. Expiry ends the run with an execution error and no
|
|
@@ -636,7 +874,7 @@ it sits a ceiling connecta enforces outside the sandbox, `execute.watchdogMs`
|
|
|
636
874
|
(120 s by default, above both executors' own deadlines), because an executor's
|
|
637
875
|
deadline may live inside the sandbox it is meant to stop: a wedged Dynamic
|
|
638
876
|
Worker never fires its in-isolate timer. A run whose executor has not settled
|
|
639
|
-
by the ceiling ends as a non-retryable `
|
|
877
|
+
by the ceiling ends as a non-retryable `timeout` whose message calls
|
|
640
878
|
the sandbox unresponsive, with no partial result, and its admission lease is
|
|
641
879
|
released, so wedged runs cannot fill the code pool. Raising an executor's
|
|
642
880
|
deadline past the ceiling means raising the ceiling too.
|
|
@@ -644,25 +882,38 @@ deadline past the ceiling means raising the ceiling too.
|
|
|
644
882
|
**L4.** Per-execution bounds that are contract, identical in both executors
|
|
645
883
|
because connecta enforces them above the sandbox:
|
|
646
884
|
|
|
647
|
-
| Bound
|
|
648
|
-
|
|
|
649
|
-
| Host calls per execution, shared by `search`, `describe`, and `
|
|
650
|
-
|
|
|
651
|
-
| Deadline per host call
|
|
652
|
-
| Discovery page
|
|
653
|
-
| `describe` addresses
|
|
654
|
-
| `describe` nearby suggestions
|
|
655
|
-
| Caller text echoed by `describe` recovery
|
|
656
|
-
| Result
|
|
657
|
-
| Logs presented to the model
|
|
658
|
-
|
|
659
|
-
Every `call`
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
`
|
|
664
|
-
|
|
665
|
-
|
|
885
|
+
| Bound | Value |
|
|
886
|
+
| ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
887
|
+
| Host calls per execution, shared by `search`, `describe`, `call`, and `read` | 20 by default, `execute.maxHostCalls` |
|
|
888
|
+
| Trusted-pool writes per run, on top of the host calls they also spend (`W10`) | 10 by default, `execute.maxWrites` |
|
|
889
|
+
| Deadline per host call | 15 s, `execute.hostCallTimeoutMs`; one deadline covers catalog resolution, admission, and the connector call |
|
|
890
|
+
| Discovery page | ≤ 100 tools, ≤ 256,000 serialized bytes |
|
|
891
|
+
| `describe` addresses | ≤ 100 |
|
|
892
|
+
| `describe` nearby suggestions | ≤ 3 canonical addresses per failed entry |
|
|
893
|
+
| Caller text echoed by `describe` recovery | ≤ 512 UTF-8 bytes per field, plus `…` |
|
|
894
|
+
| Result | 24,000 serialized characters |
|
|
895
|
+
| Logs presented to the model | 4,000 characters |
|
|
896
|
+
|
|
897
|
+
Every `call`, `read`, `search`, and `describe` spends one host call on entry, before
|
|
898
|
+
resolution, validation, or dispatch. Catching a local refusal refunds nothing.
|
|
899
|
+
The first call beyond the budget ends the host run with one non-retryable
|
|
900
|
+
`budget_exceeded` (`E2`). Its bridge stays pending until lease disposal so guest
|
|
901
|
+
`try/catch` cannot swallow it. Later host access, including `emit`, stops; pending
|
|
902
|
+
replies are withheld. The refusal reaches no connector, returns no partial result,
|
|
903
|
+
and discards accepted emits (`M4`). Calls still resolving or awaiting admission
|
|
904
|
+
are cancelled, including trusted-pool writes past their gate. Dispatched trusted-pool writes
|
|
905
|
+
drain under `W9`; unknown outcomes retain precedence. The lease then releases:
|
|
906
|
+
QuickJS terminates its child, and the Worker adapter disposes RPC and loader
|
|
907
|
+
handles independently of the guest deadline. Workers guest computation may
|
|
908
|
+
continue briefly, including a timer escaping the bridge (`X3`), with no host
|
|
909
|
+
access. The Promise executor contract carries typed failures separately from guest values.
|
|
910
|
+
|
|
911
|
+
The failure adds payload-free `hostCalls: { attempted, admitted, succeeded, failed }`
|
|
912
|
+
without diagnostics. `attempted` includes the first refusal, normally 21; `admitted`
|
|
913
|
+
counts the 20 calls past the gate, local refusals included. `succeeded` and `failed`
|
|
914
|
+
count outcomes at response time, the budget refusal and abandoned pending calls
|
|
915
|
+
as failed, so `succeeded + failed === attempted`. `emit` and later attempts are
|
|
916
|
+
excluded; no budget refills.
|
|
666
917
|
|
|
667
918
|
**L5.** The guest is memory-, stack-, and CPU-bounded, and a program that
|
|
668
919
|
exhausts a bound ends the run with an error instead of degrading the host. The
|
|
@@ -672,22 +923,44 @@ the Dynamic Worker inherits the platform isolate's limits (`X2`). A third
|
|
|
672
923
|
executor must bound all three somehow — this is the clause that makes untrusted
|
|
673
924
|
code safe to run at all.
|
|
674
925
|
|
|
675
|
-
**L6.**
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
926
|
+
**L6.** QuickJS bounds each serialized host-call message at 256 KiB. Full guest
|
|
927
|
+
returns cross bounded 65,536-character IPC chunks, with a 64 MiB aggregate
|
|
928
|
+
transport ceiling. The parent retains the completed value until it can apply
|
|
929
|
+
the result stash policy; the 1 MiB per-message IPC ceiling stays in force. Oversized
|
|
930
|
+
`connecta.call` results use the existing direct-call stash before crossing that
|
|
931
|
+
bridge. The trusted guest initializer reconstructs values up to 1 MiB from
|
|
932
|
+
bounded pages, retaining JSON versus text format and every payload code point,
|
|
933
|
+
including U+FEFF at page starts. Larger values return a
|
|
934
|
+
`{ format: "paged", valueFormat, resultId, totalBytes, truncated: true, hint }`
|
|
935
|
+
handle. Pass the handle or its `resultId` to `connecta.result` and reduce the
|
|
936
|
+
pages before returning them. Automatic transfers spend no additional host-call
|
|
937
|
+
budget; explicit paging does. This policy is shared by QuickJS, Worker and custom
|
|
938
|
+
executors that run provider preludes.
|
|
939
|
+
Oversized raw text containing unpaired UTF-16 surrogates returns a handle without
|
|
940
|
+
`resultId`, with a notice that it cannot be paged as text. This preserves the
|
|
941
|
+
UTF-8 byte-offset contract without silently replacing code units. The completed
|
|
942
|
+
call stays successful, including write accounting; JSON-wrapped strings still
|
|
943
|
+
round-trip losslessly.
|
|
944
|
+
|
|
945
|
+
Stashes retain their existing bindings, 15-minute expiry, per-connector page
|
|
946
|
+
caps and aggregate capacity charges on memory, SQLite and D1. Capacity exhaustion
|
|
947
|
+
or a storage failure returns a successful notice without a `resultId`. A failed
|
|
948
|
+
automatic reconstruction retains the handle. Neither result path reissues the
|
|
949
|
+
call or changes a completed write into a failed or unknown write. Guest returns use the same store when they exceed the presentation cap (`R2`–`R4`).
|
|
950
|
+
|
|
951
|
+
Over-bound arguments and other unpaged bridge results still fail catchably with
|
|
952
|
+
executor-owned text. An over-bound result names the called address; an argument
|
|
953
|
+
payload is refused before parsing and names no address.
|
|
682
954
|
|
|
683
955
|
**L7.** Executions are admitted, not queued indefinitely: bounded concurrency
|
|
684
956
|
plus a bounded queue with a wait timeout. Overload is a retryable
|
|
685
957
|
`executor_overloaded` carrying `retryAfterMs`; cancellation and shutdown are
|
|
686
|
-
terminal. Admission happens
|
|
958
|
+
terminal. Admission happens _before_ any catalog or provider is built, so a
|
|
687
959
|
queued request holds no state.
|
|
688
960
|
|
|
689
|
-
**L8.**
|
|
690
|
-
|
|
961
|
+
**L8.** Result, log, host-call, and emission budgets are deployment configuration.
|
|
962
|
+
A call may request `timeoutMs` just as a direct call does; the guest deadline is
|
|
963
|
+
capped by the time remaining before the program watchdog. `execute_code`'s description states the host-call
|
|
691
964
|
budget and the per-call deadline — the ones a program must plan around before it
|
|
692
965
|
runs. The result and log caps live here and in the truncation notice itself
|
|
693
966
|
(`R2`, `R5`).
|
|
@@ -705,7 +978,7 @@ event.
|
|
|
705
978
|
|
|
706
979
|
**V2.** Each event carries `connectorId`, `toolName`, `address`, `source`,
|
|
707
980
|
`outcome` (`success`, `error`, `timeout`, `cancelled`), `durationMs`,
|
|
708
|
-
`attempts`, and `errorCode` when the call
|
|
981
|
+
`attempts`, and `errorCode` when the call _failed_ — plus request, actor, and
|
|
709
982
|
server identity. Rows written before
|
|
710
983
|
[#672](https://github.com/zackbart/connecta/issues/672) may also carry the
|
|
711
984
|
`paused` and `approved` outcomes, `source: "resume_execution"`, and an
|
|
@@ -719,65 +992,89 @@ is still recorded. `address` is canonical (`A1`) where a tool resolved,
|
|
|
719
992
|
otherwise the name the program used — the honest record of what was attempted.
|
|
720
993
|
|
|
721
994
|
**V3.** A call whose connector does not exist is recorded at the address as
|
|
722
|
-
written,
|
|
995
|
+
written, _provided_ it split into the two fields activity keeps — one with no
|
|
723
996
|
interior dot records nothing. An invented id is the address mistake an operator
|
|
724
997
|
most needs to see, but recording it as written puts caller-authored text in
|
|
725
998
|
fields that are otherwise operator- and connector-authored, so `connectorId`
|
|
726
999
|
and `toolName` clamp at 128 UTF-8 bytes (`address` at 257) with a `…` marker:
|
|
727
|
-
payload-free
|
|
1000
|
+
payload-free _by construction_ means the event has nowhere to put a payload.
|
|
728
1001
|
|
|
729
1002
|
**V4.** The execution itself emits no event. It has no address, and its one
|
|
730
|
-
distinctive
|
|
1003
|
+
distinctive output is the program source — exactly what a payload-free history
|
|
731
1004
|
must never keep.
|
|
732
1005
|
|
|
733
|
-
**V5.**
|
|
1006
|
+
**V5.** A trusted-pool write a program issues after it has already returned is not
|
|
734
1007
|
sent and records nothing: it was never an attempt (`W9`).
|
|
735
1008
|
|
|
736
1009
|
## Writes
|
|
737
1010
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
`
|
|
779
|
-
|
|
780
|
-
|
|
1011
|
+
Pool trust belongs to deployment code. The default `/mcp` endpoint uses
|
|
1012
|
+
`trust: "read-only"`; each named pool has its own `trust`, also defaulting to
|
|
1013
|
+
`"read-only"`. A trusted default endpoint does not make named pools trusted.
|
|
1014
|
+
The default preserves refusal of ordinary program writes. A deployment must opt into program writes explicitly.
|
|
1015
|
+
|
|
1016
|
+
```ts
|
|
1017
|
+
createConnecta({
|
|
1018
|
+
connectors, executor,
|
|
1019
|
+
trust: "read-only",
|
|
1020
|
+
pools: {
|
|
1021
|
+
automation: { tools: ["posthog"], trust: "trusted", grant },
|
|
1022
|
+
},
|
|
1023
|
+
classification: {
|
|
1024
|
+
posthog: { exec: "read" }, // only for a deployment with a read-only exec contract
|
|
1025
|
+
vendor: { mislabeled_update: "write" },
|
|
1026
|
+
},
|
|
1027
|
+
});
|
|
1028
|
+
```
|
|
1029
|
+
|
|
1030
|
+
The registry computes one `classifyTool` verdict on each request-scoped
|
|
1031
|
+
published catalog entry. It caches and persists only raw downstream facts.
|
|
1032
|
+
Every caller consumes that stored verdict. Config cannot classify an individual
|
|
1033
|
+
invocation's arguments: marking a mixed entry point read is an assertion about
|
|
1034
|
+
all calls this deployment can make through it.
|
|
1035
|
+
|
|
1036
|
+
| Precedence | Evidence | Result |
|
|
1037
|
+
| ---------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
1038
|
+
| 1 | Exact deployment `classification[connectorId][toolName]` | `read` or `write`, even over a stale provider review |
|
|
1039
|
+
| 2 | `Connector.classification` provider review | Reviewed writes remain writes; a stale schema digest makes a read a write; an explicit downstream contradiction also invalidates a reviewed read |
|
|
1040
|
+
| 3 | Downstream annotations | Read only when `readOnlyHint === true && destructiveHint !== true`; otherwise write |
|
|
1041
|
+
|
|
1042
|
+
Unknown connector override keys fail construction. Unknown static tool keys
|
|
1043
|
+
fail construction; unknown remote tool keys fail publication of the whole
|
|
1044
|
+
catalog. Overrides are exact tool names, including names containing dots.
|
|
1045
|
+
They are never inferred from descriptions or arguments.
|
|
1046
|
+
|
|
1047
|
+
**W9.** Programs in trusted pools may write. A dispatched write is awaited even
|
|
1048
|
+
if the program does not await it, bounded by its host-call deadline. A write
|
|
1049
|
+
that reaches accounting after the program settles is not sent. An unanswered
|
|
1050
|
+
write makes the run fail `write_outcome_unknown` with
|
|
1051
|
+
`writes: { succeeded, failed, unknown }`, regardless of its return value.
|
|
1052
|
+
A failed program that already wrote carries those counts on its error. No
|
|
1053
|
+
write is automatically retried, including an ambiguous timeout. A downstream
|
|
1054
|
+
refusal or a tool's `isError` can establish failure; a timeout or an unanswered
|
|
1055
|
+
transport failure leaves the outcome unknown.
|
|
1056
|
+
|
|
1057
|
+
**W10.** `execute.maxWrites`, default 10, bounds writes in trusted programs in
|
|
1058
|
+
addition to the host-call budget. It is checked after argument validation and
|
|
1059
|
+
before admission, so an over-budget write spends no permit.
|
|
1060
|
+
|
|
1061
|
+
Program `uncertainCall` and `uncertainCalls` use the same schema-filtered argument
|
|
1062
|
+
snapshots as direct calls, even when guest code catches the failure. `argsRedacted: true`
|
|
1063
|
+
means sensitive fields were omitted or the entire echo was withheld because
|
|
1064
|
+
sensitivity could not be resolved. `argsOmitted: true` means no `args` is present,
|
|
1065
|
+
including echoes above the byte budget. These fields identify targets for
|
|
1066
|
+
reconciliation. Any new call must use the original arguments when its echo is
|
|
1067
|
+
partial or absent. A returned `writes` count cannot make a run safe to repeat.
|
|
1068
|
+
See [argument echo rules](./meta-tools.md#echo-budgets) for supported schema shapes.
|
|
1069
|
+
|
|
1070
|
+
**W12.** `trusted` endpoints annotate `execute_code` as a write and permit
|
|
1071
|
+
program writes. `read-only` endpoints annotate it as read-only and refuse
|
|
1072
|
+
program writes before validation, with `call_destructive_tool` as the recovery.
|
|
1073
|
+
`call_tool` accepts only reads in either tier; `call_destructive_tool` may send
|
|
1074
|
+
writes in either tier. Approval belongs to the host. Trust grants no tool or
|
|
1075
|
+
connector access and cannot be set by guest code, request arguments, or a
|
|
1076
|
+
downstream catalog. `execute.approval`, `Connector.approval`, and per-tool
|
|
1077
|
+
approval exemptions are removed. `W1`–`W8` and `W11` remain retired.
|
|
781
1078
|
|
|
782
1079
|
## Executor exceptions
|
|
783
1080
|
|
|
@@ -796,12 +1093,13 @@ isolate limits apply untuned. A specific heap ceiling is a Node-only option.
|
|
|
796
1093
|
`AbortSignal` and kills the child — SIGTERM, then SIGKILL if it has not exited
|
|
797
1094
|
within a second — and releasing a lease whose child is still running recycles
|
|
798
1095
|
that child, so a run the watchdog abandons (`L3`) ends too.
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
1096
|
+
Upstream `execute()` takes no signal; its guest timeout may never settle after
|
|
1097
|
+
the parent response ends. `workerExecutor()` owns each lease's RPC and loader
|
|
1098
|
+
handles: release disposes them, detaches host functions, and settles the adapter's
|
|
1099
|
+
promise independently of upstream evaluation. Guest computation may continue
|
|
1100
|
+
briefly until platform teardown, but no late return, callback, `finally`, call,
|
|
1101
|
+
or emit changes the finished host result. Disposal releases request resources;
|
|
1102
|
+
it does not guarantee a synchronous guest-CPU kill.
|
|
805
1103
|
|
|
806
1104
|
**X4. Log rendering and capture.** QuickJS JSON-stringifies non-string arguments
|
|
807
1105
|
and captures `log`, `info`, `warn`, `error`, and `debug`; the Dynamic Worker
|
|
@@ -820,14 +1118,16 @@ starts has no guest logs to recover.
|
|
|
820
1118
|
`process`, timers, `crypto`, or `WebSocket`, and its Node child starts with an
|
|
821
1119
|
explicit environment holding only `TZ=UTC`, so local time matches a Dynamic
|
|
822
1120
|
Worker's, rather than inheriting
|
|
823
|
-
deployment variables or `NODE_OPTIONS`. A Dynamic Worker
|
|
824
|
-
|
|
825
|
-
`node:
|
|
826
|
-
|
|
827
|
-
The
|
|
1121
|
+
deployment variables or `NODE_OPTIONS`. A Dynamic Worker exposes runtime-only
|
|
1122
|
+
builtins through `import()` and `process.getBuiltinModule()`, including `node:path`,
|
|
1123
|
+
`node:crypto`, `node:net`, `node:tls`, `node:dns`, and
|
|
1124
|
+
`cloudflare:workers`; the upstream set drifts, so that is not an allowlist.
|
|
1125
|
+
The adapter refuses `node:module` and `node:process` imports and removes their
|
|
1126
|
+
builtin lookup routes, so `createRequire` cannot resolve runner modules.
|
|
1127
|
+
The supported adapter uses `new DynamicWorkerExecutor({ loader, timeout })`.
|
|
828
1128
|
`bindings`, `modules`, and `globalOutbound` each grant ambient configuration,
|
|
829
|
-
code, or egress. Under it, `process.env
|
|
830
|
-
`
|
|
1129
|
+
code, or egress. Under it, `process.env` and `cloudflare:workers.env` are empty,
|
|
1130
|
+
and lexical `this.env` is undefined; `node:fs`, `node:http`, and `node:https` are
|
|
831
1131
|
unavailable through either access route; external `fetch`, `WebSocket`,
|
|
832
1132
|
`node:net`, and `node:tls` fail with workerd's outbound-denial error; DNS lookup
|
|
833
1133
|
ends unresolved; and `fetch("data:...")` resolves locally. `P2` is the portable
|
|
@@ -844,9 +1144,9 @@ reasonable demand on a platform sandbox.
|
|
|
844
1144
|
values through a tagged envelope, so a `Uint8Array` may survive there. `P3` is
|
|
845
1145
|
the contract: JSON-serializable values, or the program is Workers-only.
|
|
846
1146
|
|
|
847
|
-
**X8. Unknown
|
|
848
|
-
|
|
849
|
-
|
|
1147
|
+
**X8. Unknown properties.** The guest namespace exposes only the seven documented
|
|
1148
|
+
functions. Unknown and inherited members are absent on both executors; calling
|
|
1149
|
+
one is a guest `TypeError` under `E6`. Engine message text is not contract.
|
|
850
1150
|
|
|
851
1151
|
**X9. Refusing a value outside JSON.** The Dynamic Worker ends the run with an
|
|
852
1152
|
error when a program returns something its codec cannot carry. QuickJS converts
|
|
@@ -856,81 +1156,87 @@ Normalizing that would spend real CPU on every program to improve the error
|
|
|
856
1156
|
message of a program that is already wrong. `P3` is the contract: neither
|
|
857
1157
|
behavior returns the value.
|
|
858
1158
|
|
|
859
|
-
**X10. Per-host-call payload bound.** `L6`'s 256 KiB
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
one tool call therefore fails on Node and may succeed on Workers — reduce inside
|
|
865
|
-
the program either way (`R1`).
|
|
1159
|
+
**X10. Per-host-call payload bound.** QuickJS enforces `L6`'s 256 KiB message
|
|
1160
|
+
ceiling at its IPC boundary. The Dynamic Worker uses Workers RPC limits.
|
|
1161
|
+
Connecta's shared program result policy keeps call results and result pages
|
|
1162
|
+
within the QuickJS message ceiling on every executor. It does not raise the
|
|
1163
|
+
argument limit or the guest's heap, CPU, execution, or returned-result limits.
|
|
866
1164
|
|
|
867
1165
|
**X12** described a paused sandbox and left with pausing
|
|
868
1166
|
([#672](https://github.com/zackbart/connecta/issues/672)); the id stays retired.
|
|
869
1167
|
|
|
870
|
-
**X11. Typed host rejection.**
|
|
871
|
-
host
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
1168
|
+
**X11. Typed host rejection.** QuickJS creates and retains guest Error handles
|
|
1169
|
+
in its host bridge and compares handles when the program rejects. The Worker
|
|
1170
|
+
adapter stores each typed failure in a per-run host map under a random UUID.
|
|
1171
|
+
Its private entrypoint associates that ID with the guest Error and returns only
|
|
1172
|
+
the ID through Worker Loader RPC. The host resolves it to its own record before
|
|
1173
|
+
upstream result shaping; unknown or forged IDs attach no typed details, and IDs
|
|
1174
|
+
from previous runs cannot resolve. Rethrowing an earlier call's Error retains
|
|
1175
|
+
that call's record. The guest receives a separate copy for catching errors.
|
|
1176
|
+
Both construct `failure.call` from host-retained values, never from a guest
|
|
1177
|
+
result, parsed guest-realm object, or printed text. The Worker codec checks own
|
|
1178
|
+
binary-envelope properties, and completion uses captured array iteration even
|
|
1179
|
+
when the executor runs without the Connecta guest prelude. Host failure details are
|
|
1180
|
+
bounded before bridging (`E1`), including JSON escapes. No frame parser or
|
|
1181
|
+
prose matching participates in classification. The guest cannot import runner
|
|
1182
|
+
modules or repeat privileged initialization. QuickJS checks host interrupt and
|
|
1183
|
+
deadline facts before describing a rejection. It retains a private native Error
|
|
1184
|
+
brand check and reads only own string data descriptors for diagnostics; guest
|
|
1185
|
+
accessors, serialization hooks, and Proxy traps do not run. Other thrown objects
|
|
1186
|
+
receive a fixed description.
|
|
878
1187
|
|
|
879
1188
|
## Verification
|
|
880
1189
|
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
`test/
|
|
890
|
-
|
|
891
|
-
|
|
|
892
|
-
|
|
|
893
|
-
| `
|
|
894
|
-
| `
|
|
895
|
-
| `
|
|
896
|
-
| `
|
|
897
|
-
| `
|
|
898
|
-
| `
|
|
899
|
-
| `
|
|
900
|
-
| `
|
|
901
|
-
| `
|
|
902
|
-
| `
|
|
903
|
-
| `
|
|
904
|
-
| `
|
|
905
|
-
| `
|
|
906
|
-
| `
|
|
907
|
-
| `
|
|
908
|
-
| `
|
|
909
|
-
| `
|
|
910
|
-
| `
|
|
911
|
-
| `
|
|
912
|
-
| `
|
|
913
|
-
| `
|
|
914
|
-
| `
|
|
915
|
-
| `
|
|
916
|
-
| `
|
|
917
|
-
| `
|
|
918
|
-
| `
|
|
919
|
-
| `
|
|
920
|
-
| `
|
|
921
|
-
| `
|
|
922
|
-
| `
|
|
923
|
-
| `
|
|
924
|
-
| `
|
|
925
|
-
| `
|
|
926
|
-
| `
|
|
927
|
-
| `
|
|
928
|
-
| `
|
|
929
|
-
| `
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
| `X7` | `P3`'s tests; the Workers superset is deliberately unused |
|
|
933
|
-
|
|
934
|
-
The surface itself is checked by `test/server.test.ts` (the exact seven-tool list),
|
|
1190
|
+
`test/guest-contract-cases.ts` runs on QuickJS in `test/guest-api-contract-quickjs.node.test.ts`
|
|
1191
|
+
and on the Worker adapter with a real Miniflare Loader in `test/guest-api-contract.test.ts`.
|
|
1192
|
+
Titles name clauses; executor-independent clauses run in both arms.
|
|
1193
|
+
`test/codemode-compat.test.ts` pins upstream shape compatibility, minified upstream
|
|
1194
|
+
rejection, and branded adapter acceptance across module copies.
|
|
1195
|
+
|
|
1196
|
+
| Clauses | Test |
|
|
1197
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1198
|
+
| `P1`, `P5` | both guest-contract executors (TypeScript syntax, trailing terminators, wrapper recovery), `test/program-source.test.ts` (which semicolons and wrappers are recovered), `test/quickjs-executor.node.test.ts` (`normalizeCode`) |
|
|
1199
|
+
| `P2`, `X5` | `test/guest-api-contract.test.ts` (Dynamic globals plus loader-only filesystem, HTTP, environment, egress, DNS, and local `data:` boundaries), `test/guest-api-contract-quickjs.node.test.ts` (exact absent globals and blocked imports), `test/quickjs-child-stderr.node.test.ts` (a child-process environment holding only `TZ=UTC`), `test/deployment-shapes.node.test.ts` (loader-only Worker construction) |
|
|
1200
|
+
| `P3`, `X9` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` |
|
|
1201
|
+
| `P4` | `test/guest-api-contract.test.ts` (no cross-run leakage), `test/execute.test.ts` (one catalog load per connector per execution) |
|
|
1202
|
+
| `A1`, `A2` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (canonical addressing), `test/server.test.ts` (bounded live connector inventory) |
|
|
1203
|
+
| `S1`, `S1a`, `S2` | `test/guest-api-contract.test.ts` (flat page, connector guides, schema keys, unfiltered browse), `test/execute.test.ts` (guide pagination/partial/no-match behavior and `$ref`/`allOf`), `test/meta-tools-search.test.ts` (mixed complete/partial ranking, stable pagination, the two safety classes), `test/typescript-signatures.test.ts` (the TypeScript format over provider and pathological schemas, search/describe parity, observed labeling), `test/typescript-signatures-parse.node.test.ts` (every rendering parses) |
|
|
1204
|
+
| `S3` | `test/guest-api-contract.test.ts` (typed uncaught bound), `test/execute.test.ts` (count limits, fan-out bound) |
|
|
1205
|
+
| `S4` | both guest-contract executors (ordered mixed describe results with unknown-address, unknown-tool suggestion, and catalog-failure details), `test/meta-tools-search.test.ts` (top-level routing, no-suggestion, catalog-failure, and hostile-input bounds) |
|
|
1206
|
+
| `S5`, `S6` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (`unwrapMcpResult`, fail-closed annotations, activity parity) |
|
|
1207
|
+
| `S7` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (parallel calls and shared admission) |
|
|
1208
|
+
| `S8`, `E1`, `X11` | both guest-contract executors (caught call, discovery, utility, removed-function, and forgery cases; typed promise rejections), `test/quickjs-executor.node.test.ts` (oversized messages, private transport, forged outcomes) |
|
|
1209
|
+
| `S9` | `test/result-shapes.test.ts` (value exclusion, bounds, merging, LRU and time expiry, runtime isolation, read-only admission, declared precedence, definition invalidation, unwrapped MCP results, discovery provenance, copy isolation, failure isolation) |
|
|
1210
|
+
| `S10` | `test/resource-read.test.ts` (qualified routing, whole-connector grants, personal credentials, redaction, admission, timeout, cancellation and downstream MCP reads), both guest-contract executors (successful resource reads and caught/uncaught typed failures) |
|
|
1211
|
+
| `E2`, `E8` | `test/guest-api-contract.test.ts` (code → `retryable`, caught, parallel, and uncaught validation recovery, a conflict's bounded `current`), `test/meta-tools-call.test.ts` (direct, destructive, provider fallback), `test/validate.test.ts` (bounded payload-free findings), `test/errors.test.ts` |
|
|
1212
|
+
| `E3`, `E4` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (`auth_required`, destructive reroute), `test/program-writes.test.ts` (the refusal's `nextAction`, nothing sent, a caught refusal) |
|
|
1213
|
+
| `E5` | `test/guest-api-contract.test.ts` (execution-failure channel, in-flight `cancelled`), `test/execute.test.ts` (admission), `test/executor-admission.test.ts`, `test/quickjs-executor.node.test.ts` (mid-run shutdown) |
|
|
1214
|
+
| `E6`, `X8` | `test/guest-api-contract.test.ts` (unknown and inherited members, retained error identities), `test/quickjs-executor.node.test.ts` |
|
|
1215
|
+
| `E7` | `test/guest-api-contract.test.ts` (refusals about a `503`-named connector), `test/errors.test.ts` |
|
|
1216
|
+
| `R1`, `R2`, `R3`, `R4` | `test/guest-api-contract.test.ts` and `test/guest-api-contract-quickjs.node.test.ts` (small pass-through, shared return paging and unavailable fallback, no repeated writes, live authority), `test/program-result-cases.ts` (reconstruction, redaction, notice survives a 2,000-character spill) |
|
|
1217
|
+
| `M6`, `M9` | verdicts; `R2`'s guard, `M1`'s strict typing, and `M2`'s collect-then-deliver are their enforcement |
|
|
1218
|
+
| `R5` | `test/guest-api-contract.test.ts`, `test/quickjs-log-limits.node.test.ts` |
|
|
1219
|
+
| `R6`–`R8` | `test/guest-api-contract.test.ts` (normal result keys), `test/execute.test.ts` (opt-in operation aggregates, failure paths, payload exclusion) |
|
|
1220
|
+
| `Y1`, `Y2`, `Y3` | `test/guest-api-contract.test.ts` (one attempt per call, retryable flags by code) |
|
|
1221
|
+
| `Y4` | `test/meta-tools-call.test.ts`, `test/call-admission.test.ts` (one attempt, retry hints, caller reissue) |
|
|
1222
|
+
| `L1`, `L2` | `test/guest-api-contract.test.ts` (in-flight call fails `cancelled`), `test/execute.test.ts` (cancels outstanding host calls, discovery included, and refuses discovery after the run; a cancelled wedged executor, or one whose `acquire()` ignores the signal, returns promptly and releases its lease) |
|
|
1223
|
+
| `L3`, `X1` | `test/guest-api-contract.test.ts` (short-deadline executors), `test/execute.test.ts` (the watchdog ends a never-settling executor, frees the default pool, spares a slow run, and falls back from an unusable value) |
|
|
1224
|
+
| `L4`, `L8` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (shared discovery/call budgets and terminal catch-and-continue loops and queued-write cancellation on both executors), `test/worker-budget-response.node.test.ts` (native handle disposal and admission recovery across completed HTTP responses) |
|
|
1225
|
+
| `L5`, `L7`, `X2` | `test/quickjs-executor.node.test.ts` (CPU, heap), `test/execute.test.ts` and `test/executor-admission.test.ts` (bounded admission and queue) |
|
|
1226
|
+
| `L6`, `X10` | `test/guest-api-contract-quickjs.node.test.ts` and `test/guest-api-contract.test.ts` (whole oversized reads and one-write pageable handles), `test/sqlite-storage.node.test.ts` and `test/d1-storage.node.test.ts` (shared stash transfers), `test/quickjs-executor.node.test.ts` (bridge and IPC bounds for arguments and result; the address in the over-bound message), `test/quickjs-child-stderr.node.test.ts` (outer reply serialization failure settles the call) |
|
|
1227
|
+
| `V1`–`V4` | `test/guest-api-contract.test.ts` (dispatched calls, every refusal class including an address no connector owns, the friction each derives, no event for the execution itself), `test/activity.test.ts` (the shared code → friction table, the identity clamp, the one-attempt floor), `test/operator-view.test.ts`, `test/sql-storage-contract.ts`, run by `test/d1-storage.node.test.ts` and `test/sqlite-storage.node.test.ts` (historical pause and approval rows still render and round-trip) |
|
|
1228
|
+
| `V5`, `W9` | `test/program-writes.test.ts` (an unawaited trusted-pool write finished and recorded, its unknown outcome reported, counts on a failed program, the classification table), `test/invocation-pipeline.test.ts` (the gate after validation, an unrecorded refusal) |
|
|
1229
|
+
| `W10`, `W12` | `test/program-writes.test.ts` (a trusted-pool write runs and every other write keeps `E4`, the write budget, pool trust and override precedence, `call_tool` still refusing, search and describe verdicts, construction refusals), `test/operator-ui-model.test.ts`, `test/browser/operator-ui.spec.ts` (the badge) |
|
|
1230
|
+
| `M1` | `test/guest-api-contract.test.ts` (invalid emits throw catchably, accept nothing), `test/execute-emit.test.ts` (rejected shapes, bounded native snapshots, paging before metadata traversal, and cyclic presentation refusal) |
|
|
1231
|
+
| `M2`, `M3` | `test/guest-api-contract.test.ts` (delivery order, truncated return plus delivered blocks), `test/execute-emit.test.ts` (envelope, `structuredContent`, byte-for-byte no-emit path) |
|
|
1232
|
+
| `M4` | `test/guest-api-contract.test.ts` (discard is visible), `test/execute-emit.test.ts` (structured and plain paths), `test/quickjs-executor.node.test.ts` (mid-run shutdown) |
|
|
1233
|
+
| `M5`, `M7` | `test/execute-emit.test.ts` (both budgets fail the crossing block; host-call budget untouched) |
|
|
1234
|
+
| `M8` | two arms passing one case table, `test/codemode-compat.test.ts` |
|
|
1235
|
+
| `M10` | `test/execute-emit.test.ts` (aggregate present, numbers only, absent when nothing emitted) |
|
|
1236
|
+
| `X4` | `test/guest-api-contract.test.ts` (string logs only), `test/quickjs-executor.node.test.ts` (logs before cancellation), `test/quickjs-child-stderr.node.test.ts` (crash, shutdown, deadline, IPC failure, bounded parent retention), `test/quickjs-log-limits.node.test.ts` (unchanged successful logs) |
|
|
1237
|
+
| `X3`, `X6` | `test/quickjs-executor.node.test.ts` (cancels a running child, never-settling await), `test/execute.test.ts` (a wedged executor stops being awaited) |
|
|
1238
|
+
| `X7` | `P3`'s tests; the Workers superset is deliberately unused |
|
|
1239
|
+
|
|
1240
|
+
The surface itself is checked by `test/server.test.ts` (the exact six-tool list),
|
|
935
1241
|
`test/code-first-surface.test.ts` (construction, executor, removed tools, copy, and size),
|
|
936
1242
|
and `test/program-writes.test.ts` (the retired pause options refused at construction).
|