@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.
Files changed (332) hide show
  1. package/CHANGELOG.md +855 -5
  2. package/README.md +125 -116
  3. package/bin/connecta.mjs +121 -139
  4. package/bin/meta-tool-names.d.mts +2 -0
  5. package/bin/meta-tool-names.mjs +9 -0
  6. package/bin/version.mjs +3 -0
  7. package/dist/access-tokens.js +53 -63
  8. package/dist/activity-request.js +8 -0
  9. package/dist/activity.d.ts +76 -42
  10. package/dist/activity.js +110 -42
  11. package/dist/argument-redaction.js +230 -0
  12. package/dist/auth/clerk-sdk/client.d.ts +65 -0
  13. package/dist/auth/clerk-sdk/client.js +5 -0
  14. package/dist/auth/clerk-sdk/generated.js +1845 -0
  15. package/dist/auth/clerk-transport.js +19 -0
  16. package/dist/auth/clerk.d.ts +17 -7
  17. package/dist/auth/clerk.js +189 -107
  18. package/dist/auth/cloudflare-access.js +25 -26
  19. package/dist/auth/downstream-client-metadata.d.ts +29 -0
  20. package/dist/auth/downstream-client-metadata.js +133 -0
  21. package/dist/auth/downstream-oauth.js +1584 -1580
  22. package/dist/auth/downstream-revocation.js +106 -0
  23. package/dist/auth/oauth-token-response.js +231 -0
  24. package/dist/auth/oauth-v2-migration.js +116 -0
  25. package/dist/auth/static-oauth.js +93 -71
  26. package/dist/auth-elicitation.js +288 -0
  27. package/dist/authorization-handoff.js +111 -0
  28. package/dist/branding.d.ts +8 -16
  29. package/dist/branding.js +26 -59
  30. package/dist/byte-read-response.js +39 -0
  31. package/dist/call-admission.js +12 -16
  32. package/dist/catalog-cache.js +739 -0
  33. package/dist/catalog-drift.d.ts +50 -15
  34. package/dist/catalog-drift.js +365 -128
  35. package/dist/catalog-fingerprint.js +2 -4
  36. package/dist/catalog-freshness.js +13 -0
  37. package/dist/catalog-limits.js +2 -2
  38. package/dist/catalog-service.js +409 -225
  39. package/dist/catalog.js +43 -84
  40. package/dist/concurrency.js +3 -4
  41. package/dist/config-defaults.d.ts +39 -0
  42. package/dist/config-defaults.js +46 -0
  43. package/dist/config-schema.d.ts +181 -0
  44. package/dist/config-schema.js +435 -0
  45. package/dist/config-value-sources.js +102 -0
  46. package/dist/config.d.ts +633 -0
  47. package/dist/config.js +508 -0
  48. package/dist/connector-access.d.ts +1 -0
  49. package/dist/connector-access.js +13 -15
  50. package/dist/connector-caller.d.ts +8 -0
  51. package/dist/connector-caller.js +15 -6
  52. package/dist/connector-scope.js +1 -1
  53. package/dist/connectors/api-connector.d.ts +59 -7
  54. package/dist/connectors/api-connector.js +106 -19
  55. package/dist/connectors/api.js +4 -1
  56. package/dist/connectors/guarded-fetch.d.ts +144 -0
  57. package/dist/connectors/guarded-fetch.js +87 -38
  58. package/dist/connectors/negotiation-cache.js +46 -0
  59. package/dist/connectors/option-shapes.js +27 -0
  60. package/dist/connectors/remote-mcp.d.ts +30 -4
  61. package/dist/connectors/remote-mcp.js +1774 -320
  62. package/dist/connectors/resource-uri.js +335 -0
  63. package/dist/credential-contract.d.ts +10 -0
  64. package/dist/credential-rules.js +1 -3
  65. package/dist/credential-url.js +108 -0
  66. package/dist/credentials.d.ts +6 -1
  67. package/dist/credentials.js +27 -18
  68. package/dist/d1.d.ts +130 -0
  69. package/dist/d1.js +290 -0
  70. package/dist/describe-config.d.ts +165 -0
  71. package/dist/describe-config.js +315 -0
  72. package/dist/described.js +106 -0
  73. package/dist/downstream-input-context.js +128 -0
  74. package/dist/downstream-input.js +325 -0
  75. package/dist/errors.d.ts +132 -31
  76. package/dist/errors.js +175 -87
  77. package/dist/execute.js +798 -318
  78. package/dist/executor-admission.d.ts +1 -0
  79. package/dist/executor-admission.js +11 -15
  80. package/dist/executor-contract.d.ts +20 -0
  81. package/dist/executor-contract.js +48 -0
  82. package/dist/executor-result.js +30 -13
  83. package/dist/executors/quickjs-child.js +15 -9
  84. package/dist/executors/quickjs-protocol.js +5 -6
  85. package/dist/executors/quickjs-runtime.js +152 -59
  86. package/dist/executors/quickjs.js +49 -39
  87. package/dist/favicon.js +1 -2
  88. package/dist/fix-prompt.js +1 -3
  89. package/dist/guest-runtime.js +238 -0
  90. package/dist/guest-types.d.ts +218 -0
  91. package/dist/guest-types.js +1 -0
  92. package/dist/html-security.js +24 -0
  93. package/dist/identity.js +1 -3
  94. package/dist/inbound-credential.js +52 -0
  95. package/dist/index.d.ts +24 -256
  96. package/dist/index.js +65 -478
  97. package/dist/invocation-auth.js +69 -0
  98. package/dist/invocation.js +262 -79
  99. package/dist/json-schema.d.ts +1 -1
  100. package/dist/mcp-client-context.js +35 -0
  101. package/dist/mcp-result.js +11 -7
  102. package/dist/meta-output.js +61 -0
  103. package/dist/meta-tool-names.d.ts +2 -0
  104. package/dist/meta-tool-names.js +3 -0
  105. package/dist/meta-tools.js +419 -272
  106. package/dist/module-contracts.d.ts +8 -23
  107. package/dist/node.d.ts +0 -2
  108. package/dist/node.js +2 -2
  109. package/dist/oauth-callback-outcome.js +1 -3
  110. package/dist/oauth-handoff.js +194 -0
  111. package/dist/oauth-sealing.js +20 -0
  112. package/dist/operator-record.d.ts +137 -0
  113. package/dist/operator-record.js +420 -0
  114. package/dist/operator-ui/assets.js +31 -0
  115. package/dist/operator-ui/contract.d.ts +72 -0
  116. package/dist/operator-ui/contract.js +1 -0
  117. package/dist/operator-ui/fix-prompts.d.ts +18 -0
  118. package/dist/operator-ui/generated.js +5 -4
  119. package/dist/operator-ui/model.d.ts +12 -87
  120. package/dist/operator-ui/model.js +2 -9
  121. package/dist/operator-ui/setup-commands.js +1 -3
  122. package/dist/operator-ui/view.d.ts +323 -0
  123. package/dist/operator-ui/view.js +62 -189
  124. package/dist/page-styles.js +2 -3
  125. package/dist/program-result.js +5 -0
  126. package/dist/program-source.js +14 -2
  127. package/dist/{exempt-writes.js → program-writes.js} +60 -19
  128. package/dist/provider.d.ts +142 -0
  129. package/dist/provider.js +187 -0
  130. package/dist/providers/_shared/google/result-size.js +57 -0
  131. package/dist/providers/_shared/google/service-account.d.ts +58 -0
  132. package/dist/providers/_shared/google/service-account.js +500 -0
  133. package/dist/providers/_shared/google/workspace.d.ts +276 -0
  134. package/dist/providers/_shared/google/workspace.js +518 -0
  135. package/dist/providers/_shared/request-token.js +83 -0
  136. package/dist/providers/{basecamp.d.ts → basecamp/index.d.ts} +6 -28
  137. package/dist/providers/basecamp/index.js +997 -0
  138. package/dist/providers/basecamp/skill.generated.js +9 -0
  139. package/dist/providers/{breeze.d.ts → breeze/index.d.ts} +2 -2
  140. package/dist/providers/{breeze.js → breeze/index.js} +184 -140
  141. package/dist/providers/breeze/skill.generated.js +9 -0
  142. package/dist/providers/{ccb.d.ts → ccb/index.d.ts} +2 -2
  143. package/dist/providers/{ccb.js → ccb/index.js} +271 -116
  144. package/dist/providers/ccb/skill.generated.js +9 -0
  145. package/dist/providers/{cloudflare.d.ts → cloudflare/index.d.ts} +8 -7
  146. package/dist/providers/{cloudflare.js → cloudflare/index.js} +171 -738
  147. package/dist/providers/cloudflare/skill.generated.js +10 -0
  148. package/dist/providers/docs/index.d.ts +54 -0
  149. package/dist/providers/docs/index.js +1237 -0
  150. package/dist/providers/docs/skill.generated.js +9 -0
  151. package/dist/providers/drive/index.d.ts +53 -0
  152. package/dist/providers/drive/index.js +1523 -0
  153. package/dist/providers/drive/skill.generated.js +9 -0
  154. package/dist/providers/forms/index.d.ts +54 -0
  155. package/dist/providers/forms/index.js +1217 -0
  156. package/dist/providers/forms/skill.generated.js +11 -0
  157. package/dist/providers/github/auth.d.ts +32 -0
  158. package/dist/providers/github/auth.js +361 -0
  159. package/dist/providers/github/hosted.js +218 -0
  160. package/dist/providers/github/index.d.ts +13 -0
  161. package/dist/providers/github/index.js +140 -0
  162. package/dist/providers/github/key.js +100 -0
  163. package/dist/providers/github/rest.js +321 -0
  164. package/dist/providers/github/scope.d.ts +29 -0
  165. package/dist/providers/github/scope.js +124 -0
  166. package/dist/providers/github/skill.generated.js +8 -0
  167. package/dist/providers/gmail/index.d.ts +51 -0
  168. package/dist/providers/gmail/index.js +1436 -0
  169. package/dist/providers/gmail/skill.generated.js +9 -0
  170. package/dist/providers/infisical/index.d.ts +7 -0
  171. package/dist/providers/infisical/index.js +713 -0
  172. package/dist/providers/infisical/skill.generated.js +8 -0
  173. package/dist/providers/{linear.d.ts → linear/index.d.ts} +11 -14
  174. package/dist/providers/linear/index.js +352 -0
  175. package/dist/providers/linear/skill.generated.js +8 -0
  176. package/dist/providers/{mixpanel.d.ts → mixpanel/index.d.ts} +5 -10
  177. package/dist/providers/mixpanel/index.js +416 -0
  178. package/dist/providers/mixpanel/skill.generated.js +9 -0
  179. package/dist/providers/{notion.d.ts → notion/index.d.ts} +8 -8
  180. package/dist/providers/{notion.js → notion/index.js} +226 -239
  181. package/dist/providers/notion/skill.generated.js +10 -0
  182. package/dist/providers/{overflow.d.ts → overflow/index.d.ts} +2 -2
  183. package/dist/providers/{overflow.js → overflow/index.js} +74 -111
  184. package/dist/providers/overflow/skill.generated.js +8 -0
  185. package/dist/providers/{planning-center.d.ts → planning-center/index.d.ts} +2 -2
  186. package/dist/providers/{planning-center.js → planning-center/index.js} +264 -104
  187. package/dist/providers/planning-center/skill.generated.js +10 -0
  188. package/dist/providers/{revenuecat.d.ts → revenuecat/index.d.ts} +5 -10
  189. package/dist/providers/revenuecat/index.js +557 -0
  190. package/dist/providers/revenuecat/skill.generated.js +11 -0
  191. package/dist/providers/sheets/index.d.ts +54 -0
  192. package/dist/providers/sheets/index.js +1237 -0
  193. package/dist/providers/sheets/skill.generated.js +10 -0
  194. package/dist/providers/slides/index.d.ts +53 -0
  195. package/dist/providers/slides/index.js +2645 -0
  196. package/dist/providers/slides/skill.generated.js +9 -0
  197. package/dist/providers/{stripe.d.ts → stripe/index.d.ts} +5 -12
  198. package/dist/providers/stripe/index.js +266 -0
  199. package/dist/providers/stripe/skill.generated.js +11 -0
  200. package/dist/providers/{tithely.d.ts → tithely/index.d.ts} +2 -2
  201. package/dist/providers/{tithely.js → tithely/index.js} +60 -91
  202. package/dist/providers/tithely/skill.generated.js +8 -0
  203. package/dist/providers/{vercel.d.ts → vercel/index.d.ts} +8 -8
  204. package/dist/providers/vercel/index.js +1038 -0
  205. package/dist/providers/vercel/mcp-ownership.js +212 -0
  206. package/dist/providers/vercel/skill.generated.js +11 -0
  207. package/dist/registry.d.ts +110 -171
  208. package/dist/registry.js +588 -927
  209. package/dist/request-state.js +21 -0
  210. package/dist/resource-read.js +103 -0
  211. package/dist/result-shapes.js +17 -49
  212. package/dist/retired-toolkits.js +1 -1
  213. package/dist/routes/access-tokens.js +3 -6
  214. package/dist/routes/activity-context.js +21 -0
  215. package/dist/routes/activity-disclosure.js +40 -0
  216. package/dist/routes/activity.js +59 -21
  217. package/dist/routes/actor-labels.js +3 -50
  218. package/dist/routes/connect.js +221 -0
  219. package/dist/routes/credentials.js +15 -27
  220. package/dist/routes/mcp.js +365 -130
  221. package/dist/routes/oauth-client-metadata.js +15 -0
  222. package/dist/routes/oauth-management.js +45 -107
  223. package/dist/routes/oauth.js +110 -57
  224. package/dist/routes/operator.js +3 -3
  225. package/dist/routes/shared.d.ts +25 -64
  226. package/dist/routes/shared.js +160 -80
  227. package/dist/routes/skills.js +30 -0
  228. package/dist/routes/ui-config.js +225 -0
  229. package/dist/routes/ui-data.js +40 -35
  230. package/dist/routes/ui.js +66 -56
  231. package/dist/runtime/admission.js +4 -2
  232. package/dist/runtime/call-admission.js +3 -1
  233. package/dist/runtime/connector-scope.js +1 -4
  234. package/dist/runtime/run.js +10 -39
  235. package/dist/runtime/services.js +12 -117
  236. package/dist/runtime/shared-read.js +1 -3
  237. package/dist/runtime/storage.js +8 -1
  238. package/dist/sent-secrets.d.ts +93 -0
  239. package/dist/sent-secrets.js +1013 -0
  240. package/dist/server.js +28 -71
  241. package/dist/skills.js +416 -174
  242. package/dist/sqlite.d.ts +48 -0
  243. package/dist/sqlite.js +181 -0
  244. package/dist/storage/keys.js +443 -0
  245. package/dist/storage/memory.js +16 -4
  246. package/dist/storage/sql.d.ts +66 -0
  247. package/dist/storage/sql.js +543 -0
  248. package/dist/timeout.js +4 -2
  249. package/dist/tool-name.js +17 -0
  250. package/dist/tool-safety.d.ts +9 -35
  251. package/dist/tool-safety.js +20 -40
  252. package/dist/types.d.ts +336 -56
  253. package/dist/types.js +0 -1
  254. package/dist/ui.d.ts +7 -19
  255. package/dist/ui.js +76 -90
  256. package/dist/url-safety.js +3 -6
  257. package/dist/usage-guide.js +146 -0
  258. package/dist/validate.d.ts +7 -0
  259. package/dist/validate.js +309 -47
  260. package/dist/version.d.ts +1 -7
  261. package/dist/version.js +3 -7
  262. package/dist/worker.d.ts +11 -0
  263. package/dist/worker.js +435 -0
  264. package/documentation/README.md +63 -0
  265. package/documentation/architecture.md +696 -231
  266. package/documentation/auth.md +1069 -546
  267. package/documentation/code-mode.md +662 -356
  268. package/documentation/deploying.md +146 -0
  269. package/documentation/integrating.md +159 -0
  270. package/documentation/meta-tools.md +570 -216
  271. package/documentation/operating.md +135 -0
  272. package/documentation/operator-tests.md +97 -0
  273. package/documentation/operator-ui.md +132 -0
  274. package/documentation/provider-migration-0.29.md +65 -0
  275. package/examples/worker/AGENTS.md +34 -12
  276. package/examples/worker/README.md +293 -255
  277. package/examples/worker/kv-to-d1.wrangler.jsonc +26 -0
  278. package/examples/worker/scripts/copy-kv-to-d1.mjs +162 -0
  279. package/examples/worker/src/connecta.config.ts +151 -0
  280. package/examples/worker/src/index.ts +14 -197
  281. package/examples/worker/wrangler.jsonc +15 -35
  282. package/package.json +126 -54
  283. package/templates/node/.dockerignore +1 -2
  284. package/templates/node/.env.example +20 -21
  285. package/templates/node/AGENTS.md +21 -17
  286. package/templates/node/Dockerfile +3 -5
  287. package/templates/node/README.md +140 -58
  288. package/templates/node/docker-compose.yml +11 -12
  289. package/templates/node/package.json +4 -2
  290. package/templates/node/src/connecta.config.ts +119 -0
  291. package/templates/node/src/index.ts +9 -154
  292. package/templates/node/src/provision-token.ts +17 -0
  293. package/AGENTS.md +0 -170
  294. package/dist/artifacts/connector.d.ts +0 -58
  295. package/dist/artifacts/connector.js +0 -730
  296. package/dist/artifacts/document.js +0 -86
  297. package/dist/artifacts/guide.js +0 -140
  298. package/dist/artifacts/html-scan.js +0 -329
  299. package/dist/artifacts/json.js +0 -78
  300. package/dist/artifacts/kv-store.d.ts +0 -20
  301. package/dist/artifacts/kv-store.js +0 -140
  302. package/dist/artifacts/markdown.js +0 -478
  303. package/dist/artifacts/module.d.ts +0 -37
  304. package/dist/artifacts/module.js +0 -66
  305. package/dist/artifacts/operations.d.ts +0 -197
  306. package/dist/artifacts/operations.js +0 -1002
  307. package/dist/artifacts/refresh.d.ts +0 -55
  308. package/dist/artifacts/refresh.js +0 -236
  309. package/dist/artifacts/routes.js +0 -206
  310. package/dist/artifacts/types.d.ts +0 -214
  311. package/dist/artifacts/types.js +0 -22
  312. package/dist/artifacts/validate.d.ts +0 -62
  313. package/dist/artifacts/validate.js +0 -651
  314. package/dist/artifacts.d.ts +0 -6
  315. package/dist/artifacts.js +0 -9
  316. package/dist/auth/bearer.d.ts +0 -11
  317. package/dist/auth/bearer.js +0 -50
  318. package/dist/providers/basecamp.js +0 -445
  319. package/dist/providers/linear.js +0 -217
  320. package/dist/providers/mixpanel.js +0 -247
  321. package/dist/providers/revenuecat.js +0 -317
  322. package/dist/providers/stripe.js +0 -253
  323. package/dist/providers/vercel.js +0 -1253
  324. package/dist/storage/file.d.ts +0 -15
  325. package/dist/storage/file.js +0 -455
  326. package/ethos.md +0 -93
  327. package/examples/worker/src/cloudflare-kv.ts +0 -43
  328. package/examples/worker/src/d1-activity-row.ts +0 -155
  329. package/examples/worker/src/d1-activity.ts +0 -147
  330. package/examples/worker/src/d1-storage.ts +0 -138
  331. package/examples/worker/src/r2-artifact-blobs.ts +0 -29
  332. package/templates/node/src/file-activity.ts +0 -182
