@zackbart/connecta 0.22.3 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +5 -0
- package/CHANGELOG.md +82 -0
- package/README.md +19 -11
- package/dist/activity-friction.d.ts +3 -0
- package/dist/activity-friction.js +19 -0
- package/dist/activity.d.ts +11 -2
- package/dist/activity.js +15 -19
- package/dist/auth/downstream-oauth.d.ts +2 -1
- package/dist/auth/downstream-oauth.js +10 -1
- package/dist/branding.d.ts +67 -0
- package/dist/branding.js +176 -0
- package/dist/catalog-service.d.ts +1 -6
- package/dist/catalog-service.js +3 -53
- package/dist/connectors/remote-mcp.js +3 -5
- package/dist/credential-contract.d.ts +24 -0
- package/dist/credential-contract.js +1 -0
- package/dist/credential-rules.d.ts +85 -0
- package/dist/credential-rules.js +107 -0
- package/dist/credentials.d.ts +4 -100
- package/dist/credentials.js +3 -107
- package/dist/errors.d.ts +1 -1
- package/dist/execute.d.ts +5 -52
- package/dist/execute.js +40 -347
- package/dist/executors/quickjs-protocol.d.ts +0 -7
- package/dist/executors/quickjs-protocol.js +2 -10
- package/dist/executors/quickjs.js +1 -1
- package/dist/index.d.ts +23 -56
- package/dist/index.js +30 -58
- package/dist/invocation.d.ts +0 -33
- package/dist/invocation.js +56 -124
- package/dist/meta-tools.d.ts +7 -6
- package/dist/meta-tools.js +14 -21
- package/dist/module-contracts.d.ts +19 -0
- package/dist/module-contracts.js +1 -0
- package/dist/operator-ui/generated.js +2 -2
- package/dist/operator-ui/model.d.ts +6 -3
- package/dist/operator-ui/view.d.ts +2 -18
- package/dist/operator-ui/view.js +3 -20
- package/dist/registry.d.ts +4 -1
- package/dist/registry.js +8 -6
- package/dist/routes/activity.js +1 -1
- package/dist/routes/credentials.js +5 -2
- package/dist/routes/mcp.js +7 -51
- package/dist/routes/oauth-management.d.ts +2 -0
- package/dist/routes/oauth-management.js +108 -0
- package/dist/routes/oauth.d.ts +0 -1
- package/dist/routes/oauth.js +21 -121
- package/dist/routes/shared.d.ts +19 -17
- package/dist/routes/shared.js +48 -44
- package/dist/routes/ui.js +36 -33
- package/dist/server.d.ts +1 -2
- package/dist/server.js +7 -45
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +55 -19
- package/dist/types.d.ts +3 -15
- package/dist/ui.d.ts +15 -70
- package/dist/ui.js +176 -317
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/architecture.md +31 -26
- package/documentation/auth.md +65 -111
- package/documentation/call-admission.md +10 -11
- package/documentation/cloudflare.md +1 -1
- package/documentation/code-mode.md +65 -260
- package/documentation/connectors.md +8 -6
- package/documentation/linear.md +1 -1
- package/documentation/meta-tools.md +37 -18
- package/documentation/mixpanel.md +1 -1
- package/documentation/notion.md +2 -2
- package/documentation/operations.md +19 -23
- package/documentation/operator-ui.md +82 -104
- package/documentation/optional-modules-upgrade.md +243 -0
- package/documentation/provider-conventions.md +7 -5
- package/documentation/revenuecat.md +1 -1
- package/documentation/storage-and-credentials.md +59 -40
- package/documentation/stripe.md +1 -1
- package/documentation/upgrading.md +83 -8
- package/ethos.md +36 -43
- package/examples/worker/AGENTS.md +3 -1
- package/examples/worker/README.md +68 -84
- package/examples/worker/src/d1-activity.ts +1 -1
- package/examples/worker/src/index.ts +11 -6
- package/package.json +18 -2
- package/templates/node/AGENTS.md +8 -6
- package/templates/node/README.md +56 -67
- package/templates/node/package.json +1 -1
- package/templates/node/src/file-activity.ts +1 -1
- package/templates/node/src/index.ts +11 -12
- package/dist/access-tokens.d.ts +0 -31
- package/dist/access-tokens.js +0 -236
- package/dist/apps-shell.d.ts +0 -37
- package/dist/apps-shell.js +0 -174
- package/dist/routes/access-tokens.d.ts +0 -6
- package/dist/routes/access-tokens.js +0 -83
|
@@ -83,30 +83,23 @@ interface ExecuteResult {
|
|
|
83
83
|
Connecta passes exactly one provider, named `connecta`. An executor must:
|
|
84
84
|
|
|
85
85
|
1. **Expose each provider as a guest global** whose properties are its `fns`,
|
|
86
|
-
called with the program's arguments and awaited. Connecta
|
|
87
|
-
`
|
|
88
|
-
point 3.
|
|
86
|
+
called with the program's arguments and awaited. Connecta supplies `search`,
|
|
87
|
+
`describe`, `call`, and `emit`.
|
|
89
88
|
2. **Evaluate `prelude` after the provider globals exist and before the
|
|
90
|
-
program
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
3. **Let the prelude reach the provider.** That prelude
|
|
94
|
-
(`lazyNamespacePrelude` in `src/execute.ts`) assigns one
|
|
95
|
-
`globalThis[<connectorId>]` Proxy per connector, each forwarding to
|
|
96
|
-
`connecta.__callNamespace(connectorId, toolName, args)`. An executor exposing
|
|
97
|
-
only the four documented functions leaves every shortcut dead and breaks `A2`.
|
|
98
|
-
4. **Marshal values as JSON** in both directions (`P3`), and reject a host call
|
|
89
|
+
program.** This is trusted host code. Connecta uses it to restore typed host
|
|
90
|
+
errors in the guest without exposing the private error frame.
|
|
91
|
+
3. **Marshal values as JSON** in both directions (`P3`), and reject a host call
|
|
99
92
|
whose function is not an own property of `fns` — the guest can ask for
|
|
100
93
|
anything, including inherited members.
|
|
101
|
-
|
|
94
|
+
4. **Return, never throw, for a failed program**: set `error` to the guest's
|
|
102
95
|
message, leave `result` undefined. `createExecuteTool` reads `error` first and
|
|
103
96
|
matches it back to the failures recorded during the run, which is how an
|
|
104
97
|
uncaught tool failure keeps its type (`E1`).
|
|
105
|
-
|
|
98
|
+
5. **Capture `console.log`, `console.warn`, and `console.error`** into `logs` in
|
|
106
99
|
call order (`R5`), bounding what it retains.
|
|
107
|
-
|
|
100
|
+
6. **Bound the guest**: wall clock, memory, stack, and CPU (`L3`, `L5`). Keep
|
|
108
101
|
ambient capabilities within the documented and tested `P2`/`X5` boundary.
|
|
109
|
-
|
|
102
|
+
7. **Grant no ambient authority of its own.** Never back this with `eval` or
|
|
110
103
|
`node:vm`: the sandbox is a containment layer on top of connecta's boundary,
|
|
111
104
|
not a replacement for it, and every capability arrives through `fns`.
|
|
112
105
|
|
|
@@ -130,14 +123,9 @@ reinterpreted, so do not rely on it.
|
|
|
130
123
|
|
|
131
124
|
**P2.** The only capabilities in the contract are:
|
|
132
125
|
|
|
133
|
-
-
|
|
134
|
-
- `connecta.search`, `connecta.describe`, `connecta.call`, `connecta.batch`;
|
|
126
|
+
- `connecta.search`, `connecta.describe`, `connecta.call`, `connecta.emit`;
|
|
135
127
|
- `console.log`, `console.warn`, `console.error`, captured and returned.
|
|
136
128
|
|
|
137
|
-
`connecta` also carries the `__`-prefixed dispatcher the shortcut prelude uses.
|
|
138
|
-
It is host plumbing, callable but not contract: it takes a connector id and an
|
|
139
|
-
unsanitized-or-sanitized tool name and can change shape without notice.
|
|
140
|
-
|
|
141
129
|
Anything else a runtime happens to expose is outside the portable contract and
|
|
142
130
|
must not be used. QuickJS grants none of it. A loader-only Dynamic Worker denies
|
|
143
131
|
external egress and filesystem access and keeps its environment maps empty, but
|
|
@@ -157,49 +145,21 @@ runtime modules. Neither executor exposes `require`.
|
|
|
157
145
|
|
|
158
146
|
## Addressing
|
|
159
147
|
|
|
160
|
-
**A1.**
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
`[A-Za-z0-9_$]` become `_`, a leading digit gets `_` prefixed, and a reserved
|
|
172
|
-
word gets `_` appended (`my-service.get.thing` → `my_service.get_thing`). The
|
|
173
|
-
globals are lazy: no catalog is fetched until a program touches one. The
|
|
174
|
-
bounded deployment inventory in the `execute_code` description shows each
|
|
175
|
-
canonical connector id and labels the shortcut only when it differs; the
|
|
176
|
-
[discovery guide](./meta-tools.md#discovery-context) defines that bound. The sugar is frozen: every expansion invents a collision class `A1` already solves ([#223](https://github.com/zackbart/connecta/issues/223)).
|
|
177
|
-
|
|
178
|
-
**A3.** A shortcut that resolves to more than one tool fails closed with
|
|
179
|
-
`ambiguous_tool_alias`, naming the colliding tool names and pointing at
|
|
180
|
-
`connecta.call`. It never picks one. The canonical addresses of both tools
|
|
181
|
-
remain callable.
|
|
182
|
-
|
|
183
|
-
**A4.** A deployment whose connector ids collide with each other after
|
|
184
|
-
sanitization, or that sanitize onto a name the sandbox reserves, fails *every*
|
|
185
|
-
`execute_code` request with an error naming the offending ids. Failing loudly on
|
|
186
|
-
the deployment's mistake beats silently answering from whichever connector
|
|
187
|
-
sorted first.
|
|
188
|
-
|
|
189
|
-
**A5 (verdict: shortcut namespaces are kept, and frozen).** They cost nothing to
|
|
190
|
-
keep, a working ergonomic surface should not be removed mid-arc, and the
|
|
191
|
-
exploration's cold-start sample used them naturally. Frozen means no typed method
|
|
192
|
-
lists, no per-tool closures, no generated `.d.ts`, no second sanitization rule —
|
|
193
|
-
every expansion invents a collision class the addressing in `A1` already solves.
|
|
194
|
-
The default has since flipped without revisiting them
|
|
195
|
-
([#224](https://github.com/zackbart/connecta/issues/224)), so evidence rather
|
|
196
|
-
than a gate would take them away: if programs reach for `connecta.call` anyway,
|
|
197
|
-
or shortcut ambiguity shows up in failures, they lose.
|
|
148
|
+
**A1.** A tool has one canonical address, `<connectorId>.<toolName>`, exactly
|
|
149
|
+
as discovery returns it. Call it with `connecta.call(address, args)`. Punctuation
|
|
150
|
+
is preserved; no JavaScript identifier conversion takes place.
|
|
151
|
+
|
|
152
|
+
**A2.** Connectors create no guest globals. Connector ids that resemble a
|
|
153
|
+
JavaScript builtin, or would collide after sanitization, remain usable through
|
|
154
|
+
their canonical addresses. The bounded connector inventory in the tool
|
|
155
|
+
description shows canonical ids with bounded configured titles when present.
|
|
156
|
+
|
|
157
|
+
Clauses A3–A5 belonged to shortcut dispatch and are retired. Clients and stored
|
|
158
|
+
programs should follow the [migration guide](./upgrading.md#0230-program-api-pruning).
|
|
198
159
|
|
|
199
160
|
## The surface
|
|
200
161
|
|
|
201
|
-
Four functions, all `async`,
|
|
202
|
-
(`P2`) that is callable but not contract. Nothing else works: reading any other
|
|
162
|
+
Four functions, all `async`: `search`, `describe`, `call`, and `emit`. Nothing else works: reading any other
|
|
203
163
|
property yields a function — the guest namespace is a Proxy, so `typeof
|
|
204
164
|
connecta.toString` is `"function"` — but *calling* it fails, because the host
|
|
205
165
|
resolves only own members of the provider's `fns`. A program must treat the four
|
|
@@ -220,9 +180,9 @@ const page = await connecta.search({
|
|
|
220
180
|
});
|
|
221
181
|
```
|
|
222
182
|
|
|
223
|
-
**S1.** Returns one flat page: `{ tools, total, offset, limit, hasMore }`, plus `nextOffset` when more remains and `matchMode: "partial"` when no tool matched every term. Top-level `search_tools` is different: it returns `{ connectors: [{ id, tools }], total, offset, limit, hasMore }`. Complete matches normally precede partial matches, but a partial candidate whose complete normalized tool name occurs in the normalized raw query competes by score; conversational cleanup applies only to scoring terms. Other candidates covering at least two terms fill the page after every complete match; when no complete match exists, the existing any-term fallback remains. Each entry in `tools` carries `address`, `name`, and — when requested — `description`, `inputSchema`, `outputSchema`, `annotations`, and the connector's `guide`. An output shape learned under `S9` also carries `outputSchemaSource: "observed"`; provider declarations carry no source marker. Tool rows expose neither lexical scores nor per-result coverage. An empty or whitespace-only query browses. Non-empty input with no ASCII lexical terms returns no tools and bounded no-match analysis; mixed input searches with its ASCII terms. Compact shapes omit property prose, put required fields first, and cap each shape at 1,024 UTF-8 bytes. Each enum node gets 256 of those bytes. About three near-cap enum nodes can therefore coexist while leaving the final quarter for surrounding syntax; the unchanged global fallback still applies above 1,024 bytes. A capped enum preserves whole values before `unknown` and an exact omitted-value count, while an empty enum renders as `never`. Either cap carries `inputSchemaTruncated` or `outputSchemaTruncated`; a shape-wide cap remains structurally valid with `unknown` types plus `/* truncated */`. Small enums remain complete. Use `connecta.describe` (or JSON search) for omitted exact constraints.
|
|
183
|
+
**S1.** Returns one flat page: `{ tools, total, offset, limit, hasMore }`, plus `nextOffset` when more remains and `matchMode: "partial"` when no tool matched every term. Top-level `search_tools` is different: it returns `{ connectors: [{ id, tools }], total, offset, limit, hasMore }`. Complete matches normally precede partial matches, but a partial candidate whose complete normalized tool name occurs in the normalized raw query competes by score; conversational cleanup applies only to scoring terms. Other candidates covering at least two terms fill the page after every complete match; when no complete match exists, the existing any-term fallback remains. Each entry in `tools` carries `address`, `name`, the configured `connectorTitle` when present (normalized whitespace, at most 120 UTF-8 bytes), and — when requested — `description`, `inputSchema`, `outputSchema`, `annotations`, and the connector's `guide`. An output shape learned under `S9` also carries `outputSchemaSource: "observed"`; provider declarations carry no source marker. Tool rows expose neither lexical scores nor per-result coverage. An empty or whitespace-only query browses. Non-empty input with no ASCII lexical terms returns no tools and bounded no-match analysis; mixed input searches with its ASCII terms. Compact shapes omit property prose, put required fields first, and cap each shape at 1,024 UTF-8 bytes. Each enum node gets 256 of those bytes. About three near-cap enum nodes can therefore coexist while leaving the final quarter for surrounding syntax; the unchanged global fallback still applies above 1,024 bytes. A capped enum preserves whole values before `unknown` and an exact omitted-value count, while an empty enum renders as `never`. Either cap carries `inputSchemaTruncated` or `outputSchemaTruncated`; a shape-wide cap remains structurally valid with `unknown` types plus `/* truncated */`. Small enums remain complete. Use `connecta.describe` (or JSON search) for omitted exact constraints.
|
|
224
184
|
|
|
225
|
-
**S1a.** `connector` loads only the named catalog; omit it only when the integration is ambiguous, because an unscoped search fans out across every configured connector. `safety: "readOnly"` returns exactly the tools available through `connecta.call
|
|
185
|
+
**S1a.** `connector` loads only the named catalog; omit it only when the integration is ambiguous, because an unscoped search fans out across every configured connector. `safety: "readOnly"` returns exactly the tools available through `connecta.call`; `"approvalRequired"` returns the complementary fail-closed class, including false, missing, and contradictory annotations. Omitted or `"all"` preserves the complete catalog. These filters grant no authority and change no admission decision.
|
|
226
186
|
|
|
227
187
|
**S2.** A requested object schema carries `inputKeys`, `requiredInputKeys`, and `outputKeys`: the same names the rendered schema shows, ready to check before building arguments. Match inputs, truncation, safety, and outputs, not lexical
|
|
228
188
|
rank; search distinct operations separately and use `outputKeys`, not guessed roots. A non-object schema — a union, an array, an
|
|
@@ -276,30 +236,33 @@ when present, otherwise text content JSON-parsed when it parses and the raw text
|
|
|
276
236
|
when it does not; a downstream result flagged `isError` throws. Omitted `args`
|
|
277
237
|
is treated as `{}`.
|
|
278
238
|
|
|
279
|
-
**S6.** Every call
|
|
239
|
+
**S6.** Every call goes through the same catalog,
|
|
280
240
|
fail-closed read-only predicate, admission, credential containment, timeout
|
|
281
241
|
classification, health accounting, and activity recording as an ordinary
|
|
282
242
|
meta-tool call. The sandbox is an additional containment layer, not a second
|
|
283
243
|
implementation of the boundary, and nothing a program does widens what it can
|
|
284
244
|
reach.
|
|
285
245
|
|
|
286
|
-
###
|
|
246
|
+
### Parallel calls
|
|
247
|
+
|
|
248
|
+
**S7.** Use `Promise.all` for independent calls when any failure should fail the
|
|
249
|
+
program, or `Promise.allSettled` to retain every outcome in input order. Both
|
|
250
|
+
use the same per-call admission, host-call budget, deadlines, and activity path
|
|
251
|
+
as sequential calls. There is no separate batch size or result contract.
|
|
287
252
|
|
|
288
253
|
```js
|
|
289
|
-
const outcomes = await
|
|
290
|
-
|
|
291
|
-
|
|
254
|
+
const outcomes = await Promise.allSettled([
|
|
255
|
+
connecta.call("ci.get_run", { runId: 42 }),
|
|
256
|
+
connecta.call("ci.list_jobs", { runId: 42 }),
|
|
292
257
|
]);
|
|
258
|
+
return outcomes.map((outcome) => outcome.status === "fulfilled"
|
|
259
|
+
? { ok: true, data: outcome.value }
|
|
260
|
+
: { ok: false, code: outcome.reason.code, message: outcome.reason.message });
|
|
293
261
|
```
|
|
294
262
|
|
|
295
|
-
**
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
`errorDetails` is the typed object described in [Errors](#errors) — the same two
|
|
299
|
-
field names the host's internal batch path uses. One failing call never rejects
|
|
300
|
-
the batch, and more than ten calls throws.
|
|
301
|
-
|
|
302
|
-
**S8.** Batch and thrown failures share one vocabulary (`E1`): an entry's `errorDetails.code` and `retryable` equal the fields on the error the same call would throw. Use batch for independent concurrency, not to recover lost type.
|
|
263
|
+
**S8.** A rejected promise retains the caught error's `code`, `retryable`, and
|
|
264
|
+
`details`. Project those fields before returning; an Error object itself is
|
|
265
|
+
not a JSON result contract.
|
|
303
266
|
|
|
304
267
|
**S9.** A successful explicitly read-only call whose provider declared no `outputSchema` passively learns one from the unwrapped result. The observation retains field names and broad JSON types only: no arguments, scalar values, raw results, code, credentials, or errors. Property names may be user-authored. Objects stay open, every field stays optional, and search or describe labels the shape `outputSchemaSource: "observed"` so a model cannot mistake runtime evidence for a provider contract. Later observations merge fields and types in a process-local 256-entry LRU; a provider declaration always wins. Inference stops at depth 6, 128 schema nodes, 48 properties per object, 32 inspected array items, and 128 UTF-8 bytes per property name; `__proto__`, `constructor`, and `prototype` names are discarded. A tool definition over 64 KiB or an observed schema over 16 KiB is ignored. An entry expires after 24 hours and carries the exact serialized tool definition, so a changed catalog entry, process restart, or Worker isolate eviction starts cold. A failed call or failed result-processing step learns nothing, and any observation failure is discarded without changing a successful call. No discovery read, timer, refresh, background job, or storage adapter executes or persists work for this cache: the result-sampling refusal in [#282](https://github.com/zackbart/connecta/issues/282) stands.
|
|
305
268
|
|
|
@@ -314,17 +277,16 @@ clauses are [Emitted output](#emitted-output) (`M1`–`M10`).
|
|
|
314
277
|
|
|
315
278
|
## Errors
|
|
316
279
|
|
|
317
|
-
**E1.** There are
|
|
280
|
+
**E1.** There are three error channels. Connecta failures are typed whether caught or uncaught.
|
|
318
281
|
|
|
319
282
|
| Channel | Shape | Typed? |
|
|
320
283
|
| --- | --- | --- |
|
|
321
284
|
| A caught Connecta host failure | `Error` with `message`, `code`, `retryable`, and `details` | yes |
|
|
322
|
-
| `connecta.batch` outcome | `{ ok: false, error, errorDetails }` | yes |
|
|
323
285
|
| An uncaught **tool or discovery** failure, as the model sees it | `{ error: { code, message, retryable, … } }` with `isError` | yes |
|
|
324
286
|
| Program or execution failure (`E5`, `E6`, a bridge bound in `L6`) | error text | no |
|
|
325
287
|
|
|
326
288
|
Both executor bridges reduce a rejected host call to `new Error(message)`. Connecta restores the typed failure in a trusted prelude with a per-execution authenticated frame (`X11`), without turning the rejection into a returned value.
|
|
327
|
-
`message` remains the human text. `code` and `retryable` are the stable branch fields; `details` is the complete host classification. This covers `call`,
|
|
289
|
+
`message` remains the human text. `code` and `retryable` are the stable branch fields; `details` is the complete host classification. This covers `call`, `search`, `describe`, `emit`, and the host-call budget.
|
|
328
290
|
Program-authored errors stay untyped, and code must never parse error prose.
|
|
329
291
|
|
|
330
292
|
**E2.** The taxonomy: `retryable` is what connecta reports, `Y3` what a program may do.
|
|
@@ -333,7 +295,6 @@ Program-authored errors stay untyped, and code must never parse error prose.
|
|
|
333
295
|
| --- | --- | --- |
|
|
334
296
|
| `unknown_address` | no connector owns the address | false |
|
|
335
297
|
| `unknown_tool` | the connector has no such tool | false |
|
|
336
|
-
| `ambiguous_tool_alias` | a shortcut matches two tools (`A3`) | false |
|
|
337
298
|
| `destructive_tool_requires_approval` | the tool is not explicitly read-only | false |
|
|
338
299
|
| `auth_required` | the credential is missing, expired, or rejected | false |
|
|
339
300
|
| `invalid_args` | arguments or discovery bounds were rejected | false |
|
|
@@ -344,7 +305,6 @@ Program-authored errors stay untyped, and code must never parse error prose.
|
|
|
344
305
|
| `timeout` | the per-call 15-second deadline expired | true |
|
|
345
306
|
| `cancelled` | the run ended while this call was in flight (`E5`) | false |
|
|
346
307
|
| `connector_call_failed` | anything else the connector threw | per message |
|
|
347
|
-
| `batch_call_failed` | a `connecta.batch` entry connecta could not even attempt | per message |
|
|
348
308
|
| `catalog_lookup_failed` | the connector's catalog could not be loaded | per cause |
|
|
349
309
|
| `result_processing_failed` | the result could not be prepared | per message |
|
|
350
310
|
| `result_too_large` | a discovery response exceeded its byte bound | false |
|
|
@@ -370,8 +330,7 @@ guest: admission rejection (`executor_overloaded`, retryable, with
|
|
|
370
330
|
reported to the model as an error result. One seam: a host call still in flight
|
|
371
331
|
when the run is cancelled fails with `cancelled`, catchable on the way out but
|
|
372
332
|
never worth acting on (`Y3`). When shutdown tears down a program that had
|
|
373
|
-
already started, accepted blocks
|
|
374
|
-
and `U3`; a failure before execution started carries no discard fields.
|
|
333
|
+
already started, accepted blocks are reported as discarded under `M4`; a failure before execution started carries no discard fields.
|
|
375
334
|
|
|
376
335
|
**E6.** An error the program raises itself — a `TypeError`, a call to a
|
|
377
336
|
`connecta` member that is not a provider function (including an inherited one
|
|
@@ -382,7 +341,7 @@ exactly first, by containment second — so a program that *wraps* a failure's
|
|
|
382
341
|
message in its own text still reports the underlying typed failure. Keeping the
|
|
383
342
|
type beats keeping the prose.
|
|
384
343
|
|
|
385
|
-
**E7.** `retryable` for `unknown_address`, `unknown_tool`,
|
|
344
|
+
**E7.** `retryable` for `unknown_address`, `unknown_tool`, and `destructive_tool_requires_approval` is pinned false, never inferred from an address containing `503`, `429`, or `temporar`. The first two carry `nextAction: { function: "connecta.search", arguments: { query, connector?, includeSchemas: "compact" } }` — the same scoped discovery the top-level record names, keyed to the surface the caller actually has. A program cannot call `search_tools`, so it is never told to. The message, the derived `query`, and a failed describe entry's `address` clamp caller-authored text to 512 UTF-8 bytes with an `…` marker. Those values land in the text content and `structuredContent`, so an invented 50 KB address would otherwise produce a refusal orders of magnitude past the deployment's result cap. A clipped address still identifies the mistake by its position; a short one — the common case — is exact and untagged.
|
|
386
345
|
|
|
387
346
|
**E8.** A remote MCP tool whose advertised schema rejects the call fails before provider dispatch with `invalid_args`, carrying bounded, value-free `{ path, code, expected }` findings and scoped search recovery keyed `function: "connecta.search"` like every other in-program miss. A declared property reports the schema keyword that failed, never the validator's duplicate `additionalProperties` branch; a truly undeclared property still reports `additionalProperties`. Unsupported schemas pass through; unrecognized provider prose remains `connector_call_failed`.
|
|
388
347
|
|
|
@@ -428,7 +387,7 @@ on data nobody asked for.
|
|
|
428
387
|
|
|
429
388
|
**R6.** Nothing else is added to a normal program result. Passing `diagnostics: true` adds one request-local, payload-free `diagnostics` block; a program that emitted adds `emitted: N` and its blocks (`M2`). Omitted, `false`, and emit-free are byte-for-byte the ordinary response path. Diagnostics exist so catalog, connector, and executor costs are distinguishable without persisting payloads or charging normal responses ([#247](https://github.com/zackbart/connecta/issues/247)).
|
|
430
389
|
|
|
431
|
-
**R7.** Timing separates admission, provider setup, total executor wall time, catalog work, and connector work. Catalog and connector values are cumulative, so parallel work can exceed executor wall time. Each used operation kind (`search`, `describe`, `call
|
|
390
|
+
**R7.** Timing separates admission, provider setup, total executor wall time, catalog work, and connector work. Catalog and connector values are cumulative, so parallel work can exceed executor wall time. Each used operation kind (`search`, `describe`, `call`) gets one aggregate with count, failures, duration, returned serialized bytes, and catalog/connector time.
|
|
432
391
|
|
|
433
392
|
**R8.** Diagnostics contain measurements and fixed operation names only: no addresses, arguments, results, code, credentials, logs, or raw errors. Result sizes are numbers, never previews. The collector exists only for the opted-in request; it is not activity, a session, or a stream.
|
|
434
393
|
|
|
@@ -490,125 +449,13 @@ response, and `emit` resolving means "accepted," never "delivered."
|
|
|
490
449
|
aggregate — count and serialized bytes, numbers only (`R8`), present only
|
|
491
450
|
when something was emitted.
|
|
492
451
|
|
|
493
|
-
## Rendered output
|
|
494
|
-
|
|
495
|
-
`connecta.emit` gave programs pixels; it did not give them a *view*. This is the
|
|
496
|
-
one the human looks at directly while the model keeps its cheap textual summary:
|
|
497
|
-
one MCP Apps view per successful run, assembled where composition already
|
|
498
|
-
happens. Programs supply HTML content and nothing else — the only `ui://` URI in
|
|
499
|
-
the system is connecta's build-time shell, so nothing a client could dereference
|
|
500
|
-
is derived from anything a program said. The argument, the refused shapes, and
|
|
501
|
-
the security posture live in the [design record](https://github.com/zackbart/connecta/blob/main/records/mcp-ui-design.md)
|
|
502
|
-
([#266](https://github.com/zackbart/connecta/issues/266),
|
|
503
|
-
[#277](https://github.com/zackbart/connecta/issues/277)); this section is the
|
|
504
|
-
contract, and it wins where the two disagree.
|
|
505
|
-
|
|
506
|
-
**U1.** `connecta.ui(html)` accepts exactly one non-empty HTML string. There is
|
|
507
|
-
no options parameter, read manifest, or sugar form. Every other shape throws
|
|
508
|
-
catchably and accepts nothing.
|
|
509
|
-
|
|
510
|
-
**U2.** At most one payload per run. A second call throws catchably, naming the
|
|
511
|
-
constraint; the first accepted payload stands. One tool result renders one view,
|
|
512
|
-
and last-wins would silently discard a payload the program deliberately
|
|
513
|
-
supplied.
|
|
514
|
-
|
|
515
|
-
**U3.** Delivered on success only, and out of model context: the tool result
|
|
516
|
-
gains `_meta["connecta/ui"] = { html }` and the JSON envelope gains `ui: true`,
|
|
517
|
-
so the model learns a view rendered without seeing its bytes. `structuredContent`
|
|
518
|
-
stays the envelope alone. The single-label `connecta/ui` prefix is deliberate —
|
|
519
|
-
connecta has no domain to reverse, and fabricating one to satisfy MCP's
|
|
520
|
-
reverse-DNS SHOULD would be a worse answer than the shape the key format's MUST
|
|
521
|
-
already permits. A program that never calls `connecta.ui` produces the
|
|
522
|
-
byte-for-byte ordinary response (`R6`). A failed program delivers nothing and
|
|
523
|
-
reports `uiDiscarded: true` *only* when a payload had been accepted — a field on
|
|
524
|
-
the structured envelope, a trailing line on the plain-text paths — coexisting
|
|
525
|
-
with `emittedDiscarded: N` when one failure discards both.
|
|
526
|
-
|
|
527
|
-
**U4.** The payload spends the aggregate emit byte budget
|
|
528
|
-
(`ConnectaConfig.execute.maxEmittedBytes`), measured at the call as the
|
|
529
|
-
serialized bytes of `{ html }` — `M5`'s measurement. Over budget throws
|
|
530
|
-
catchably, naming the budget and the room remaining, with nothing partially
|
|
531
|
-
accepted. It spends no block count (`maxEmittedBlocks`: it is not a block) and no
|
|
532
|
-
host-call budget (`L4`). One transport bound covers everything rich a program
|
|
533
|
-
delivers.
|
|
534
|
-
|
|
535
|
-
**U5.** One static shell: a connecta-authored HTML5 document at
|
|
536
|
-
`ui://connecta/program-ui/v3`, mimeType `text/html;profile=mcp-app`, declared on
|
|
537
|
-
`execute_code` via `_meta.ui.resourceUri` together with an explicit
|
|
538
|
-
`_meta.ui.visibility: ["model"]`. The other six tools declare the same
|
|
539
|
-
model-only visibility without a resource URI. Omission defaults to model and
|
|
540
|
-
app visibility, which would let a display-only view call them. A
|
|
541
|
-
`resources/read` handler answers exactly that URI and fails on any other;
|
|
542
|
-
`resources/list` is served and returns an empty list.
|
|
543
|
-
The version segment bumps whenever the shell's bytes change, because hosts cache
|
|
544
|
-
templates by URI.
|
|
545
|
-
|
|
546
|
-
**U6.** The shell renders the payload in a nested iframe
|
|
547
|
-
(`srcdoc`, `sandbox="allow-scripts"`, no `allow-same-origin`) and declares no CSP
|
|
548
|
-
domains, so the host applies its restrictive default and the `about:srcdoc` frame
|
|
549
|
-
inherits `default-src 'none'; connect-src 'none'`. The shell offers no direct
|
|
550
|
-
network, tool calls, discovery, conversation messages, writes, or links. It
|
|
551
|
-
participates in the Apps lifecycle — initialize, tool-result, size-changed,
|
|
552
|
-
resource-teardown — and forwards no channel whatsoever from the inner frame to
|
|
553
|
-
the host. That isolation makes
|
|
554
|
-
program views fixed-height by construction: with no bridge there is no
|
|
555
|
-
content-height signal, the shell reports only its own box, and content taller
|
|
556
|
-
than that scrolls inside the inner frame rather than growing the view.
|
|
557
|
-
|
|
558
|
-
**U7.** Structural executor parity, per `M8`: `connecta.ui` is a provider
|
|
559
|
-
function, `ExecuteResult` and the `Executor` interface are unchanged, and both
|
|
560
|
-
executors get it through the bridge they already have.
|
|
561
|
-
|
|
562
|
-
**U8.** Request-local and unstreamed, per `M9`. The payload exists only in the
|
|
563
|
-
finished response, and `connecta.ui` resolving means "accepted," never
|
|
564
|
-
"rendered."
|
|
565
|
-
|
|
566
|
-
**U9.** `diagnostics: true` adds a distinct `ui` aggregate — the payload's byte
|
|
567
|
-
size, a number and nothing else (`R8`), present only when a payload was accepted.
|
|
568
|
-
UI bytes are not folded into `emitted`: that aggregate pairs a block count with
|
|
569
|
-
the bytes those blocks cost, and bytes without a block would desync the pair.
|
|
570
|
-
|
|
571
|
-
**U10.** `_meta.ui.resourceUri` is declared unconditionally. A host without the
|
|
572
|
-
extension ignores unknown `_meta` and sees the ordinary envelope, which *is* the
|
|
573
|
-
text fallback the Apps spec mandates; `connecta.ui` never fails because a client
|
|
574
|
-
cannot render. A stateless aggregator cannot reliably know, and connecta is not a
|
|
575
|
-
nanny.
|
|
576
|
-
|
|
577
|
-
**U11.** connecta declares `io.modelcontextprotocol/ui` in its server capability
|
|
578
|
-
declaration, and that is the one extension it advertises. The Apps extension must
|
|
579
|
-
be explicitly negotiated and a conforming client acts on one only when both sides
|
|
580
|
-
declare it, so without this declaration no host reads `_meta.ui.resourceUri`, no
|
|
581
|
-
host fetches the shell, and the whole design is inert. Reading the *client's*
|
|
582
|
-
declaration in order to register tool metadata conditionally stays refused
|
|
583
|
-
(`U10`), knowingly against a spec SHOULD.
|
|
584
|
-
|
|
585
|
-
**U12.** The return value, not the view, is what the model reads. `U3` puts the
|
|
586
|
-
view out of model context, so a program that renders one also returns the summary
|
|
587
|
-
the model should reason over, built from the same variables the initial view renders — a
|
|
588
|
-
view the return value does not mirror is a view nobody in the loop can check.
|
|
589
|
-
This binds program authors and nothing else: connecta never reads the HTML, diffs
|
|
590
|
-
it against the return, or enforces the correspondence. A heuristic there would be
|
|
591
|
-
the same mistake as automatic host-side projection, refused in `ethos.md`
|
|
592
|
-
([#282](https://github.com/zackbart/connecta/issues/282)).
|
|
593
|
-
|
|
594
|
-
**U13.** The always-loaded MCP instructions locate `connecta.ui(html)` before an
|
|
595
|
-
agent chooses a route: it exists only inside `execute_code`, never in connector
|
|
596
|
-
search, and carries `U12`'s mirrored-return duty. The detailed call, budget,
|
|
597
|
-
and repair rules live in the on-demand `usage` skill. The location
|
|
598
|
-
distinction rides `initialize`, under a 1,000-character ceiling for the complete
|
|
599
|
-
instructions string. This promotes existing contract, not capability: the
|
|
600
|
-
seven-tool surface, guest API, catalog, Apps delivery, and runtime do not change
|
|
601
|
-
([#286](https://github.com/zackbart/connecta/issues/286),
|
|
602
|
-
[#418](https://github.com/zackbart/connecta/issues/418)).
|
|
603
|
-
|
|
604
452
|
## Retry semantics
|
|
605
453
|
|
|
606
|
-
**Y1.** Connecta
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
loop, and its budget is visible to it (`L4`).
|
|
454
|
+
**Y1.** Connecta makes one downstream attempt per admitted call, both inside a
|
|
455
|
+
program and through either direct-call tool. It never waits and retries on the
|
|
456
|
+
caller's behalf. An admission refusal may prevent even that attempt.
|
|
610
457
|
|
|
611
|
-
**Y2.** A program may retry a caught failure whose `retryable` is true, or a
|
|
458
|
+
**Y2.** A program may retry a caught failure whose `retryable` is true, or a rejected promise whose `reason.retryable` is true (`S8`). Every attempt spends host-call budget, so an unchecked loop converts a transient failure into `budget_exceeded`.
|
|
612
459
|
|
|
613
460
|
**Y3.** What must never be retried automatically:
|
|
614
461
|
|
|
@@ -620,10 +467,9 @@ loop, and its budget is visible to it (`L4`).
|
|
|
620
467
|
re-issue with `retryAfterMs` in hand.
|
|
621
468
|
- a cancelled or timed-out *execution*: it is already over (`L1`).
|
|
622
469
|
|
|
623
|
-
**Y4.**
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
verbatim as `err.details.retryAfterMs` or `errorDetails.retryAfterMs`.
|
|
470
|
+
**Y4.** A provider's `retryAfterMs` is returned unchanged. The caller decides
|
|
471
|
+
whether and when to reissue. A later call receives its own deadline and
|
|
472
|
+
admission decision.
|
|
627
473
|
|
|
628
474
|
## Cancellation and limits
|
|
629
475
|
|
|
@@ -646,7 +492,6 @@ because connecta enforces them above the sandbox:
|
|
|
646
492
|
| Bound | Value |
|
|
647
493
|
| --- | --- |
|
|
648
494
|
| Host calls per execution | 20 |
|
|
649
|
-
| Calls per `connecta.batch` | 10 |
|
|
650
495
|
| Deadline per host call | 15 s |
|
|
651
496
|
| Discovery page | ≤ 100 tools, ≤ 256,000 serialized bytes |
|
|
652
497
|
| `describe` addresses | ≤ 100 |
|
|
@@ -669,7 +514,7 @@ code safe to run at all.
|
|
|
669
514
|
bounded — QuickJS caps both at 256 KiB (`X10`) — and exceeding either fails that
|
|
670
515
|
call, not the execution, so a program can catch it and ask for less. The failure
|
|
671
516
|
is executor-owned untyped text, not a Connecta host failure (`E1`). An over-bound *result* names the address the program
|
|
672
|
-
called,
|
|
517
|
+
called, rather than only the generic bridge function; an over-bound
|
|
673
518
|
*argument* payload is refused before it is parsed, so it names no address at
|
|
674
519
|
all — parsing it to write a better message would spend exactly the work the bound
|
|
675
520
|
exists to refuse.
|
|
@@ -680,8 +525,7 @@ carrying `retryAfterMs`; cancellation and shutdown are terminal. Admission happe
|
|
|
680
525
|
*before* any catalog or provider is built, so a queued request holds no state.
|
|
681
526
|
|
|
682
527
|
**L8.** Bounds are deployment configuration, not program inputs: a program cannot
|
|
683
|
-
raise one by asking. `execute_code`'s description states the host-call budget
|
|
684
|
-
batch maximum, and the per-call deadline — the ones a program must plan around
|
|
528
|
+
raise one by asking. `execute_code`'s description states the host-call budget and the per-call deadline — the ones a program must plan around
|
|
685
529
|
before it runs. The result and log caps live here and in the truncation notice
|
|
686
530
|
itself (`R2`, `R5`).
|
|
687
531
|
|
|
@@ -689,7 +533,7 @@ itself (`R2`, `R5`).
|
|
|
689
533
|
|
|
690
534
|
**V1.** One payload-free activity event per attempted call, with
|
|
691
535
|
`source: "execute_code"` — every dispatched call plus every local refusal: a
|
|
692
|
-
read-only refusal, an unknown tool, an
|
|
536
|
+
read-only refusal, an unknown tool, an unloadable
|
|
693
537
|
catalog, a missing credential, an exhausted host-call budget, an address no
|
|
694
538
|
connector owns. Ten tools called is ten events, as legible as ten `call_tool`
|
|
695
539
|
calls — which makes moving work into the sandbox an optimization, not a blindfold.
|
|
@@ -705,7 +549,7 @@ return is refused paging by design rather than truncated into friction. There is
|
|
|
705
549
|
nowhere to put arguments, results, program source, or
|
|
706
550
|
raw error text; a caught failure is still recorded. `address` is
|
|
707
551
|
canonical (`A1`) where a tool resolved, otherwise the name the program used —
|
|
708
|
-
|
|
552
|
+
the honest record of what was attempted.
|
|
709
553
|
|
|
710
554
|
**V3.** A call whose connector does not exist is recorded at the address as
|
|
711
555
|
written, *provided* it split into the two fields activity keeps — one with no
|
|
@@ -785,37 +629,10 @@ The human message is unchanged; a mismatched frame is ordinary untyped prose.
|
|
|
785
629
|
|
|
786
630
|
## Changes from earlier code mode
|
|
787
631
|
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
- **`connecta.batch` failures gained `errorDetails`** (`S7`). They carried only a
|
|
794
|
-
message, which left a program unable to tell a policy refusal from a transient
|
|
795
|
-
failure. Additive, and it reuses the host's internal batch field names, so a
|
|
796
|
-
program and the host describe a failed call the same way.
|
|
797
|
-
- **A policy refusal can no longer look retryable** (`E7`). Pinned in code rather
|
|
798
|
-
than read out of message text, so a connector named `svc-503` stops flipping a
|
|
799
|
-
permanent refusal to `retryable: true`. This reaches the call tools too.
|
|
800
|
-
- **An uncaught discovery-bound failure is typed** (`S3`): `invalid_args` or
|
|
801
|
-
`result_too_large` rather than prose, the same envelope a failed call gets.
|
|
802
|
-
- **A bridge-bound failure names the address** (`L6`), not the internal
|
|
803
|
-
dispatcher every shortcut namespace shares.
|
|
804
|
-
- **An oversized result is truncated once** (`R2`). The envelope is sized so its
|
|
805
|
-
*serialized* form fits the cap; the QuickJS path previously truncated in the
|
|
806
|
-
child and again in the parent, reporting the inner envelope's length as
|
|
807
|
-
`totalChars`. Previews are shorter now; `totalChars` is the real size.
|
|
808
|
-
|
|
809
|
-
The middle three were places where the contract described behavior the code did
|
|
810
|
-
not quite have. The code moved, because the described behavior is the one worth
|
|
811
|
-
having.
|
|
812
|
-
|
|
813
|
-
Two surfaces were added since, both additive by construction and each with its
|
|
814
|
-
byte-for-byte no-call promise pinned by test:
|
|
815
|
-
[emitted output](#emitted-output) (`M1`–`M10`,
|
|
816
|
-
[#270](https://github.com/zackbart/connecta/issues/270)) and
|
|
817
|
-
[rendered output](#rendered-output) (`U1`–`U12`,
|
|
818
|
-
[#277](https://github.com/zackbart/connecta/issues/277)).
|
|
632
|
+
MCP Apps rendering, connector shortcut globals, and `connecta.batch` are
|
|
633
|
+
removed. Direct calls also lose automatic retries. The seven top-level tools,
|
|
634
|
+
read-only boundary, JSON projection, and emitted media remain. See the
|
|
635
|
+
[migration guide](./upgrading.md#0230-program-api-pruning).
|
|
819
636
|
|
|
820
637
|
## Verification
|
|
821
638
|
|
|
@@ -835,19 +652,16 @@ the upstream `Executor` shape assignable.
|
|
|
835
652
|
| `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.test.ts` (exact absent globals and blocked imports), `test/quickjs-child-stderr.test.ts` (empty child-process environment), `test/deployment-shapes.test.ts` (loader-only Worker construction) |
|
|
836
653
|
| `P3`, `X9` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` |
|
|
837
654
|
| `P4` | `test/guest-api-contract.test.ts` (no cross-run leakage), `test/execute.test.ts` (one catalog load per connector per execution) |
|
|
838
|
-
| `A1`, `A2` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (
|
|
839
|
-
| `A3` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (colliding alias) |
|
|
840
|
-
| `A4` | `test/execute.test.ts` (namespace collisions, reserved namespace) |
|
|
841
|
-
| `A5` | verdict; `A1`–`A3` are its enforcement |
|
|
655
|
+
| `A1`, `A2` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (canonical addressing), `test/server.test.ts` (bounded live connector inventory) |
|
|
842
656
|
| `S1`, `S2` | `test/guest-api-contract.test.ts` (flat page, connector guides, schema keys, and the unfiltered browse that replaces `list_connectors`), `test/execute.test.ts` (guide pagination/partial/no-match behavior and `$ref`/`allOf`), `test/meta-tools.test.ts` (mixed complete/partial ranking and stable pagination) |
|
|
843
657
|
| `S3` | `test/guest-api-contract.test.ts` (typed uncaught bound), `test/execute.test.ts` (count limits, fan-out bound) |
|
|
844
658
|
| `S4` | both guest-contract executors (ordered mixed describe results with unknown-address, unknown-tool suggestion, and catalog-failure details), `test/meta-tools.test.ts` (top-level routing, no-suggestion, catalog-failure, and hostile-input bounds) |
|
|
845
659
|
| `S5` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (`unwrapMcpResult`) |
|
|
846
660
|
| `S6` | `test/execute.test.ts` (fail-closed annotations, activity parity) |
|
|
847
|
-
| `S7` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (
|
|
848
|
-
| `S8`, `E1`, `X11` | both guest-contract executors (caught call,
|
|
661
|
+
| `S7` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (parallel calls and shared admission) |
|
|
662
|
+
| `S8`, `E1`, `X11` | both guest-contract executors (caught call, discovery, utility, budget, removed-function, and forgery cases; typed promise rejections) |
|
|
849
663
|
| `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, and failure isolation) |
|
|
850
|
-
| `E2`, `E8` | `test/guest-api-contract.test.ts` (code → `retryable`, caught,
|
|
664
|
+
| `E2`, `E8` | `test/guest-api-contract.test.ts` (code → `retryable`, caught, parallel, and uncaught validation recovery), `test/meta-tools.test.ts` (direct, destructive, provider fallback), `test/validate.test.ts` (bounded payload-free findings), `test/errors.test.ts` |
|
|
851
665
|
| `E3` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (`auth_required`) |
|
|
852
666
|
| `E4` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (destructive) |
|
|
853
667
|
| `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.test.ts` (mid-run shutdown) |
|
|
@@ -860,7 +674,7 @@ the upstream `Executor` shape assignable.
|
|
|
860
674
|
| `R6`–`R8` | `test/guest-api-contract.test.ts` (normal result keys), `test/execute.test.ts` (opt-in operation aggregates, failure paths, payload exclusion) |
|
|
861
675
|
| `Y1` | `test/guest-api-contract.test.ts` (one attempt per call) |
|
|
862
676
|
| `Y2`, `Y3` | `test/guest-api-contract.test.ts` (retryable flags by code) |
|
|
863
|
-
| `Y4` | `test/meta-tools.test.ts` (
|
|
677
|
+
| `Y4` | `test/meta-tools-call.test.ts`, `test/call-admission.test.ts` (one attempt, retry hints, caller reissue) |
|
|
864
678
|
| `L1`, `L2` | `test/guest-api-contract.test.ts` (in-flight call fails `cancelled`), `test/execute.test.ts` (cancels outstanding host calls) |
|
|
865
679
|
| `L3`, `X1` | `test/guest-api-contract.test.ts` (short-deadline executors) |
|
|
866
680
|
| `L4`, `L8` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (budgets) |
|
|
@@ -875,15 +689,6 @@ the upstream `Executor` shape assignable.
|
|
|
875
689
|
| `M6`, `M9` | verdicts; `M1`'s strict typing and `M2`'s collect-then-deliver are their enforcement |
|
|
876
690
|
| `M8` | two arms passing one case table, `test/codemode-compat.test.ts` |
|
|
877
691
|
| `M10` | `test/execute-emit.test.ts` (aggregate present, numbers only, absent when nothing emitted) |
|
|
878
|
-
| `U1`, `U2` | `test/guest-api-contract.test.ts` (invalid and repeated calls throw catchably, first payload stands), `test/execute-ui.test.ts` (every rejected shape) |
|
|
879
|
-
| `U3` | `test/guest-api-contract.test.ts` (`_meta` payload and `ui: true`, identical on both executors), `test/execute-ui.test.ts` (`structuredContent`, byte-for-byte no-call path, discard structured and plain, coexistence with `emittedDiscarded`), `test/quickjs-executor.test.ts` (mid-run shutdown) |
|
|
880
|
-
| `U4` | `test/execute-ui.test.ts` (one shared byte aggregate crossed in either order; block count and host-call budget untouched) |
|
|
881
|
-
| `U5`, `U10`, `U11` | `test/server.test.ts` (the shell URI, mimeType, and body; every other URI fails; empty listing; exact model-only `_meta.ui` on all seven tools; exactly one declared extension) |
|
|
882
|
-
| `U6` | `test/execute-ui.test.ts` (valid HTML5, `srcdoc` and sandbox attributes, no `allow-same-origin`, no path from the inner frame to the host) |
|
|
883
|
-
| `U7`, `U8` | two arms passing one case table, `test/codemode-compat.test.ts` |
|
|
884
|
-
| `U9` | `test/execute-ui.test.ts` (a `ui` byte aggregate distinct from `emitted`, absent when nothing was accepted) |
|
|
885
|
-
| `U12` | `test/server.test.ts` (the `connecta.ui` bullet carries the return-value clause); a duty on program authors, so the description is the only place it can be enforced |
|
|
886
|
-
| `U13` | `test/code-first-surface.test.ts`, `test/server.test.ts` (served `initialize.instructions` locate UI inside `execute_code`, exclude it from connector search, state the mirrored-return duty, and stay within the complete 1,000-character budget; the usage skill carries detailed call rules) |
|
|
887
692
|
| `X3` | `test/quickjs-executor.test.ts` (cancels a running child) |
|
|
888
693
|
| `X4` | `test/guest-api-contract.test.ts` (string logs only) |
|
|
889
694
|
| `X6` | `test/quickjs-executor.test.ts` (never-settling await) |
|
|
@@ -21,6 +21,10 @@ produce ordinary `Connector` instances and pass through the same catalog,
|
|
|
21
21
|
read-only admission, credentials, storage, invocation, result-size, and
|
|
22
22
|
activity paths.
|
|
23
23
|
|
|
24
|
+
Custom HTTP routes belong to the deployment fetch handler. Connectors expose
|
|
25
|
+
tools and the documented OAuth hooks; a removed `handleRequest` declaration
|
|
26
|
+
refuses construction.
|
|
27
|
+
|
|
24
28
|
Connector instances are deployment configuration. They are not registered or
|
|
25
29
|
reconfigured at runtime. Request-local clients, transports, abort signals, and
|
|
26
30
|
catalogs must be released with the request that created them.
|
|
@@ -292,9 +296,8 @@ Connecta deliberately sits between protocol generations
|
|
|
292
296
|
five-minute fingerprinted catalog cache; that remains gated in
|
|
293
297
|
[#206](https://github.com/zackbart/connecta/issues/206).
|
|
294
298
|
- **Multi-round-trip results:** a downstream `input_required` result becomes a
|
|
295
|
-
non-retryable `input_required_unsupported` failure. `call_tool
|
|
296
|
-
`execute_code` host bridge
|
|
297
|
-
structured code. Relaying the
|
|
299
|
+
non-retryable `input_required_unsupported` failure. `call_tool` and the
|
|
300
|
+
`execute_code` host bridge preserve the structured code. Relaying the
|
|
298
301
|
opaque `requestState` is architecturally possible but gated until real hosts
|
|
299
302
|
and downstreams adopt it.
|
|
300
303
|
|
|
@@ -320,8 +323,7 @@ freshness. The operator page reports whether the last agent read in this runtime
|
|
|
320
323
|
was fresh or stale; this payload-free timestamp is not persisted. No timer or
|
|
321
324
|
idle warmup originates downstream traffic.
|
|
322
325
|
|
|
323
|
-
Tool calls must use the shared invocation path. That keeps direct calls,
|
|
324
|
-
children, and code-mode host calls aligned on safety, retries, admission,
|
|
326
|
+
Tool calls must use the shared invocation path. That keeps direct calls and code-mode host calls aligned on safety, retry hints, admission,
|
|
325
327
|
timeouts, validation, result guards, and typed failures.
|
|
326
328
|
|
|
327
329
|
That path also learns an observed output schema after a successful explicitly
|
|
@@ -365,7 +367,7 @@ A remote MCP connector that authenticates with a static key has two ways to
|
|
|
365
367
|
receive one. `{ type: "headers", headers }` bakes the literal value into the
|
|
366
368
|
deployment file, which suits a secret the runtime already holds.
|
|
367
369
|
`{ type: "credential" }` declares the slot instead and lets an operator paste
|
|
368
|
-
the key at
|
|
370
|
+
the key at the connection UI at `/`, where it is encrypted at rest and rotatable without
|
|
369
371
|
a redeploy:
|
|
370
372
|
|
|
371
373
|
```ts
|
package/documentation/linear.md
CHANGED
|
@@ -88,7 +88,7 @@ configuration. A personal API key carries the acting user's full workspace
|
|
|
88
88
|
permissions, so pair it with `access: "read-only"` unless the deployment
|
|
89
89
|
genuinely writes.
|
|
90
90
|
|
|
91
|
-
The same key can arrive from
|
|
91
|
+
The same key can arrive from the connection UI at `/` instead, which is what a deployment
|
|
92
92
|
with no secret store — or an operator who rotates keys without a redeploy —
|
|
93
93
|
wants:
|
|
94
94
|
|