@zackbart/connecta 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +12 -5
- package/CHANGELOG.md +289 -0
- package/README.md +6 -1
- package/dist/catalog-service.d.ts +4 -0
- package/dist/catalog-service.js +49 -5
- package/dist/catalog.d.ts +11 -0
- package/dist/catalog.js +134 -12
- package/dist/errors.d.ts +28 -2
- package/dist/errors.js +1 -0
- package/dist/execute.d.ts +5 -0
- package/dist/execute.js +229 -161
- package/dist/invocation.js +3 -1
- package/dist/meta-tools.d.ts +4 -0
- package/dist/meta-tools.js +46 -14
- package/dist/operator-ui/generated.d.ts +1 -1
- package/dist/operator-ui/generated.js +1 -1
- package/dist/operator-ui/model.d.ts +3 -1
- package/dist/providers/cloudflare.js +13 -25
- package/dist/providers/mixpanel.d.ts +3 -5
- package/dist/providers/mixpanel.js +73 -5
- package/dist/providers/stripe.d.ts +2 -2
- package/dist/providers/stripe.js +13 -11
- package/dist/registry.d.ts +32 -9
- package/dist/registry.js +217 -33
- package/dist/routes/mcp.js +6 -0
- package/dist/skills.d.ts +4 -0
- package/dist/skills.js +157 -18
- package/dist/types.d.ts +14 -2
- package/dist/ui.js +4 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/architecture.md +7 -4
- package/documentation/cloudflare.md +40 -8
- package/documentation/code-first-exploration.md +2 -2
- package/documentation/code-mode.md +45 -53
- package/documentation/connector-guides.md +24 -19
- package/documentation/connectors.md +13 -1
- package/documentation/meta-tools.md +33 -18
- package/documentation/mixpanel.md +20 -0
- package/documentation/notion.md +7 -2
- package/documentation/operations.md +74 -29
- package/documentation/operator-ui.md +12 -2
- package/documentation/provider-audit.md +4 -4
- package/documentation/provider-conventions.md +68 -19
- package/documentation/stripe.md +45 -14
- package/documentation/upgrading.md +478 -0
- package/ethos.md +4 -4
- package/examples/worker/README.md +13 -6
- package/package.json +7 -2
- package/templates/node/AGENTS.md +5 -0
- package/templates/node/package.json +1 -1
|
@@ -53,8 +53,8 @@ createConnecta({
|
|
|
53
53
|
});
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
Dynamic Workers require the Workers Paid plan. The
|
|
57
|
-
|
|
56
|
+
Dynamic Workers require the Workers Paid plan. The supported constructor passes only `loader`; `bindings`, `modules`, or
|
|
57
|
+
`globalOutbound` grant ambient guest authority and violate `P2`. The [Worker example](../examples/worker/README.md#code-mode) carries the full setup.
|
|
58
58
|
|
|
59
59
|
## What an executor must implement
|
|
60
60
|
|
|
@@ -104,8 +104,8 @@ Connecta passes exactly one provider, named `connecta`. An executor must:
|
|
|
104
104
|
uncaught tool failure keeps its type (`E1`).
|
|
105
105
|
6. **Capture `console.log`, `console.warn`, and `console.error`** into `logs` in
|
|
106
106
|
call order (`R5`), bounding what it retains.
|
|
107
|
-
7. **Bound the guest**: wall clock, memory, stack, and CPU (`L3`, `L5`)
|
|
108
|
-
|
|
107
|
+
7. **Bound the guest**: wall clock, memory, stack, and CPU (`L3`, `L5`). Keep
|
|
108
|
+
ambient capabilities within the documented and tested `P2`/`X5` boundary.
|
|
109
109
|
8. **Grant no ambient authority of its own.** Never back this with `eval` or
|
|
110
110
|
`node:vm`: the sandbox is a containment layer on top of connecta's boundary,
|
|
111
111
|
not a replacement for it, and every capability arrives through `fns`.
|
|
@@ -138,10 +138,10 @@ reinterpreted, so do not rely on it.
|
|
|
138
138
|
It is host plumbing, callable but not contract: it takes a connector id and an
|
|
139
139
|
unsanitized-or-sanitized tool name and can change shape without notice.
|
|
140
140
|
|
|
141
|
-
Anything else a runtime happens to expose is outside the contract and
|
|
142
|
-
be used
|
|
143
|
-
filesystem access
|
|
144
|
-
|
|
141
|
+
Anything else a runtime happens to expose is outside the portable contract and
|
|
142
|
+
must not be used. QuickJS grants none of it. A loader-only Dynamic Worker denies
|
|
143
|
+
external egress and filesystem access and keeps its environment maps empty, but
|
|
144
|
+
it exposes the globals and runtime builtins described in `X5`.
|
|
145
145
|
|
|
146
146
|
**P3.** Values cross the host bridge as JSON. Arguments must be
|
|
147
147
|
JSON-serializable and results arrive as plain JSON values. A value outside JSON —
|
|
@@ -154,8 +154,9 @@ scratch storage carried to the next program, and no request-bound object outlive
|
|
|
154
154
|
the request that created it. Within one execution, host calls share one
|
|
155
155
|
downstream request scope.
|
|
156
156
|
|
|
157
|
-
**P5.** Plain JavaScript only. TypeScript syntax is a syntax error
|
|
158
|
-
|
|
157
|
+
**P5.** Plain JavaScript only. TypeScript syntax is a syntax error. Portable code
|
|
158
|
+
does not import: QuickJS blocks imports, while Dynamic Workers expose the `X5`
|
|
159
|
+
runtime modules. Neither executor exposes `require`.
|
|
159
160
|
|
|
160
161
|
## Addressing
|
|
161
162
|
|
|
@@ -240,8 +241,8 @@ can set `includeSchemaKeys: false` to buy the bytes back.
|
|
|
240
241
|
**S3.** Discovery is bounded and the bounds throw rather than silently shrink: a
|
|
241
242
|
`limit` outside 1–100 is `invalid_args`, and a page whose serialized form
|
|
242
243
|
exceeds 256,000 bytes is `result_too_large`, each with a hint naming the ways to
|
|
243
|
-
ask for less.
|
|
244
|
-
(`E1`)
|
|
244
|
+
ask for less. The thrown error carries the stable `code`, `retryable`, and
|
|
245
|
+
`details` fields (`E1`).
|
|
245
246
|
|
|
246
247
|
### connecta.describe
|
|
247
248
|
|
|
@@ -295,9 +296,7 @@ order. A success is `{ address, ok: true, data }`. A failure is
|
|
|
295
296
|
field names the host's internal batch path uses. One failing call never rejects
|
|
296
297
|
the batch, and more than ten calls throws.
|
|
297
298
|
|
|
298
|
-
**S8.** `
|
|
299
|
-
error crosses the bridge as a bare message (`E1`), a batch of one is the supported
|
|
300
|
-
way for a program to *decide* something about a failure rather than report it.
|
|
299
|
+
**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.
|
|
301
300
|
|
|
302
301
|
### connecta.emit
|
|
303
302
|
|
|
@@ -310,27 +309,20 @@ clauses are [Emitted output](#emitted-output) (`M1`–`M10`).
|
|
|
310
309
|
|
|
311
310
|
## Errors
|
|
312
311
|
|
|
313
|
-
**E1.** There are four error channels
|
|
312
|
+
**E1.** There are four error channels. Connecta failures are typed whether caught or uncaught.
|
|
314
313
|
|
|
315
314
|
| Channel | Shape | Typed? |
|
|
316
315
|
| --- | --- | --- |
|
|
317
|
-
| A
|
|
316
|
+
| A caught Connecta host failure | `Error` with `message`, `code`, `retryable`, and `details` | yes |
|
|
318
317
|
| `connecta.batch` outcome | `{ ok: false, error, errorDetails }` | yes |
|
|
319
318
|
| An uncaught **tool or discovery** failure, as the model sees it | `{ error: { code, message, retryable, … } }` with `isError` | yes |
|
|
320
|
-
|
|
|
319
|
+
| Program or execution failure (`E5`, `E6`, a bridge bound in `L6`) | error text | no |
|
|
321
320
|
|
|
322
|
-
|
|
323
|
-
host call
|
|
324
|
-
|
|
325
|
-
classify, use `errorDetails`; to hand a failure to the model with its type
|
|
326
|
-
intact, let it escape uncaught — connecta re-attaches the typed details on the
|
|
327
|
-
way out. The model-facing version of this lives in `execute_code`'s description,
|
|
328
|
-
not in the always-loaded usage skill, which `test/meta-tools.test.ts` caps at
|
|
329
|
-
2,500 bytes — a budget the guide already spends nearly all of, so new text there
|
|
330
|
-
displaces old rather than adding to what every request pays for.
|
|
321
|
+
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.
|
|
322
|
+
`message` remains the human text. `code` and `retryable` are the stable branch fields; `details` is the complete host classification. This covers `call`, connector shortcuts, `search`, `describe`, `emit`, `ui`, rejected batch input, and the host-call budget.
|
|
323
|
+
Program-authored errors stay untyped, and code must never parse error prose.
|
|
331
324
|
|
|
332
|
-
**E2.** The taxonomy
|
|
333
|
-
program may do about it.
|
|
325
|
+
**E2.** The taxonomy: `retryable` is what connecta reports, `Y3` what a program may do.
|
|
334
326
|
|
|
335
327
|
| Code | Raised when | `retryable` |
|
|
336
328
|
| --- | --- | --- |
|
|
@@ -340,15 +332,18 @@ program may do about it.
|
|
|
340
332
|
| `destructive_tool_requires_approval` | the tool is not explicitly read-only | false |
|
|
341
333
|
| `auth_required` | the credential is missing, expired, or rejected | false |
|
|
342
334
|
| `invalid_args` | arguments or discovery bounds were rejected | false |
|
|
335
|
+
| `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 ([H11](./provider-conventions.md#h11--errors-are-mapped-to-what-the-caller-does-next)) | false |
|
|
343
336
|
| `input_required_unsupported` | a downstream asked for mid-call input | false |
|
|
344
337
|
| `rate_limited` | the downstream reported a rate limit | true |
|
|
345
338
|
| `unavailable` | the downstream is down or unreachable | true |
|
|
346
339
|
| `timeout` | the per-call 15-second deadline expired | true |
|
|
347
340
|
| `cancelled` | the run ended while this call was in flight (`E5`) | false |
|
|
348
|
-
| `connector_call_failed` | anything else the connector threw
|
|
341
|
+
| `connector_call_failed` | anything else the connector threw | per message |
|
|
349
342
|
| `batch_call_failed` | a `connecta.batch` entry connecta could not even attempt | per message |
|
|
350
343
|
| `catalog_lookup_failed` | the connector's catalog could not be loaded | per cause |
|
|
351
344
|
| `result_processing_failed` | the result could not be prepared | per message |
|
|
345
|
+
| `result_too_large` | a discovery response exceeded its byte bound | false |
|
|
346
|
+
| `budget_exceeded` | the run exhausted a host-call or emitted-output budget | false |
|
|
352
347
|
|
|
353
348
|
**E3.** `auth_required` carries the same recovery envelope as `call_tool`:
|
|
354
349
|
`connector`, `operation`, `recovery` (`oauth`, `operator_config`, or
|
|
@@ -608,25 +603,22 @@ annotation-gated `maxRetries`; code mode fixes it at zero, so one
|
|
|
608
603
|
`connecta.call` is exactly one downstream attempt. The program is the retry
|
|
609
604
|
loop, and its budget is visible to it (`L4`).
|
|
610
605
|
|
|
611
|
-
**Y2.** A program may retry a failure whose `errorDetails.retryable` is true,
|
|
612
|
-
learned through `connecta.batch` (`S8`). Every attempt spends host-call budget,
|
|
613
|
-
so a retry loop that ignores the budget converts a transient failure into a
|
|
614
|
-
budget failure.
|
|
606
|
+
**Y2.** A program may retry a caught failure whose `retryable` is true, or a batch failure whose `errorDetails.retryable` is true (`S8`). Every attempt spends host-call budget, so an unchecked loop converts a transient failure into `budget_exceeded`.
|
|
615
607
|
|
|
616
608
|
**Y3.** What must never be retried automatically:
|
|
617
609
|
|
|
618
610
|
- anything with `retryable: false` — a policy refusal, a missing credential, a
|
|
619
611
|
bad address, or malformed arguments will fail identically forever;
|
|
620
|
-
- `rate_limited`, immediately.
|
|
621
|
-
wait
|
|
622
|
-
|
|
623
|
-
`retryAfterMs` in hand.
|
|
612
|
+
- `rate_limited`, immediately. A portable program has no timer, and a
|
|
613
|
+
Dynamic-Worker-only wait would spend the run's wall-clock budget on code that
|
|
614
|
+
fails on QuickJS. Return the failure and let the model, which can wait,
|
|
615
|
+
re-issue with `retryAfterMs` in hand.
|
|
624
616
|
- a cancelled or timed-out *execution*: it is already over (`L1`).
|
|
625
617
|
|
|
626
618
|
**Y4.** Connecta's own retry machinery beneath the meta-tools honours a
|
|
627
619
|
connector-reported `Retry-After` exactly or not at all, and declines windows
|
|
628
620
|
longer than 10 seconds rather than shortening them. A program sees the window
|
|
629
|
-
verbatim as `errorDetails.retryAfterMs`.
|
|
621
|
+
verbatim as `err.details.retryAfterMs` or `errorDetails.retryAfterMs`.
|
|
630
622
|
|
|
631
623
|
## Cancellation and limits
|
|
632
624
|
|
|
@@ -656,10 +648,7 @@ because connecta enforces them above the sandbox:
|
|
|
656
648
|
| Result | 24,000 serialized characters |
|
|
657
649
|
| Logs presented to the model | 4,000 characters |
|
|
658
650
|
|
|
659
|
-
Exhausting the host-call budget fails that call
|
|
660
|
-
`connector_call_failed` (`E2`) and a message naming the budget — no connector was
|
|
661
|
-
reached, so nothing more specific is true. Retrying it is pointless: the budget
|
|
662
|
-
does not refill inside one execution.
|
|
651
|
+
Exhausting the host-call budget fails that call with non-retryable `budget_exceeded` (`E2`) and a message naming the budget. No connector is reached, and the budget does not refill inside one execution.
|
|
663
652
|
|
|
664
653
|
**L5.** The guest is memory-, stack-, and CPU-bounded, and a program that
|
|
665
654
|
exhausts a bound ends the run with an error instead of degrading the host. The
|
|
@@ -672,7 +661,7 @@ code safe to run at all.
|
|
|
672
661
|
**L6.** A host call's serialized arguments and its serialized result are each
|
|
673
662
|
bounded — QuickJS caps both at 256 KiB (`X10`) — and exceeding either fails that
|
|
674
663
|
call, not the execution, so a program can catch it and ask for less. The failure
|
|
675
|
-
is untyped text (`E1`). An over-bound *result* names the address the program
|
|
664
|
+
is executor-owned untyped text, not a Connecta host failure (`E1`). An over-bound *result* names the address the program
|
|
676
665
|
called, not the internal dispatcher behind the shortcut namespaces; an over-bound
|
|
677
666
|
*argument* payload is refused before it is parsed, so it names no address at
|
|
678
667
|
all — parsing it to write a better message would spend exactly the work the bound
|
|
@@ -750,11 +739,9 @@ Worker renders arguments with `String()` (so an object logs as
|
|
|
750
739
|
latter two. Only the three captured everywhere are contract (`R5`); rendering is
|
|
751
740
|
not.
|
|
752
741
|
|
|
753
|
-
**X5. Leftover
|
|
754
|
-
`
|
|
755
|
-
`
|
|
756
|
-
`process.env` is empty, and timers work. `P2` is the contract — a program that
|
|
757
|
-
uses `setTimeout` is writing Workers-only code, and it will fail on Node.
|
|
742
|
+
**X5. Leftover authority.** QuickJS blocks imports and has no `fetch`, `process`, timers, `crypto`, or `WebSocket`. A Dynamic Worker has those globals plus a non-contract set of runtime builtins through `import()` and `process.getBuiltinModule()`, including `node:path`, `node:crypto`, `node:net`, `node:tls`, `node:dns`, `node:module`, and `cloudflare:workers`. The upstream set can drift; this list is not an allowlist.
|
|
743
|
+
The supported Worker construction is exactly `new DynamicWorkerExecutor({ loader })`. Do not pass `bindings`, `modules`, or `globalOutbound`: each can grant ambient configuration, code, or egress. Under it, `process.env`, lexical `this.env`, and `cloudflare:workers.env` are empty; `node:fs`, `node:http`, and `node:https` are unavailable through either access route; external `fetch`, `WebSocket`, `node:net`, and `node:tls` fail with workerd's outbound-denial error; DNS lookup ends unresolved; and `fetch("data:...")` resolves locally.
|
|
744
|
+
`P2` is the portable contract. Programs use none of this runtime-only authority, including timers and `crypto`, because the same code fails on QuickJS. The `execute_code` description and served `usage` skill say so before an agent writes code.
|
|
758
745
|
|
|
759
746
|
**X6. Stall detection.** QuickJS notices a program awaiting something that can
|
|
760
747
|
never settle and fails fast; the Dynamic Worker waits for its deadline. The fast
|
|
@@ -786,11 +773,16 @@ a `process.send` with a hard ceiling. A program that returns a quarter-megabyte
|
|
|
786
773
|
from one tool call therefore fails on Node and may succeed on Workers — reduce
|
|
787
774
|
inside the program either way (`R1`).
|
|
788
775
|
|
|
776
|
+
**X11. Typed host rejection.** Both executors rebuild Connecta's authenticated host-failure frame as a thrown guest `Error` (`E1`). The per-run secret stays in the trusted prelude closure, and the prelude locks `globalThis.Error`, so guest code and connector prose cannot forge the host transport frame.
|
|
777
|
+
The human message is unchanged; a mismatched frame is ordinary untyped prose.
|
|
778
|
+
|
|
789
779
|
## Changes from earlier code mode
|
|
790
780
|
|
|
791
|
-
|
|
781
|
+
Six behaviors changed with this contract, matching the changelog's Unreleased
|
|
792
782
|
entry. Programs that ran before still run.
|
|
793
783
|
|
|
784
|
+
- **Caught Connecta failures expose their classification** (`E1`, `X11`). Their human message and thrown semantics stay unchanged; `code`, `retryable`, and `details` are additive.
|
|
785
|
+
|
|
794
786
|
- **`connecta.batch` failures gained `errorDetails`** (`S7`). They carried only a
|
|
795
787
|
message, which left a program unable to tell a policy refusal from a transient
|
|
796
788
|
failure. Additive, and it reuses the host's internal batch field names, so a
|
|
@@ -833,7 +825,7 @@ the upstream `Executor` shape assignable.
|
|
|
833
825
|
| Clauses | Test |
|
|
834
826
|
| --- | --- |
|
|
835
827
|
| `P1`, `P5` | `test/guest-api-contract.test.ts` (TypeScript syntax), `test/quickjs-executor.test.ts` (`normalizeCode`) |
|
|
836
|
-
| `P2`, `X5` | `test/guest-api-contract.test.ts` (
|
|
828
|
+
| `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/deployment-shapes.test.ts` (loader-only Worker construction) |
|
|
837
829
|
| `P3`, `X9` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` |
|
|
838
830
|
| `P4` | `test/guest-api-contract.test.ts` (no cross-run leakage), `test/execute.test.ts` (one catalog load per connector per execution) |
|
|
839
831
|
| `A1`, `A2` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (sanitizing) |
|
|
@@ -846,8 +838,8 @@ the upstream `Executor` shape assignable.
|
|
|
846
838
|
| `S5` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (`unwrapMcpResult`) |
|
|
847
839
|
| `S6` | `test/execute.test.ts` (fail-closed annotations, activity parity) |
|
|
848
840
|
| `S7` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (batch cap) |
|
|
849
|
-
| `S8`, `E1` |
|
|
850
|
-
| `E2`, `E8` | `test/guest-api-contract.test.ts` (code → `retryable`, batch and uncaught validation recovery), `test/meta-tools.test.ts` (direct, destructive, batch, provider fallback), `test/validate.test.ts` (bounded payload-free findings), `test/errors.test.ts` |
|
|
841
|
+
| `S8`, `E1`, `X11` | both guest-contract executors (caught call, namespace, discovery, utility, batch-validation, budget, and forgery cases; typed batch equivalence) |
|
|
842
|
+
| `E2`, `E8` | `test/guest-api-contract.test.ts` (code → `retryable`, caught, batch, and uncaught validation recovery), `test/meta-tools.test.ts` (direct, destructive, batch, provider fallback), `test/validate.test.ts` (bounded payload-free findings), `test/errors.test.ts` |
|
|
851
843
|
| `E3` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (`auth_required`) |
|
|
852
844
|
| `E4` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (destructive) |
|
|
853
845
|
| `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) |
|
|
@@ -40,13 +40,17 @@ hand-written connector. It is deployment-owned configuration like everything
|
|
|
40
40
|
else here: an edit and a redeploy, never a runtime registration.
|
|
41
41
|
|
|
42
42
|
`content` is returned byte for byte by `skills({ name: "connector:<id>" })`.
|
|
43
|
-
`summary` is normalized and
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
43
|
+
`summary` is normalized and must fit 120 characters. A longer configured value
|
|
44
|
+
refuses construction instead of silently changing the operator's words. Omit
|
|
45
|
+
it and connecta derives the same bounded summary the skills listing uses: the
|
|
46
|
+
first meaningful body paragraph, joined across Markdown's physical line wraps,
|
|
47
|
+
with frontmatter, fences, rules, comments, and tables skipped. When the
|
|
48
|
+
paragraph does not fit, connecta keeps a useful complete sentence when one
|
|
49
|
+
fits, then prefers a clause or word boundary before adding an ellipsis. A heading is used
|
|
50
|
+
only when the guide has no body, and the connector's description is the last
|
|
51
|
+
resort. A derived summary is usually worse than a written one — it was written
|
|
52
|
+
to open a document, not to answer "is this guide relevant to what I am about
|
|
53
|
+
to do".
|
|
50
54
|
|
|
51
55
|
`connector:<id>` is the only address for a guide, and built-in skill names are
|
|
52
56
|
bare identifiers, so a guide can never shadow or be shadowed by `usage`: a
|
|
@@ -160,15 +164,16 @@ schemas will never carry, because it cannot change them
|
|
|
160
164
|
## Tests that enforce this
|
|
161
165
|
|
|
162
166
|
`test/meta-tools.test.ts` owns the guide behavior end to end: the skills
|
|
163
|
-
listing carrying one entry per guided connector, summaries
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
167
|
+
listing carrying one entry per guided connector, summaries joining a
|
|
168
|
+
hard-wrapped opening paragraph and shortening at readable boundaries,
|
|
169
|
+
configured summaries refusing construction past the bound, heading and
|
|
170
|
+
description fallbacks, markup skipping, whitespace-only guides treated as no
|
|
171
|
+
guide, content returned verbatim including surrounding padding, identical
|
|
172
|
+
content in two deployments staying isolated, every miss erroring rather than
|
|
173
|
+
falling back to the generic guide with an identically labelled skills list on
|
|
174
|
+
each branch, the `guide` pointer in search output, and `guideRequired`
|
|
175
|
+
appearing for connector-required conventions, approval-bound tools, and
|
|
176
|
+
truncated schemas — and being absent from a search that asked for no schemas.
|
|
177
|
+
`test/server.test.ts` owns the conditional half: it compares a guide-free
|
|
178
|
+
deployment's four tool descriptions against a guided one's, and asserts the
|
|
179
|
+
`usage` skill is byte-identical between them.
|
|
@@ -252,6 +252,17 @@ the cursor ends, preserve schemas and annotations, and never cache or serve a
|
|
|
252
252
|
partial walk. The fixed TTL is paired with a schema fingerprint so a changed
|
|
253
253
|
catalog invalidates persisted results even within the time window.
|
|
254
254
|
|
|
255
|
+
Agent reads use a complete entry inside `staleCatalogSeconds` immediately and
|
|
256
|
+
defer the refresh that read already demanded. Every live refresh is
|
|
257
|
+
single-flight per connector in one runtime. A blocking operator or direct read
|
|
258
|
+
joins an agent-owned refresh and awaits it; an agent stale read joins an
|
|
259
|
+
operator-owned refresh without awaiting it. The first refresh owns the context
|
|
260
|
+
and deadline. A deferred first refresh owns a fresh scope and signal, then
|
|
261
|
+
closes that scope. Operator status and direct registry reads still await
|
|
262
|
+
freshness. The operator page reports whether the last agent read in this runtime
|
|
263
|
+
was fresh or stale; this payload-free timestamp is not persisted. No timer or
|
|
264
|
+
idle warmup originates downstream traffic.
|
|
265
|
+
|
|
255
266
|
Tool calls must use the shared invocation path. That keeps direct calls, batch
|
|
256
267
|
children, and code-mode host calls aligned on safety, retries, admission,
|
|
257
268
|
timeouts, validation, result guards, and typed failures.
|
|
@@ -259,7 +270,8 @@ timeouts, validation, result guards, and typed failures.
|
|
|
259
270
|
Connector usage guides are configuration too. `usageGuide` accepts the
|
|
260
271
|
historical markdown string or `{ content, summary?, required? }`; the latter
|
|
261
272
|
lets discovery explain what the guide covers without loading it. The summary
|
|
262
|
-
is
|
|
273
|
+
is a 120-character routing hint; a longer configured value refuses construction
|
|
274
|
+
instead of being silently shortened. Mark a guide `required` only when no complete
|
|
263
275
|
tool schema can describe correct use, such as a generic operation wrapper or a
|
|
264
276
|
mandatory cross-tool sequence. Mutations and truncated compact schemas already
|
|
265
277
|
produce automatic review requirements. Two deployments may reuse the same
|
|
@@ -89,14 +89,16 @@ Compact search is deliberately a routing view, not a second copy of connector
|
|
|
89
89
|
documentation. Tool purposes are capped at 160 characters, connector
|
|
90
90
|
descriptions and property prose are omitted, required input fields render
|
|
91
91
|
before optional ones, and each input or output shape is capped at 1,024 UTF-8
|
|
92
|
-
bytes. Within that unchanged total, each enum node
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
92
|
+
bytes. Within that unchanged total, each enum node and each constraint
|
|
93
|
+
annotation may spend at most 256 UTF-8 bytes. Numeric bounds, string length
|
|
94
|
+
bounds, patterns, and formats render beside their type. A constraint that does
|
|
95
|
+
not fit is dropped whole. If constraints push the full shape over 1,024 bytes,
|
|
96
|
+
search retries the shape without them. Compact describe keeps all declared
|
|
97
|
+
constraints. A large enum keeps the longest whole-value prefix that fits, then
|
|
98
|
+
adds `unknown` and a comment with the exact omitted-value count. An empty enum
|
|
99
|
+
renders as the valid `never` type. A capped object becomes a valid
|
|
100
|
+
required-first shape with `unknown` types; other shapes become
|
|
101
|
+
`unknown /* truncated */`. Any cap marks the match with
|
|
100
102
|
`inputSchemaTruncated` or `outputSchemaTruncated`; repeat the search with
|
|
101
103
|
`includeSchemas: "json"` or use the existing describe path when exact
|
|
102
104
|
constraints matter. Small enums and both exact paths remain complete.
|
|
@@ -107,12 +109,13 @@ A connector may attach a deployment-owned guide as markdown, preserving the
|
|
|
107
109
|
original `usageGuide: string` configuration, or as
|
|
108
110
|
`{ content, summary?, required? }`. The structured form does not register a
|
|
109
111
|
connector or create a shared runtime template. `content` remains the markdown
|
|
110
|
-
returned verbatim by `skills`; `summary` is normalized and
|
|
111
|
-
|
|
112
|
-
fallback used by the skills listing: the first meaningful body
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
112
|
+
returned verbatim by `skills`; `summary` is normalized and refuses construction
|
|
113
|
+
when it exceeds 120 characters. When it is absent, Connecta derives the same
|
|
114
|
+
bounded fallback used by the skills listing: the first meaningful body
|
|
115
|
+
paragraph, joined across physical Markdown line wraps and shortened at a
|
|
116
|
+
sentence, clause, or word boundary, with a heading used only when the guide has
|
|
117
|
+
no body. `required: true` is reserved for generic API wrappers and
|
|
118
|
+
cross-operation conventions a complete downstream schema cannot express.
|
|
116
119
|
|
|
117
120
|
Search and describe results keep the existing `guide: "connector:<id>"`
|
|
118
121
|
pointer and add `guideSummary`. A matching tool also carries
|
|
@@ -170,12 +173,18 @@ can shrink anything before it returns.
|
|
|
170
173
|
|
|
171
174
|
`fields` keeps its historical flat `{ "<path>": value }` result when every
|
|
172
175
|
requested dot-path resolves. Dot notation traverses objects; append `[]` to an
|
|
173
|
-
array field before continuing, as in `results[].id`.
|
|
176
|
+
array field before continuing, as in `results[].id`. Empty arrays resolve to
|
|
177
|
+
empty arrays. An exact downstream
|
|
174
178
|
`$connecta` field is always escaped under `data`. If any path misses—or that
|
|
175
179
|
reserved name is selected—the result carries matches under `data` and reserves `$connecta` for a
|
|
176
180
|
`type: "field_projection"` recovery record naming each `unmatchedFields`
|
|
177
|
-
entry.
|
|
178
|
-
|
|
181
|
+
entry. A path that resolves for only some array elements stays in `data` and
|
|
182
|
+
appears in `partialFields`; its unresolved positions serialize as `null`, while
|
|
183
|
+
the recovery record distinguishes them from genuine downstream nulls. A path
|
|
184
|
+
that misses every element appears in `unmatchedFields` and is omitted from
|
|
185
|
+
`data`. Both lists scale with requested paths, never with array length. When a
|
|
186
|
+
miss matches a declared array path except for `[]`, the record also carries the
|
|
187
|
+
traversal hint. The discriminator means downstream fields
|
|
179
188
|
named `data`, `projection`,
|
|
180
189
|
or `$connecta` remain ordinary values nested under `data`, never apparent
|
|
181
190
|
metadata. A declared output schema contributes a bounded `availableFields`
|
|
@@ -229,7 +238,13 @@ results explain that no single tool covered every term and recommend splitting
|
|
|
229
238
|
distinct intents. A true negative says that no matching capability is
|
|
230
239
|
configured and recommends refining, connector-scoping, or browsing; when a
|
|
231
240
|
connector catalog was unavailable, the response includes
|
|
232
|
-
`unavailableConnectorCount` instead of making that stronger claim. A
|
|
241
|
+
`unavailableConnectorCount` instead of making that stronger claim. A no-match
|
|
242
|
+
query whose terms name a configured connector's `id` or `title` never makes it
|
|
243
|
+
either: connector identity is not in the lexical index — indexing it would move
|
|
244
|
+
ranking for every query that already matches tools — so instead the guidance on
|
|
245
|
+
an unscoped miss names up to three such connectors by ID and sends the caller
|
|
246
|
+
to a scoped browse. Identity affects that one sentence and nothing else: no
|
|
247
|
+
ranking, no result, and no new field. A search
|
|
233
248
|
explicitly scoped to that unavailable connector also receives `catalogError` —
|
|
234
249
|
the bounded classified failure (`code`, `message`, `retryable`, and any
|
|
235
250
|
`retryAfterMs`) so the caller can tell a transient outage from one a deployment
|
|
@@ -50,6 +50,26 @@ password, not ordinary configuration. Mixpanel currently labels service-account
|
|
|
50
50
|
MCP authentication beta. Prefer OAuth unless the deployment is intentionally
|
|
51
51
|
headless.
|
|
52
52
|
|
|
53
|
+
## Conditional input contracts
|
|
54
|
+
|
|
55
|
+
Mixpanel's hosted descriptions enforce three cross-field conditions that its
|
|
56
|
+
input schemas do not encode. Connecta preserves those schemas unchanged under
|
|
57
|
+
[P1](./provider-conventions.md#p1--normalize-by-adding-never-by-rewriting), so
|
|
58
|
+
the maintained guide carries the missing call guidance:
|
|
59
|
+
|
|
60
|
+
- `Get-Business-Context` requires `project_id` or `organization_id`.
|
|
61
|
+
- `Get-Property-Values` requires `properties` or the deprecated `property`
|
|
62
|
+
alias. Event property values also require `event`.
|
|
63
|
+
- `List-Properties` accepts `names` or `query`, never both.
|
|
64
|
+
|
|
65
|
+
A read-only live audit on 2026-08-13 confirmed all three refusals against the
|
|
66
|
+
US hosted endpoint. They are reported upstream as
|
|
67
|
+
[`mixpanel/mixpanel-headless#202`](https://github.com/mixpanel/mixpanel-headless/issues/202).
|
|
68
|
+
The vetted catalog records the same audit's schema digests for all 63 tools,
|
|
69
|
+
so a later schema correction or regression appears by tool name in the
|
|
70
|
+
maintainer drift check. The guide can then shrink when the downstream schema
|
|
71
|
+
becomes complete; Connecta does not absorb the defect permanently.
|
|
72
|
+
|
|
53
73
|
The wrapper classifies the documented observational tools as reads and the
|
|
54
74
|
documented create, update, edit, merge, dismiss, duplicate, and delete tools as
|
|
55
75
|
writes. An unfamiliar tool the downstream leaves unannotated fails closed onto
|
package/documentation/notion.md
CHANGED
|
@@ -166,7 +166,7 @@ should do next, and two of Notion's are easy to mistranslate.
|
|
|
166
166
|
| 400 (`validation_error`, `invalid_json`, `invalid_request`, `missing_version`, …) | `invalid_args` | every documented 400 is a malformed request |
|
|
167
167
|
| 401 `unauthorized` | `auth_required` | the token is missing or invalid |
|
|
168
168
|
| 403 `restricted_resource` | `connector_call_failed`, non-retryable | **not** `auth_required` |
|
|
169
|
-
| 404 `object_not_found` | `connector_call_failed`, non-retryable | overloaded
|
|
169
|
+
| 404 `object_not_found` | `connector_call_failed`, non-retryable | overloaded — deliberately **not** `not_found`; see below |
|
|
170
170
|
| 409 `conflict_error` | `unavailable`, retryable | Notion says to retry |
|
|
171
171
|
| 429 `rate_limited` | `rate_limited` + `retryAfterMs` | `Retry-After` seconds → ms |
|
|
172
172
|
| 529 `service_overload` | `unavailable` + `retryAfterMs` | back off like a 429 |
|
|
@@ -184,7 +184,12 @@ whose message says an operator must change it in Notion.
|
|
|
184
184
|
object that does not exist and for one that exists but has not been shared with
|
|
185
185
|
the integration, and it will not say which. The message says both, because
|
|
186
186
|
treating it as deletion is exactly how an agent concludes a page is gone when
|
|
187
|
-
it was simply never shared.
|
|
187
|
+
it was simply never shared. This is why the row above does not use `not_found`,
|
|
188
|
+
which exists precisely to say "it is not there": the qualifier on that code
|
|
189
|
+
([H11](./provider-conventions.md#h11--errors-are-mapped-to-what-the-caller-does-next))
|
|
190
|
+
is that the provider must tell absence apart from a permission gap, and Notion
|
|
191
|
+
does not. A program that skipped this id as missing would be right about half
|
|
192
|
+
the time, which is the half that matters.
|
|
188
193
|
|
|
189
194
|
## Rate limiting
|
|
190
195
|
|