package/dist/errors.js CHANGED
@@ -1,5 +1,64 @@
1
1
  // Typed failure contract for connector tool calls. Web-API only — no node:
2
2
  // imports here.
3
+ import { redactCallArguments } from "./argument-redaction.js";
4
+ const CLASSIFICATION_CODE_TABLE = {
5
+ timeout: true,
6
+ auth_required: true,
7
+ downstream_oauth_required: true,
8
+ oauth_revocation_failed: true,
9
+ provider_permission_denied: true,
10
+ rate_limited: true,
11
+ unavailable: true,
12
+ invalid_args: true,
13
+ not_found: true,
14
+ conflict: true,
15
+ resource_template_ambiguous: true,
16
+ resource_match_budget_exceeded: true,
17
+ input_required_unsupported: true,
18
+ input_required_invalid: true,
19
+ input_required_limit: true,
20
+ connector_call_failed: true,
21
+ executor_overloaded: true,
22
+ executor_cancelled: true,
23
+ executor_closed: true,
24
+ cancelled: true,
25
+ unknown_address: true,
26
+ unknown_tool: true,
27
+ ambiguous_tool_alias: true,
28
+ catalog_lookup_failed: true,
29
+ result_too_large: true,
30
+ destructive_tool_requires_approval: true,
31
+ auth_replay_refused: true,
32
+ write_outcome_unknown: true,
33
+ result_processing_failed: true,
34
+ budget_exceeded: true,
35
+ executor_failed: true,
36
+ program_error: true,
37
+ };
38
+ /** `value` when it is a code connecta assigns, else undefined. */
39
+ export function classificationCode(value) {
40
+ return typeof value === "string" && Object.hasOwn(CLASSIFICATION_CODE_TABLE, value)
41
+ ? value
42
+ : undefined;
43
+ }
44
+ /** Drop oversized detail whole; clipping keys or examples changes their meaning. */
45
+ function boundedRepair(details) {
46
+ if (!details)
47
+ return undefined;
48
+ try {
49
+ const text = JSON.stringify(details);
50
+ return new TextEncoder().encode(text).length <= 4096
51
+ ? JSON.parse(text)
52
+ : {
53
+ issues: [],
54
+ truncated: true,
55
+ exampleUnavailable: "Repair detail exceeds the response budget. Inspect the published inputSchema.",
56
+ };
57
+ }
58
+ catch {
59
+ return undefined;
60
+ }
61
+ }
3
62
  export const MAX_ARGUMENT_VALIDATION_ISSUES = 3;
4
63
  const MAX_ARGUMENT_ISSUE_PATH_CHARS = 256;
5
64
  const MAX_ARGUMENT_ISSUE_CODE_CHARS = 64;
@@ -58,36 +117,40 @@ export function boundedEchoText(value, maxBytes = MAX_ECHOED_BYTES) {
58
117
  return `${echoDecoder.decode(bytes.slice(0, end))}…`;
59
118
  }
60
119
  /**
61
- * `{ args }` when the caller's arguments fit the shared echo budget,
62
- * `{}` when they do not. All or nothing: a clipped echo would be a *different*
63
- * call than the one that was refused, and the routes this feeds end at a human
64
- * approving one. Unserializable arguments are treated the same way as oversized
65
- * ones — there is nothing honest to put in the field.
120
+ * Snapshot the caller's arguments after bounded schema-aware writeOnly omission,
121
+ * then apply the shared byte budget without clipping. Unresolved sensitivity
122
+ * omits the entire echo. argsRedacted marks partial or withheld arguments as
123
+ * reconciliation context; any retry must use the caller's original arguments.
66
124
  */
67
- export function echoedCallArgs(args) {
125
+ export function echoedCallArgs(args, schema) {
68
126
  if (args === undefined)
69
127
  return {};
70
128
  let text;
129
+ let redacted = false;
71
130
  try {
72
- text = JSON.stringify(args);
131
+ const filtered = schema ? redactCallArguments(args, schema) : { value: args, redacted: false };
132
+ redacted = filtered.redacted;
133
+ if (!("value" in filtered))
134
+ return { argsRedacted: true };
135
+ const safeArgs = filtered.value;
136
+ text = JSON.stringify(safeArgs);
73
137
  }
74
138
  catch {
75
- return {};
139
+ return redacted ? { argsRedacted: true } : {};
76
140
  }
77
141
  if (text === undefined)
78
142
  return {};
79
143
  return echoEncoder.encode(text).length <= MAX_ECHOED_BYTES
80
- ? { args }
81
- : {};
144
+ ? { args: JSON.parse(text), ...(redacted ? { argsRedacted: true } : {}) }
145
+ : redacted
146
+ ? { argsRedacted: true }
147
+ : {};
82
148
  }
83
149
  function boundedValidation(details) {
84
150
  if (!details)
85
151
  return undefined;
86
- let truncated = details.truncated === true ||
87
- details.issues.length > MAX_ARGUMENT_VALIDATION_ISSUES;
88
- const issues = details.issues
89
- .slice(0, MAX_ARGUMENT_VALIDATION_ISSUES)
90
- .map((issue) => {
152
+ let truncated = details.truncated === true || details.issues.length > MAX_ARGUMENT_VALIDATION_ISSUES;
153
+ const issues = details.issues.slice(0, MAX_ARGUMENT_VALIDATION_ISSUES).map((issue) => {
91
154
  const path = boundedIssueText(issue.path, MAX_ARGUMENT_ISSUE_PATH_CHARS);
92
155
  const code = boundedIssueText(issue.code, MAX_ARGUMENT_ISSUE_CODE_CHARS);
93
156
  const expected = boundedIssueText(issue.expected, MAX_ARGUMENT_ISSUE_EXPECTED_CHARS);
@@ -103,17 +166,30 @@ function boundedValidation(details) {
103
166
  ...(truncated ? { truncated: true } : {}),
104
167
  };
105
168
  }
106
- const NETWORK_ERROR_CODES = new Set([
107
- "ECONNREFUSED", "ENOTFOUND", "ECONNRESET", "ETIMEDOUT", "EAI_AGAIN",
108
- "EAI_FAIL", "EHOSTUNREACH", "ENETUNREACH", "ENETDOWN", "EHOSTDOWN",
109
- "ECONNABORTED", "EPIPE", "EACCES", "EPERM",
110
- "UND_ERR_CONNECT_TIMEOUT", "UND_ERR_HEADERS_TIMEOUT", "UND_ERR_BODY_TIMEOUT",
111
- "UND_ERR_SOCKET", "timeout",
169
+ /** The network errnos `networkErrorCode` reports, and `timeout`. */
170
+ export const NETWORK_ERROR_CODES = new Set([
171
+ "ECONNREFUSED",
172
+ "ENOTFOUND",
173
+ "ECONNRESET",
174
+ "ETIMEDOUT",
175
+ "EAI_AGAIN",
176
+ "EAI_FAIL",
177
+ "EHOSTUNREACH",
178
+ "ENETUNREACH",
179
+ "ENETDOWN",
180
+ "EHOSTDOWN",
181
+ "ECONNABORTED",
182
+ "EPIPE",
183
+ "EACCES",
184
+ "EPERM",
185
+ "UND_ERR_CONNECT_TIMEOUT",
186
+ "UND_ERR_HEADERS_TIMEOUT",
187
+ "UND_ERR_BODY_TIMEOUT",
188
+ "UND_ERR_SOCKET",
189
+ "timeout",
112
190
  ]);
113
191
  function networkCode(value) {
114
- return typeof value === "string" && value.length <= 32 && NETWORK_ERROR_CODES.has(value)
115
- ? value
116
- : undefined;
192
+ return typeof value === "string" && value.length <= 32 && NETWORK_ERROR_CODES.has(value) ? value : undefined;
117
193
  }
118
194
  function sanitizedUnavailableDetails(details) {
119
195
  if (!details)
@@ -122,8 +198,7 @@ function sanitizedUnavailableDetails(details) {
122
198
  if (typeof details.host === "string") {
123
199
  try {
124
200
  const url = new URL(details.host);
125
- if ((url.protocol === "https:" || url.protocol === "http:") &&
126
- echoEncoder.encode(url.origin).length <= 253)
201
+ if ((url.protocol === "https:" || url.protocol === "http:") && echoEncoder.encode(url.origin).length <= 253)
127
202
  host = url.origin;
128
203
  }
129
204
  catch {
@@ -137,33 +212,73 @@ function sanitizedUnavailableDetails(details) {
137
212
  export function networkErrorCode(error) {
138
213
  if (!error || typeof error !== "object")
139
214
  return undefined;
140
- if (error instanceof Error &&
141
- (error.name === "AbortError" || error.name === "TimeoutError")) {
215
+ if (error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError")) {
142
216
  return "timeout";
143
217
  }
144
218
  const runtime = error;
145
219
  const cause = runtime.cause;
146
- return networkCode(runtime.code) ?? (cause && typeof cause === "object"
147
- ? networkCode(cause.code)
148
- : undefined);
220
+ return (networkCode(runtime.code) ??
221
+ (cause && typeof cause === "object" ? networkCode(cause.code) : undefined));
149
222
  }
150
- /** Use at a fetch boundary where the destination and transport failure are known. */
151
- export function unavailableCallError(cause, host, message = "Could not reach the downstream service.") {
152
- const code = networkErrorCode(cause);
223
+ /**
224
+ * Use at a fetch boundary where the destination and transport failure are
225
+ * known. The runtime's error is read for its errno and dropped, never kept as
226
+ * `cause`: its message and cause chain can quote the URL, headers, or body of
227
+ * the request that failed, and a logger that renders an error renders its
228
+ * cause. The origin and errno in `details` are what survives.
229
+ *
230
+ * The one failure kept is the request's own abort reason, when that is what
231
+ * the fetch rejected with: the caller wrote it, not the downstream, and it is
232
+ * how a cancelled request tells its reason from a network failure.
233
+ */
234
+ export function unavailableCallError(failure, host, message = "Could not reach the downstream service.", signal) {
235
+ const code = networkErrorCode(failure);
236
+ const ownReason = signal?.aborted === true && failure === signal.reason;
153
237
  return new ConnectorCallError("unavailable", message, {
154
- cause,
238
+ ...(ownReason ? { cause: failure } : {}),
155
239
  details: { ...(host ? { host } : {}), ...(code ? { code } : {}) },
156
240
  });
157
241
  }
242
+ /**
243
+ * A failure told in connecta's words because the original's text came from a
244
+ * downstream or authorization server, which can echo what the request carried
245
+ * or plant whatever it likes. There is no `cause`: the original is dropped
246
+ * whole, never masked.
247
+ *
248
+ * It is classified exactly as the original would have been. That verdict is
249
+ * read from the original once, here, and kept as two flags, so withholding
250
+ * the text moves no failure between `timeout`, retryable, and the caller's
251
+ * fallback code. Never wrap a `ConnectorCallError`: it already speaks in
252
+ * connecta's words and carries its own code.
253
+ */
254
+ export class WithheldTextError extends Error {
255
+ /** The original read as a timeout. */
256
+ timeout;
257
+ retryable;
258
+ constructor(message, original) {
259
+ super(message);
260
+ this.name = "WithheldTextError";
261
+ const verdict = classifyCallError(original);
262
+ this.timeout = verdict.code === "timeout";
263
+ this.retryable = verdict.retryable;
264
+ }
265
+ }
158
266
  const RETRYABLE_BY_CODE = {
159
267
  timeout: true,
160
268
  rate_limited: true,
161
269
  unavailable: true,
162
270
  auth_required: false,
271
+ downstream_oauth_required: false,
272
+ oauth_revocation_failed: false,
273
+ provider_permission_denied: false,
163
274
  invalid_args: false,
164
275
  not_found: false,
165
276
  conflict: false,
277
+ resource_template_ambiguous: false,
278
+ resource_match_budget_exceeded: false,
166
279
  input_required_unsupported: false,
280
+ input_required_invalid: false,
281
+ input_required_limit: false,
167
282
  connector_call_failed: false,
168
283
  };
169
284
  /** Entries a conflict's `current` map may carry. */
@@ -196,9 +311,9 @@ function normalizeRetryAfterMs(value) {
196
311
  }
197
312
  /**
198
313
  * Throw from `Connector.callTool` (or anything beneath it) to classify a
199
- * failure exactly. Untyped errors fall back to a message-text heuristic, so a
200
- * connector whose legitimate error text mentions "timeout" is misread as a
201
- * retryable timeout — this class is the escape hatch. `retryable` defaults per
314
+ * failure exactly. Untyped errors are non-retryable unless a runtime errno
315
+ * or abort identifies a transport failure. This class supplies the connector's
316
+ * reviewed verdict. `retryable` defaults per
202
317
  * code (timeout, rate_limited, and unavailable retry; the rest do not) and may
203
318
  * be overridden.
204
319
  *
@@ -220,6 +335,7 @@ export class ConnectorCallError extends Error {
220
335
  retryAfterMs;
221
336
  /** Bounded schema findings for `invalid_args`; never submitted values. */
222
337
  validation;
338
+ repair;
223
339
  /** Sanitized transport diagnostics for `unavailable` only. */
224
340
  details;
225
341
  /**
@@ -233,79 +349,51 @@ export class ConnectorCallError extends Error {
233
349
  this.code = code;
234
350
  this.retryable = opts.retryable ?? RETRYABLE_BY_CODE[code];
235
351
  this.retryAfterMs = normalizeRetryAfterMs(opts.retryAfterMs);
236
- this.details =
237
- code === "unavailable" ? sanitizedUnavailableDetails(opts.details) : undefined;
238
- this.validation =
239
- code === "invalid_args" ? boundedValidation(opts.validation) : undefined;
352
+ this.details = code === "unavailable" ? sanitizedUnavailableDetails(opts.details) : undefined;
353
+ this.validation = code === "invalid_args" ? boundedValidation(opts.validation) : undefined;
354
+ this.repair = code === "invalid_args" ? boundedRepair(opts.repair) : undefined;
240
355
  this.current = code === "conflict" ? boundedCurrent(opts.current) : undefined;
241
356
  }
242
357
  }
243
- /**
244
- * Codes whose retryability is a fact about connecta's own framing, never a
245
- * guess from text. The message embeds the address the caller asked for, so a
246
- * connector named `svc-503` or `temporary-export` would otherwise flip a policy
247
- * refusal into `retryable: true` through the heuristic below — and a caller that
248
- * trusts the flag would cheerfully retry a refusal forever.
249
- */
250
- const NEVER_RETRYABLE_FRAMING = new Set([
251
- "result_processing_failed",
252
- "unknown_address",
253
- "unknown_tool",
254
- "ambiguous_tool_alias",
255
- "destructive_tool_requires_approval",
256
- ]);
257
- /**
258
- * Details for a failure connecta itself framed — an address it could not
259
- * resolve, a tool it refuses to run — rather than one a connector threw.
260
- */
358
+ /** Retryability of connecta framing depends only on its code. */
261
359
  export function framingError(code, message) {
262
360
  return {
263
361
  code,
264
362
  message,
265
- retryable: NEVER_RETRYABLE_FRAMING.has(code)
266
- ? false
267
- : messageLooksRetryable(message),
363
+ retryable: code === "timeout" || code === "unavailable" || code === "rate_limited",
268
364
  };
269
365
  }
270
- const RETRYABLE_MESSAGE_RE = /timeout|timed out|econnreset|econnrefused|temporar|rate.?limit|429|502|503|504|refcountedcanceler|different request/i;
271
- const TIMEOUT_MESSAGE_RE = /timed out|timeout/i;
272
- /** Message-text fallback used when an error carries no typed classification. */
273
- function messageLooksRetryable(message) {
274
- return RETRYABLE_MESSAGE_RE.test(message);
275
- }
276
- /**
277
- * Classify a value thrown by a connector call. A `ConnectorCallError` is
278
- * authoritative; anything else falls back to the historical message-text
279
- * heuristic.
280
- */
366
+ /** Typed connector verdicts and runtime facts only. Prose never changes a verdict. */
281
367
  export function classifyCallError(err, fallbackCode = "connector_call_failed") {
282
368
  if (err instanceof ConnectorCallError) {
283
369
  return {
284
370
  code: err.code,
285
371
  message: err.message,
286
372
  retryable: err.retryable,
287
- ...(err.retryAfterMs !== undefined
288
- ? { retryAfterMs: err.retryAfterMs }
289
- : {}),
373
+ ...(err.retryAfterMs !== undefined ? { retryAfterMs: err.retryAfterMs } : {}),
290
374
  ...(err.validation ? { validation: err.validation } : {}),
375
+ ...(err.repair ? { repair: err.repair } : {}),
291
376
  ...(err.details ? { details: err.details } : {}),
292
377
  ...(err.current ? { current: err.current } : {}),
293
378
  };
294
379
  }
295
- // An aborted fetch rejects with a DOMException named "AbortError" whose
296
- // message ("The operation was aborted", and variants across runtimes) matches
297
- // neither heuristic below — so a call the engine itself cancelled would read
298
- // as a non-retryable failure, the opposite of the truth. Note this also
299
- // covers an abort the connector triggered for its own reasons; running out of
300
- // time is by far the likelier cause and retryable/timeout is the safer read.
301
- if (err instanceof Error && err.name === "AbortError") {
302
- return { code: "timeout", message: err.message, retryable: true };
380
+ if (err instanceof WithheldTextError) {
381
+ return {
382
+ code: err.timeout ? "timeout" : fallbackCode,
383
+ message: err.message,
384
+ retryable: err.retryable,
385
+ };
303
386
  }
304
387
  const message = err instanceof Error ? err.message : String(err);
388
+ const network = networkErrorCode(err);
305
389
  return {
306
- code: TIMEOUT_MESSAGE_RE.test(message) ? "timeout" : fallbackCode,
390
+ code: network === "timeout" || network === "ETIMEDOUT" || network?.endsWith("_TIMEOUT")
391
+ ? "timeout"
392
+ : network
393
+ ? "unavailable"
394
+ : fallbackCode,
307
395
  message,
308
- retryable: RETRYABLE_MESSAGE_RE.test(message),
396
+ retryable: network !== undefined,
309
397
  };
310
398
  }
311
399
  export function msg(err) {