apps 0.0.1-beta.1 → 0.0.1-beta.10

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 (118) hide show
  1. package/README.md +65 -43
  2. package/framework-reference.json +1 -1
  3. package/js/browser-XIPJGLH2.js +65 -0
  4. package/js/{chunk-SATWJKN6.js → chunk-27F7W2LG.js} +1 -1
  5. package/js/{chunk-HDJH3RPR.js → chunk-57RKNWL2.js} +2 -2
  6. package/js/{chunk-2HHMABB6.js → chunk-5T57N25Q.js} +61 -13
  7. package/js/{chunk-6IIO4NPI.js → chunk-72JNVHPK.js} +21 -9
  8. package/js/{chunk-FW5HBOIK.js → chunk-CDL5PM2Q.js} +307 -169
  9. package/js/{chunk-X7SFGU4Q.js → chunk-CRDWFA74.js} +28 -9
  10. package/js/{chunk-G7IE6BKC.js → chunk-EPT3ZP52.js} +8 -8
  11. package/js/chunk-FL2QR3XW.js +507 -0
  12. package/js/{chunk-OHRT55C4.js → chunk-IJX4CYZO.js} +3 -6
  13. package/js/{chunk-ZTFQHGEB.js → chunk-IPI4MFSN.js} +3 -5
  14. package/js/{chunk-YEJOQEII.js → chunk-JU7VHODU.js} +1 -1
  15. package/js/chunk-KUMBKVJD.js +39 -0
  16. package/js/{chunk-EVJUVWN2.js → chunk-M3B3DE4K.js} +2 -2
  17. package/js/{chunk-ZJWDMTE3.js → chunk-MKWZPDR6.js} +3 -3
  18. package/js/{chunk-BMOIAIVR.js → chunk-N7YDVXYJ.js} +49 -1
  19. package/js/chunk-NKLWZJLE.js +172 -0
  20. package/js/{chunk-ZCAMUXSG.js → chunk-ODEIDRGW.js} +3 -4
  21. package/js/{chunk-M6ZRRIBI.js → chunk-PJJ24GU7.js} +1 -1
  22. package/js/{chunk-FZJOYIZO.js → chunk-PZB6T6KU.js} +1 -1
  23. package/js/chunk-R3EV5FTO.js +97 -0
  24. package/js/{chunk-6YBRWRK3.js → chunk-RFVIONFX.js} +43 -14
  25. package/js/{chunk-QKHR7BMF.js → chunk-UK573G7W.js} +1 -1
  26. package/js/{chunk-NCYXZN2G.js → chunk-UVL56Z6E.js} +390 -23
  27. package/js/{chunk-KOXMLKTM.js → chunk-V5KNQVCT.js} +308 -316
  28. package/js/{chunk-4LPG6RCH.js → chunk-VFZKSM3T.js} +5 -25
  29. package/js/{chunk-IHQ4ML7K.js → chunk-WLE7WX2U.js} +554 -102
  30. package/js/{chunk-RBAC33PQ.js → chunk-YXQHV65J.js} +58 -83
  31. package/js/chunk-Z5M2LQOZ.js +209 -0
  32. package/js/{chunk-PLCMJREA.js → chunk-ZQINWV4W.js} +60 -20
  33. package/js/client.js +10 -26
  34. package/js/contracts.js +70 -15
  35. package/js/effect.js +19 -19
  36. package/js/es-APDZKREY.js +40968 -0
  37. package/js/graphql.js +34 -39
  38. package/js/host.js +23 -23
  39. package/js/index.js +199 -195
  40. package/js/mcp/effect.js +21 -21
  41. package/js/mcp/stdio.js +25 -25
  42. package/js/mcp.js +60 -44
  43. package/js/openapi.js +826 -41682
  44. package/js/react.js +3 -3
  45. package/js/skills/effect.js +3 -4
  46. package/js/skills.js +53 -17
  47. package/js/storage/facet.js +4 -4
  48. package/js/ui/auth/contracts.js +8 -9
  49. package/js/ui/auth.js +16 -14
  50. package/js/ui/contracts.js +4 -4
  51. package/js/ui/serving.js +9 -8
  52. package/package.json +1 -1
  53. package/runtime.json +1 -1
  54. package/types/app-cache/src/contracts/cache.d.ts +42 -2
  55. package/types/app-cache/src/index.d.ts +59 -1
  56. package/types/app-data/src/contracts/database.d.ts +33 -6
  57. package/types/app-data/src/implementation/schema.d.ts +2 -17
  58. package/types/apps/src/contracts/app.d.ts +7 -6
  59. package/types/apps/src/contracts/cache.d.ts +4 -1
  60. package/types/apps/src/contracts/failure.d.ts +25 -0
  61. package/types/apps/src/contracts/host.d.ts +34 -679
  62. package/types/apps/src/contracts/mcp.d.ts +16 -0
  63. package/types/apps/src/contracts/openapi.d.ts +11 -1
  64. package/types/apps/src/contracts/operations.d.ts +0 -5
  65. package/types/apps/src/contracts/protocol-version.d.ts +6 -0
  66. package/types/apps/src/contracts/protocols/1.d.ts +1589 -0
  67. package/types/apps/src/contracts/protocols/2.d.ts +668 -0
  68. package/types/apps/src/contracts/protocols/3.d.ts +676 -0
  69. package/types/apps/src/contracts/protocols/4.d.ts +1229 -0
  70. package/types/apps/src/contracts/protocols/5.d.ts +1090 -0
  71. package/types/apps/src/contracts/provider.d.ts +51 -5
  72. package/types/apps/src/contracts/router.d.ts +59 -0
  73. package/types/apps/src/contracts/skills.d.ts +17 -8
  74. package/types/apps/src/contracts/storage.d.ts +3 -3
  75. package/types/apps/src/contracts/ui-auth.d.ts +6 -14
  76. package/types/apps/src/contracts/workflows.d.ts +34 -3
  77. package/types/apps/src/graphql.d.ts +1 -3
  78. package/types/apps/src/implementation/account-router.d.ts +12 -0
  79. package/types/apps/src/implementation/app.d.ts +5 -4
  80. package/types/apps/src/implementation/cache.d.ts +3 -1
  81. package/types/apps/src/implementation/catalog-cache.d.ts +9 -2
  82. package/types/apps/src/implementation/elicitation.d.ts +1 -1
  83. package/types/apps/src/implementation/failure-detail.d.ts +25 -0
  84. package/types/apps/src/implementation/graphql-catalog.d.ts +1 -4
  85. package/types/apps/src/implementation/mcp-catalog.d.ts +1 -4
  86. package/types/apps/src/implementation/mcp-client.d.ts +35 -19
  87. package/types/apps/src/implementation/mcp.d.ts +35 -19
  88. package/types/apps/src/implementation/openapi-compile.d.ts +3 -2
  89. package/types/apps/src/implementation/openapi-document.d.ts +0 -2
  90. package/types/apps/src/implementation/openapi-names.d.ts +18 -0
  91. package/types/apps/src/implementation/openapi-request.d.ts +0 -1
  92. package/types/apps/src/implementation/openapi-source.d.ts +7 -7
  93. package/types/apps/src/implementation/operations.d.ts +26 -3
  94. package/types/apps/src/implementation/protocol-operations.d.ts +3 -4
  95. package/types/apps/src/implementation/provider.d.ts +9 -4
  96. package/types/apps/src/implementation/router-catalog.d.ts +225 -0
  97. package/types/apps/src/implementation/router.d.ts +59 -0
  98. package/types/apps/src/implementation/schema.d.ts +5 -6
  99. package/types/apps/src/implementation/storage.d.ts +5 -3
  100. package/types/apps/src/implementation/swagger-client.d.ts +28 -0
  101. package/types/apps/src/implementation/ui-auth.d.ts +11 -5
  102. package/types/apps/src/implementation/ui-serving.d.ts +4 -2
  103. package/types/apps/src/implementation/webhooks.d.ts +1 -1
  104. package/types/apps/src/implementation/workflow-context.d.ts +11 -3
  105. package/types/apps/src/index.d.ts +5 -4
  106. package/types/apps/src/mcp-stdio.d.ts +2 -5
  107. package/types/apps/src/mcp.d.ts +5 -4
  108. package/types/apps/src/openapi.d.ts +6 -6
  109. package/types/apps/src/skills.d.ts +6 -3
  110. package/types/apps/src/ui-auth.d.ts +2 -2
  111. package/types/telemetry/src/browser-operations.d.ts +5 -2
  112. package/js/chunk-PZ36XMXW.js +0 -93
  113. package/js/chunk-SWPD52J7.js +0 -35
  114. package/js/chunk-TE4KO4HI.js +0 -47
  115. package/js/chunk-W7D7WVSY.js +0 -18
  116. package/types/apps/src/contracts/dynamic-tools.d.ts +0 -13
  117. package/types/apps/src/implementation/account-operations.d.ts +0 -151
  118. package/types/apps/src/implementation/dynamic-tools.d.ts +0 -8
@@ -1,24 +1,41 @@
1
+ import {
2
+ makeCache
3
+ } from "./chunk-NKLWZJLE.js";
4
+ import {
5
+ accountSecrets,
6
+ boundFailureMessage,
7
+ describeFailure,
8
+ failureDetail,
9
+ readCatalog,
10
+ routerSkills
11
+ } from "./chunk-FL2QR3XW.js";
1
12
  import {
2
13
  folderSkillsEffect
3
- } from "./chunk-ZTFQHGEB.js";
14
+ } from "./chunk-IPI4MFSN.js";
4
15
  import {
5
- CacheEntry,
6
- CacheError,
16
+ ResponseStatusError,
7
17
  authorDatabase,
8
- cacheLimits,
9
18
  isApp,
10
19
  toEffectApp,
11
20
  unavailableStorage
12
- } from "./chunk-RBAC33PQ.js";
21
+ } from "./chunk-YXQHV65J.js";
13
22
  import {
23
+ parseDatabaseSchema
24
+ } from "./chunk-ZQINWV4W.js";
25
+ import {
26
+ declaredOperations,
14
27
  fromPromise,
28
+ locate,
15
29
  nativeOperation,
16
30
  toPromise
17
- } from "./chunk-PZ36XMXW.js";
31
+ } from "./chunk-Z5M2LQOZ.js";
18
32
  import {
33
+ accountProviderError,
34
+ httpProviderError,
19
35
  parseProviderError
20
- } from "./chunk-ZJWDMTE3.js";
36
+ } from "./chunk-MKWZPDR6.js";
21
37
  import {
38
+ AccountCheckResult,
22
39
  DeclaredProvider,
23
40
  DeclaredRequirements,
24
41
  ElicitationFailed,
@@ -29,6 +46,7 @@ import {
29
46
  HostError,
30
47
  HostEvaluationFailed,
31
48
  HostInputInvalid,
49
+ HostKindMismatch,
32
50
  HostOperationFailed,
33
51
  HostOperationNotFound,
34
52
  HostOutputInvalid,
@@ -38,6 +56,7 @@ import {
38
56
  HostToolBlocked,
39
57
  HostToolNotFound,
40
58
  HostToolPolicyFailed,
59
+ HostedRouter,
41
60
  HostedTool,
42
61
  HostedToolSummary,
43
62
  HostedWebhook,
@@ -47,7 +66,7 @@ import {
47
66
  ManyAccounts,
48
67
  McpError,
49
68
  NonRetryableError,
50
- OperationToolPrefixes,
69
+ OpenapiResponseError,
51
70
  ResolvedAccounts,
52
71
  ToolResultObservation,
53
72
  TrustedToolApproval,
@@ -62,32 +81,32 @@ import {
62
81
  defaultWebhookTransportLimits,
63
82
  maxInputProblems,
64
83
  workflowDurationMillis
65
- } from "./chunk-IHQ4ML7K.js";
84
+ } from "./chunk-WLE7WX2U.js";
85
+ import {
86
+ CacheError
87
+ } from "./chunk-R3EV5FTO.js";
66
88
  import {
67
89
  AppSkills,
68
90
  SkillFile,
69
91
  SkillLoadFailed
70
- } from "./chunk-YEJOQEII.js";
71
- import {
72
- OpenapiResponseError
73
- } from "./chunk-SWPD52J7.js";
92
+ } from "./chunk-JU7VHODU.js";
74
93
  import {
75
94
  captureTelemetry,
76
95
  invocationFetch
77
- } from "./chunk-ZCAMUXSG.js";
96
+ } from "./chunk-ODEIDRGW.js";
78
97
  import {
79
98
  decoderOf,
80
99
  importedJsonSchema,
81
- jsonSchemaDecoder
82
- } from "./chunk-2HHMABB6.js";
100
+ jsonSchemaDecoder,
101
+ jsonSchemaDocument
102
+ } from "./chunk-5T57N25Q.js";
83
103
  import {
84
104
  JsonObject,
85
105
  JsonValue
86
- } from "./chunk-SATWJKN6.js";
106
+ } from "./chunk-27F7W2LG.js";
87
107
  import {
88
108
  Cause_exports,
89
109
  Clock_exports,
90
- Duration_exports,
91
110
  Effect_exports,
92
111
  Encoding_exports,
93
112
  Match_exports,
@@ -96,7 +115,7 @@ import {
96
115
  SchemaIssue_exports,
97
116
  Schema_exports,
98
117
  Stream_exports
99
- } from "./chunk-FW5HBOIK.js";
118
+ } from "./chunk-CDL5PM2Q.js";
100
119
 
101
120
  // src/implementation/elicitation.ts
102
121
  var prepareElicitation = (input) => Effect_exports.gen(function* () {
@@ -137,19 +156,29 @@ var makeElicit = (handler, signal) => toPromise(
137
156
  var ApprovalDecision = Schema_exports.Literals(["approved", "denied", "user-approval"]);
138
157
 
139
158
  // src/implementation/workflow-context.ts
140
- var workflowSafe = (work) => work.pipe(
159
+ var workflowSafe = (work, secrets) => work.pipe(
141
160
  Effect_exports.catchCause((cause) => {
142
161
  if (Cause_exports.hasInterrupts(cause)) return Effect_exports.interrupt;
143
162
  const error = Cause_exports.squash(cause);
144
163
  if (Schema_exports.is(WorkflowFailure)(error)) return Effect_exports.fail(error);
164
+ const { errorName, message } = failureDetail(error, secrets);
145
165
  return Effect_exports.fail(
146
166
  new WorkflowFailure({
147
167
  reason: "execution",
148
- retryable: !(error instanceof NonRetryableError)
168
+ retryable: !(error instanceof NonRetryableError),
169
+ ...errorName === void 0 ? {} : { errorName },
170
+ ...message === void 0 ? {} : { message }
149
171
  })
150
172
  );
151
173
  })
152
174
  );
175
+ var inStep = (step) => (failure) => failure.step === void 0 ? new WorkflowFailure({
176
+ reason: failure.reason,
177
+ retryable: failure.retryable,
178
+ step: step.slice(0, 200),
179
+ ...failure.errorName === void 0 ? {} : { errorName: failure.errorName },
180
+ ...failure.message.length === 0 ? {} : { message: failure.message }
181
+ }) : failure;
153
182
  var makeWorkflowContext = (execution, definition, fresh, signal) => Effect_exports.gen(function* () {
154
183
  const services = yield* Effect_exports.context();
155
184
  const counts = /* @__PURE__ */ new Map();
@@ -204,25 +233,33 @@ var makeWorkflowContext = (execution, definition, fresh, signal) => Effect_expor
204
233
  Effect_exports.sync(() => new AbortController()),
205
234
  (controller2) => Effect_exports.sync(() => controller2.abort())
206
235
  );
207
- const ctx = yield* fresh(stepId, AbortSignal.any([signal, controller.signal]));
236
+ const step2 = yield* fresh(stepId, AbortSignal.any([signal, controller.signal]));
208
237
  const result = yield* workflowSafe(
209
- Effect_exports.tryPromise({ try: () => callback(ctx), catch: (error) => error })
238
+ Effect_exports.tryPromise({
239
+ try: () => callback(step2.context),
240
+ catch: (error) => error
241
+ }),
242
+ step2.secrets
210
243
  );
211
244
  return yield* Schema_exports.decodeUnknownEffect(WorkflowValue)(result).pipe(
212
245
  Effect_exports.mapError(
213
- () => new WorkflowFailure({ reason: "output", retryable: false })
246
+ () => new WorkflowFailure({
247
+ reason: "output",
248
+ retryable: false,
249
+ message: "The step returned a value that is not JSON, such as undefined, or is larger than 1 MiB. Return null for no result."
250
+ })
214
251
  )
215
252
  );
216
253
  })
217
254
  ).pipe(Effect_exports.provideContext(services))
218
255
  )
219
- );
256
+ ).pipe(Effect_exports.mapError(inStep(name)));
220
257
  });
221
258
  const operationStep = (kind, name, operation, input, options) => Effect_exports.gen(function* () {
222
259
  const target = nativeOperation(operation);
223
- const catalog = kind === "query" ? definition.queries : definition.mutations;
224
- const match = Object.entries(catalog ?? {}).find(
225
- ([, value]) => value === target && value.kind === kind
260
+ const root = definition.tools?.kind === "router" ? definition.tools : void 0;
261
+ const match = declaredOperations(root).find(
262
+ (entry) => entry.operation === target && entry.operation.kind === kind
226
263
  );
227
264
  if (target === void 0 || match === void 0)
228
265
  return yield* new WorkflowFailure({ reason: "operation", retryable: false });
@@ -241,9 +278,9 @@ var makeWorkflowContext = (execution, definition, fresh, signal) => Effect_expor
241
278
  parsed,
242
279
  () => attempt(
243
280
  parsed,
244
- execution.invoke({ kind, name: match[0], input: args, stepId, timeout }).pipe(Effect_exports.provideContext(services))
281
+ execution.invoke({ kind, name: match.name, input: args, stepId, timeout }).pipe(Effect_exports.provideContext(services))
245
282
  )
246
- );
283
+ ).pipe(Effect_exports.mapError(inStep(name)));
247
284
  });
248
285
  const invoke = (effect) => toPromise(() => effect.pipe(Effect_exports.provideContext(services)), signal)();
249
286
  const step = {
@@ -452,144 +489,14 @@ var dispatchWebhook = (definition, command, context, accounts) => Effect_exports
452
489
  );
453
490
  });
454
491
 
455
- // ../app-cache/src/index.ts
456
- var canonical = (value) => {
457
- if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
458
- if (value !== null && typeof value === "object")
459
- return `{${Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, item]) => `${JSON.stringify(key)}:${canonical(item)}`).join(",")}}`;
460
- return JSON.stringify(value);
461
- };
462
- var cacheKey = (key) => Effect_exports.gen(function* () {
463
- const parsed = yield* Schema_exports.decodeUnknownEffect(Schema_exports.Json)(key).pipe(
464
- Effect_exports.mapError(() => new CacheError({ reason: "invalid" }))
465
- );
466
- const bytes = new TextEncoder().encode(canonical(parsed));
467
- if (bytes.byteLength > cacheLimits.keyBytes)
468
- return yield* new CacheError({ reason: "capacity" });
469
- const hash = yield* Effect_exports.tryPromise({
470
- try: () => crypto.subtle.digest("SHA-256", bytes),
471
- catch: () => new CacheError({ reason: "invalid" })
472
- });
473
- return [...new Uint8Array(hash)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
474
- });
475
- var makeCache = (transport, background, scope = "shared") => {
476
- const keyOf = (key) => cacheKey([scope, key]);
477
- const readKeys = (keys) => transport({ operation: "read", keys }).pipe(
478
- Effect_exports.flatMap(Schema_exports.decodeUnknownEffect(Schema_exports.Array(Schema_exports.NullOr(CacheEntry)))),
479
- Effect_exports.mapError(() => new CacheError({ reason: "storage" }))
480
- );
481
- const durations = (freshFor, staleFor = 0) => Effect_exports.try({
482
- try: () => {
483
- const fresh = Duration_exports.toMillis(Duration_exports.fromInputUnsafe(freshFor));
484
- const stale = Duration_exports.toMillis(Duration_exports.fromInputUnsafe(staleFor));
485
- if (![fresh, stale].every((value) => Number.isFinite(value) && value >= 0) || fresh + stale > cacheLimits.retentionMs)
486
- throw new CacheError({ reason: "invalid" });
487
- return { fresh, stale };
488
- },
489
- catch: () => new CacheError({ reason: "invalid" })
490
- });
491
- const get = (options, refresh) => Effect_exports.gen(function* () {
492
- const key = yield* keyOf(options.key);
493
- const { fresh, stale } = yield* durations(options.freshFor, options.staleFor);
494
- const decode = (value) => Schema_exports.decodeUnknownEffect(options.schema)(value);
495
- const load = (lease) => Effect_exports.gen(function* () {
496
- const value = yield* options.load.pipe(Effect_exports.flatMap(decode));
497
- const json = yield* Schema_exports.decodeUnknownEffect(Schema_exports.Json)(value).pipe(
498
- Effect_exports.mapError(() => new CacheError({ reason: "invalid" }))
499
- );
500
- const now = yield* Clock_exports.currentTimeMillis;
501
- const published = yield* transport({
502
- operation: "publish",
503
- key,
504
- lease,
505
- entry: {
506
- value: json,
507
- version: crypto.randomUUID(),
508
- freshUntil: now + fresh,
509
- staleUntil: now + fresh + stale
510
- }
511
- });
512
- if (published !== true) return yield* new CacheError({ reason: "unavailable" });
513
- return value;
514
- }).pipe(
515
- Effect_exports.withSpan("app.cache.load"),
516
- Effect_exports.timeout(cacheLimits.loadTimeoutMs),
517
- Effect_exports.ensuring(
518
- transport({ operation: "release", key, lease }).pipe(Effect_exports.catch(() => Effect_exports.void))
519
- )
520
- );
521
- const deadline = (yield* Clock_exports.currentTimeMillis) + cacheLimits.leaseMs;
522
- let initialVersion;
523
- while (true) {
524
- const entry = (yield* readKeys([key]))[0] ?? null;
525
- const now = yield* Clock_exports.currentTimeMillis;
526
- if (initialVersion === void 0) initialVersion = entry?.version ?? null;
527
- const refreshed = refresh && entry !== null && entry.version !== initialVersion;
528
- if (entry !== null && (refreshed || !refresh && now < entry.freshUntil)) {
529
- yield* Effect_exports.annotateCurrentSpan("cache.result", "fresh");
530
- return yield* decode(entry.value);
531
- }
532
- const lease = yield* transport({
533
- operation: "claim",
534
- key,
535
- version: entry?.version ?? null
536
- }).pipe(Effect_exports.flatMap(Schema_exports.decodeUnknownEffect(Schema_exports.NullOr(Schema_exports.String))));
537
- if (!refresh && entry !== null && now < entry.staleUntil) {
538
- yield* Effect_exports.annotateCurrentSpan("cache.result", "stale");
539
- if (lease !== null) yield* background(load(lease).pipe(Effect_exports.asVoid));
540
- return yield* decode(entry.value);
541
- }
542
- if (lease !== null) {
543
- yield* Effect_exports.annotateCurrentSpan("cache.result", "miss");
544
- return yield* load(lease);
545
- }
546
- if (now >= deadline) return yield* new CacheError({ reason: "timeout" });
547
- yield* Effect_exports.sleep("100 millis");
548
- }
549
- }).pipe(Effect_exports.withSpan("app.cache.get"));
550
- return {
551
- /** Read arbitrary retained JSON entries without initiating a refresh. Missing and null are distinct. */
552
- read: (keys) => Effect_exports.forEach(keys, keyOf).pipe(Effect_exports.flatMap(readKeys)),
553
- /** Publish bounded immutable parts before publishing the manifest that references them. */
554
- write: (entries, retention) => Effect_exports.gen(function* () {
555
- const { fresh } = yield* durations(retention);
556
- const now = yield* Clock_exports.currentTimeMillis;
557
- const values = yield* Effect_exports.forEach(
558
- entries,
559
- ({ key, value }) => Effect_exports.gen(function* () {
560
- return {
561
- key: yield* keyOf(key),
562
- entry: {
563
- value,
564
- version: crypto.randomUUID(),
565
- freshUntil: now + fresh,
566
- staleUntil: now + fresh
567
- }
568
- };
569
- })
570
- );
571
- yield* transport({ operation: "write", entries: values });
572
- }),
573
- /** Revoke retained data and any loader's right to publish its in-flight result. */
574
- invalidate: (key) => keyOf(key).pipe(
575
- Effect_exports.flatMap((key2) => transport({ operation: "invalidate", key: key2 })),
576
- Effect_exports.asVoid
577
- ),
578
- /** Read fresh data, refresh stale data in the background, or wait for the lease owner. */
579
- get: (options) => get(options, false),
580
- /** Force one awaited refresh without removing the retained value. Concurrent refreshes share a load. */
581
- revalidate: (options) => get(options, true)
582
- };
583
- };
584
-
585
492
  // src/implementation/cache.ts
586
493
  var unavailableCache = {
587
494
  transport: () => Effect_exports.fail(new CacheError({ reason: "unavailable" })),
588
495
  background: () => Effect_exports.die(new Error("Cache background runner is unavailable"))
589
496
  };
590
- var authorCache = (host, accounts, signal) => {
497
+ var authorCache = (host, accounts, signal, deadline) => {
591
498
  const scoped = (scope, callerSignal = signal) => {
592
- const cache = makeCache(host.transport, host.background, scope);
499
+ const cache = makeCache(host.transport, host.background, scope, deadline);
593
500
  const load = (method, options) => cache[method]({
594
501
  key: options.key,
595
502
  schema: decoderOf(options.schema),
@@ -641,7 +548,7 @@ var authorCache = (host, accounts, signal) => {
641
548
  const bound = Object.values(accounts).flatMap((value) => Array.isArray(value) ? value : [value]).find((value) => value.id === account.id);
642
549
  if (bound === void 0) throw new CacheError({ reason: "invalid" });
643
550
  return scoped(
644
- { account: bound.id, method: bound.method, fields: bound.fields },
551
+ { account: bound.id, method: bound.method, generation: bound.generation },
645
552
  callerSignal
646
553
  );
647
554
  }
@@ -651,6 +558,10 @@ var authorCache = (host, accounts, signal) => {
651
558
  };
652
559
 
653
560
  // src/implementation/host.ts
561
+ var WireCatalog = Schema_exports.Struct({
562
+ tools: Schema_exports.Array(Schema_exports.Union([HostedTool, HostedToolSummary])),
563
+ routers: Schema_exports.Array(HostedRouter)
564
+ });
654
565
  function safe2(work, failure) {
655
566
  return Effect_exports.suspend(work).pipe(
656
567
  Effect_exports.catchCause(
@@ -658,7 +569,7 @@ function safe2(work, failure) {
658
569
  )
659
570
  );
660
571
  }
661
- var evaluationSafe = (work) => work.pipe(
572
+ var evaluationSafe = (work, secrets) => work.pipe(
662
573
  Effect_exports.catchCause((cause) => {
663
574
  if (Cause_exports.hasInterrupts(cause)) return Effect_exports.interrupt;
664
575
  const error = Cause_exports.squash(cause);
@@ -666,22 +577,25 @@ var evaluationSafe = (work) => work.pipe(
666
577
  const skills = parseSkillLoadFailed(error);
667
578
  const mcp = parseMcpError(error);
668
579
  return Effect_exports.fail(
669
- Option_exports.isSome(provider) ? provider.value : Option_exports.isSome(skills) ? skills.value : Option_exports.isSome(mcp) ? mcp.value : new HostEvaluationFailed()
580
+ Option_exports.isSome(provider) ? provider.value : Option_exports.isSome(skills) ? skills.value : Option_exports.isSome(mcp) ? mcp.value : new HostEvaluationFailed(failureDetail(error, secrets))
670
581
  );
671
582
  })
672
583
  );
673
- function jsonSchema(decoder) {
674
- const imported = importedJsonSchema(decoder);
675
- if (imported !== void 0) return Schema_exports.decodeUnknownEffect(JsonObject)(imported);
676
- const document = Schema_exports.toJsonSchemaDocument(decoder);
677
- return Schema_exports.decodeUnknownEffect(JsonObject)({
678
- ...document.schema,
679
- $defs: document.definitions,
680
- $schema: "https://json-schema.org/draft/2020-12/schema"
681
- });
682
- }
584
+ var declarationInvalid = (summary, cause, secrets = []) => new HostDeclarationInvalid({
585
+ source: "app",
586
+ errorName: "HostDeclarationInvalid",
587
+ message: boundFailureMessage(
588
+ cause === void 0 ? summary : `${summary}: ${describeFailure(cause)}`,
589
+ secrets
590
+ )
591
+ });
592
+ var declarationSafe = (work, summary) => Effect_exports.suspend(work).pipe(
593
+ Effect_exports.catchCause(
594
+ (cause) => Cause_exports.hasInterrupts(cause) ? Effect_exports.interrupt : Effect_exports.fail(declarationInvalid(summary, Cause_exports.squash(cause)))
595
+ )
596
+ );
683
597
  function providerDeclaration(provider) {
684
- return safe2(
598
+ return declarationSafe(
685
599
  () => Effect_exports.gen(function* () {
686
600
  const auth = /* @__PURE__ */ new Map();
687
601
  for (const [name, method] of Object.entries(provider.auth)) {
@@ -690,14 +604,14 @@ function providerDeclaration(provider) {
690
604
  auth.set(name, {
691
605
  type: "secrets",
692
606
  label: method.label,
693
- fields: yield* jsonSchema(method.fields)
607
+ fields: yield* jsonSchemaDocument(method.fields)
694
608
  });
695
609
  break;
696
610
  case "oauth2":
697
611
  auth.set(name, {
698
612
  type: "oauth2",
699
613
  ...method.config,
700
- response: yield* jsonSchema(method.response)
614
+ response: yield* jsonSchemaDocument(method.response)
701
615
  });
702
616
  break;
703
617
  }
@@ -707,31 +621,35 @@ function providerDeclaration(provider) {
707
621
  auth: Object.fromEntries(auth)
708
622
  });
709
623
  }),
710
- new HostDeclarationInvalid()
624
+ `Account provider "${provider.name}" has an invalid declaration`
711
625
  );
712
626
  }
713
627
  function requirements(slots, database) {
714
628
  return Effect_exports.gen(function* () {
715
629
  const accounts = /* @__PURE__ */ new Map();
716
630
  for (const [slot, selection] of Object.entries(slots)) {
631
+ const provider = selection instanceof ManyAccounts ? selection.provider : selection;
717
632
  accounts.set(slot, {
718
633
  cardinality: selection instanceof ManyAccounts ? "many" : "one",
719
- definition: yield* providerDeclaration(
720
- selection instanceof ManyAccounts ? selection.provider : selection
721
- )
634
+ definition: yield* providerDeclaration(provider),
635
+ ...provider.health === void 0 ? {} : { health: true }
722
636
  });
723
637
  }
724
638
  return yield* Schema_exports.decodeUnknownEffect(DeclaredRequirements)({
725
639
  accounts: Object.fromEntries(accounts),
726
640
  capabilities: { skills: true, toolIndex: true, skillSources: true, scheduledTools: true },
727
641
  ...database === void 0 ? {} : { database }
728
- }).pipe(Effect_exports.mapError(() => new HostDeclarationInvalid()));
642
+ }).pipe(
643
+ Effect_exports.mapError(
644
+ (cause) => declarationInvalid("The app's account or database declarations are invalid", cause)
645
+ )
646
+ );
729
647
  });
730
648
  }
731
- function canonical2(value) {
732
- if (Array.isArray(value)) return `[${value.map(canonical2).join(",")}]`;
649
+ function canonical(value) {
650
+ if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
733
651
  if (value !== null && typeof value === "object") {
734
- return `{${Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, item]) => `${JSON.stringify(key)}:${canonical2(item)}`).join(",")}}`;
652
+ return `{${Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, item]) => `${JSON.stringify(key)}:${canonical(item)}`).join(",")}}`;
735
653
  }
736
654
  return JSON.stringify(value);
737
655
  }
@@ -760,7 +678,7 @@ function bindAccounts(slots, declarations, context) {
760
678
  for (const account of accounts) {
761
679
  if (ids.has(account.id)) return yield* Effect_exports.fail(new HostAccountsInvalid());
762
680
  ids.add(account.id);
763
- if (canonical2(account.provider) !== canonical2(requirement.definition) || !Object.hasOwn(provider.auth, account.method))
681
+ if (canonical(account.provider) !== canonical(requirement.definition) || !Object.hasOwn(provider.auth, account.method))
764
682
  return yield* Effect_exports.fail(new HostAccountsInvalid());
765
683
  const method = provider.auth[account.method];
766
684
  if (method === void 0) return yield* Effect_exports.fail(new HostAccountsInvalid());
@@ -781,17 +699,67 @@ function bindAccounts(slots, declarations, context) {
781
699
  new HostAccountsInvalid()
782
700
  );
783
701
  }
702
+ var fetchLifetime = (signal, background) => Effect_exports.acquireRelease(
703
+ Effect_exports.sync(() => {
704
+ const controller = new AbortController();
705
+ let refreshes = 0;
706
+ let ended = false;
707
+ const settle = () => {
708
+ if (ended && refreshes === 0) controller.abort();
709
+ };
710
+ const end = () => {
711
+ ended = true;
712
+ settle();
713
+ };
714
+ signal.addEventListener("abort", end, { once: true });
715
+ if (signal.aborted) end();
716
+ const settled = Effect_exports.sync(() => {
717
+ refreshes -= 1;
718
+ settle();
719
+ });
720
+ return {
721
+ signal: controller.signal,
722
+ close: () => {
723
+ signal.removeEventListener("abort", end);
724
+ end();
725
+ },
726
+ /** Counted from the hand-off, so a refresh that has not started yet keeps the fetch. */
727
+ background: (task) => Effect_exports.suspend(() => {
728
+ refreshes += 1;
729
+ return background(task.pipe(Effect_exports.ensuring(settled))).pipe(
730
+ Effect_exports.onError(() => settled)
731
+ );
732
+ })
733
+ };
734
+ }),
735
+ (lifetime) => Effect_exports.sync(lifetime.close)
736
+ );
784
737
  function dispatch(app, request, context, signal) {
785
738
  return Effect_exports.scoped(
786
739
  Effect_exports.gen(function* () {
787
- if (!isApp(app)) return yield* Effect_exports.fail(new HostDeclarationInvalid());
740
+ if (!isApp(app))
741
+ return yield* Effect_exports.fail(
742
+ declarationInvalid("The app module's default export is not an app created by defineApp")
743
+ );
788
744
  const native = toEffectApp(app);
745
+ const secrets = accountSecrets(context.accounts);
746
+ const storageFailure = (error) => Effect_exports.fail(new HostOperationFailed(failureDetail(error, secrets)));
789
747
  const declared = yield* requirements(native.accounts, native.database?.schema);
790
- if (request.operation === "requirements")
748
+ if (request.operation === "requirements") {
749
+ if (native.database !== void 0)
750
+ yield* parseDatabaseSchema(native.database.schema).pipe(
751
+ Effect_exports.catchTag(
752
+ "AppDatabaseError",
753
+ (cause) => Effect_exports.fail(
754
+ declarationInvalid("The app's account or database declarations are invalid", cause)
755
+ )
756
+ )
757
+ );
791
758
  return yield* safe2(
792
759
  () => Schema_exports.decodeUnknownEffect(JsonValue)(declared),
793
760
  new HostDeclarationInvalid()
794
761
  );
762
+ }
795
763
  const lifetime = yield* Effect_exports.acquireRelease(
796
764
  Effect_exports.sync(() => new AbortController()),
797
765
  (controller) => Effect_exports.sync(() => controller.abort())
@@ -817,6 +785,14 @@ function dispatch(app, request, context, signal) {
817
785
  return yield* new WorkflowFailure({ reason: "engine", retryable: true });
818
786
  return result;
819
787
  });
788
+ if (request.operation === "account-check")
789
+ return yield* checkAccount(
790
+ native.accounts,
791
+ declared,
792
+ request.requirement,
793
+ context,
794
+ invocationSignal
795
+ ).pipe(withinDeadline);
820
796
  let running;
821
797
  let transactionOpen = false;
822
798
  const delivery = (request2, signal2) => Effect_exports.suspend(
@@ -851,11 +827,22 @@ function dispatch(app, request, context, signal) {
851
827
  const files = yield* Schema_exports.decodeUnknownEffect(Schema_exports.Array(SkillFile))(
852
828
  context.files ?? []
853
829
  ).pipe(Effect_exports.mapError(() => new HostDeclarationInvalid()));
830
+ let cacheCommands = 0;
831
+ const hostCache = context.cache ?? unavailableCache;
832
+ const fetching = yield* fetchLifetime(signal, hostCache.background);
854
833
  const bound = {
855
834
  cache: authorCache(
856
- context.cache ?? unavailableCache,
835
+ {
836
+ ...hostCache,
837
+ transport: (command) => {
838
+ cacheCommands += 1;
839
+ return hostCache.transport(command);
840
+ },
841
+ background: fetching.background
842
+ },
857
843
  Redacted_exports.value(context.accounts),
858
- invocationSignal
844
+ invocationSignal,
845
+ deadline
859
846
  ),
860
847
  files,
861
848
  ...yield* bindAccounts(native.accounts, declared, context).pipe(
@@ -863,35 +850,43 @@ function dispatch(app, request, context, signal) {
863
850
  ),
864
851
  workflows: workflowReads,
865
852
  signal: invocationSignal,
866
- fetch: yield* invocationFetch(invocationSignal),
853
+ fetch: yield* invocationFetch(fetching.signal),
867
854
  elicit: makeElicit(delivery, invocationSignal)
868
855
  };
869
- const definition = yield* evaluationSafe(native.evaluate(bound)).pipe(
856
+ const definition = yield* evaluationSafe(native.evaluate(bound), secrets).pipe(
870
857
  Effect_exports.withSpan("app.evaluate")
871
858
  );
872
859
  if (request.operation === "skills") {
873
860
  const declared2 = definition.skills ?? (yield* folderSkillsEffect({ files }).pipe(
874
861
  Effect_exports.mapError(() => new HostDeclarationInvalid())
875
862
  ));
876
- const source2 = definition.dynamicSkills;
877
- const dynamic = source2 === void 0 ? [] : yield* evaluationSafe(Effect_exports.suspend(source2.list)).pipe(
863
+ const source = definition.dynamicSkills;
864
+ const before = cacheCommands;
865
+ const dynamic = source === void 0 ? [] : yield* evaluationSafe(Effect_exports.suspend(source.list), secrets).pipe(
878
866
  Effect_exports.withSpan("app.skills.load")
879
867
  );
880
- const skills = yield* Schema_exports.decodeUnknownEffect(AppSkills)([...declared2, ...dynamic]).pipe(
881
- Effect_exports.mapError(() => new HostDeclarationInvalid())
882
- );
883
- return request.sources === true ? { skills, dynamic: source2 !== void 0 } : skills;
868
+ const cached = source !== void 0 && cacheCommands > before;
869
+ const authored = new Set([...declared2, ...dynamic].map((skill) => skill.name));
870
+ const routed = (yield* routerSkills(definition.tools).pipe(
871
+ Effect_exports.withSpan("app.skills.routers")
872
+ )).filter((skill) => !authored.has(skill.name));
873
+ const skills = yield* Schema_exports.decodeUnknownEffect(AppSkills)([
874
+ ...declared2,
875
+ ...dynamic,
876
+ ...routed
877
+ ]).pipe(Effect_exports.mapError(() => new HostDeclarationInvalid()));
878
+ return request.sources === true ? { skills, dynamic: source !== void 0, cached } : skills;
884
879
  }
885
880
  if (request.operation === "workflows") {
886
881
  return yield* Effect_exports.forEach(
887
882
  Object.entries(definition.workflows ?? {}),
888
- ([name2, entry]) => safe2(
883
+ ([name, entry]) => safe2(
889
884
  () => Effect_exports.gen(function* () {
890
885
  return yield* Schema_exports.decodeUnknownEffect(HostedWorkflow)({
891
- name: name2,
886
+ name,
892
887
  ...entry.description === void 0 ? {} : { description: entry.description },
893
- inputSchema: yield* jsonSchema(entry.input),
894
- ...entry.output === void 0 ? {} : { outputSchema: yield* jsonSchema(entry.output) }
888
+ inputSchema: yield* jsonSchemaDocument(entry.input),
889
+ ...entry.output === void 0 ? {} : { outputSchema: yield* jsonSchemaDocument(entry.output) }
895
890
  });
896
891
  }),
897
892
  new HostDeclarationInvalid()
@@ -924,108 +919,60 @@ function dispatch(app, request, context, signal) {
924
919
  new WorkflowFailure({ reason: "credentials", retryable: false })
925
920
  );
926
921
  return {
927
- ...accounts,
928
- cache: authorCache(
929
- context.cache ?? unavailableCache,
930
- Redacted_exports.value(current.accounts),
931
- signal2
932
- ),
933
- files,
934
- fetch: yield* invocationFetch(signal2),
935
- signal: signal2,
936
- runId: execution.runId,
937
- stepId,
938
- idempotencyKey: stepId
922
+ context: {
923
+ ...accounts,
924
+ cache: authorCache(
925
+ context.cache ?? unavailableCache,
926
+ Redacted_exports.value(current.accounts),
927
+ signal2
928
+ ),
929
+ files,
930
+ fetch: yield* invocationFetch(signal2),
931
+ signal: signal2,
932
+ runId: execution.runId,
933
+ stepId,
934
+ idempotencyKey: stepId
935
+ },
936
+ // The resolved values, not the app's decoded fields, which may be `Redacted`.
937
+ secrets: accountSecrets(current.accounts)
939
938
  };
940
939
  }),
941
940
  invocationSignal
942
941
  );
943
- const output = yield* workflowSafe(entry.run(workflowContext, input2));
942
+ const output = yield* workflowSafe(entry.run(workflowContext, input2), secrets);
944
943
  const outputSchema = entry.output;
945
944
  const decoded = outputSchema === void 0 ? output : yield* safe2(
946
945
  () => Schema_exports.decodeUnknownEffect(outputSchema)(output),
947
- new WorkflowFailure({ reason: "output", retryable: false })
946
+ new WorkflowFailure({
947
+ reason: "output",
948
+ retryable: false,
949
+ message: "The workflow's result does not match its declared output schema."
950
+ })
948
951
  );
949
952
  return yield* safe2(
950
953
  () => Schema_exports.decodeUnknownEffect(WorkflowValue)(decoded),
951
- new WorkflowFailure({ reason: "output", retryable: false })
954
+ new WorkflowFailure({
955
+ reason: "output",
956
+ retryable: false,
957
+ message: "The workflow returned a value that is not JSON, such as undefined, or is larger than 1 MiB. Return null for no result."
958
+ })
952
959
  );
953
960
  }
954
961
  if (request.operation === "inspect") {
955
962
  const summary = request.detail === "summary";
956
- const wanted = request.tools === void 0 ? void 0 : new Set(request.tools);
957
- const metadata = [];
958
- for (const [prefix, readOnly, catalog2] of [
959
- [OperationToolPrefixes.query, true, definition.queries],
960
- [OperationToolPrefixes.mutate, false, definition.mutations]
961
- ]) {
962
- for (const [name2, operation] of Object.entries(catalog2 ?? {})) {
963
- if (wanted !== void 0 && !wanted.has(`${prefix}${name2}`)) continue;
964
- const schedules = Object.entries(definition.schedules ?? {}).filter(([, schedule]) => schedule.tool === `${prefix}${name2}`).map(([name3, { tool: _tool, ...schedule }]) => ({ name: name3, ...schedule }));
965
- if (request.scheduled === true && schedules.length === 0) continue;
966
- metadata.push(
967
- yield* safe2(
968
- () => Effect_exports.gen(function* () {
969
- const fields = {
970
- name: `${prefix}${name2}`,
971
- schedules,
972
- description: operation.description ?? `${readOnly ? "Query" : "Mutate"} ${name2}`,
973
- ...operation.title === void 0 ? {} : { title: operation.title },
974
- readOnly,
975
- annotations: { ...operation.annotations, readOnlyHint: readOnly }
976
- };
977
- if (summary)
978
- return yield* Schema_exports.decodeUnknownEffect(HostedToolSummary)(fields);
979
- return yield* Schema_exports.decodeUnknownEffect(HostedTool)({
980
- ...fields,
981
- inputSchema: yield* jsonSchema(operation.input),
982
- ...operation.output === void 0 ? operation.outputSchema === void 0 ? {} : { outputSchema: operation.outputSchema } : { outputSchema: yield* jsonSchema(operation.output) },
983
- ...operation._meta === void 0 ? {} : { _meta: operation._meta }
984
- });
985
- }),
986
- new HostDeclarationInvalid()
987
- )
988
- );
989
- }
990
- }
991
- const dynamic = request.scheduled === true ? void 0 : definition.dynamicTools;
992
- if (dynamic !== void 0 && (wanted === void 0 || metadata.length < wanted.size)) {
993
- const declared2 = new Set(metadata.map((tool2) => tool2.name));
994
- const discover = () => {
995
- if (summary && dynamic.summaries !== void 0) return dynamic.summaries();
996
- if (wanted !== void 0 && dynamic.describe !== void 0) {
997
- const describe = dynamic.describe;
998
- return Effect_exports.forEach(
999
- [...wanted].filter((name2) => !declared2.has(name2)),
1000
- (name2) => describe(name2),
1001
- { concurrency: "unbounded" }
1002
- ).pipe(Effect_exports.map((tools) => tools.filter((tool2) => tool2 !== void 0)));
1003
- }
1004
- return dynamic.list();
1005
- };
1006
- const discovered = yield* evaluationSafe(discover()).pipe(
1007
- Effect_exports.flatMap(
1008
- (value) => safe2(
1009
- () => summary ? Schema_exports.decodeUnknownEffect(Schema_exports.Array(HostedToolSummary))(value) : Schema_exports.decodeUnknownEffect(Schema_exports.Array(HostedTool))(value),
1010
- new HostDeclarationInvalid()
1011
- )
1012
- )
1013
- );
1014
- const names = new Set(declared2);
1015
- for (const tool2 of discovered) {
1016
- const readOnly = tool2.name.startsWith(OperationToolPrefixes.query);
1017
- if (!readOnly && !tool2.name.startsWith(OperationToolPrefixes.mutate) || tool2.name === OperationToolPrefixes.query || tool2.name === OperationToolPrefixes.mutate || names.has(tool2.name))
1018
- return yield* new HostDeclarationInvalid();
1019
- names.add(tool2.name);
1020
- if (wanted !== void 0 && !wanted.has(tool2.name)) continue;
1021
- metadata.push({
1022
- ...tool2,
1023
- readOnly,
1024
- annotations: { ...tool2.annotations, readOnlyHint: readOnly }
1025
- });
1026
- }
1027
- }
1028
- return metadata;
963
+ const catalog = yield* readCatalog(definition.tools, {
964
+ summary,
965
+ secrets,
966
+ ...request.tools === void 0 ? {} : { wanted: new Set(request.tools) },
967
+ ...request.scheduled === true ? { scheduled: true } : {},
968
+ schedules: (name) => Object.entries(definition.schedules ?? {}).filter(([, schedule]) => schedule.tool === name).map(([name2, { tool: _tool, ...schedule }]) => ({ name: name2, ...schedule }))
969
+ }).pipe(Effect_exports.withSpan("app.catalog.read"));
970
+ return yield* safe2(
971
+ () => Schema_exports.encodeEffect(WireCatalog)(catalog).pipe(
972
+ Effect_exports.flatMap(Schema_exports.decodeUnknownEffect(JsonValue))
973
+ ),
974
+ new HostDeclarationInvalid()
975
+ );
1029
976
  }
1030
977
  if (request.operation === "webhook-complete" || request.operation === "webhook-validate" || request.operation === "webhooks" || request.operation === "webhook-register" || request.operation === "webhook-handle" || request.operation === "webhook-unregister") {
1031
978
  const executeWebhook = (db) => dispatchWebhook(
@@ -1049,25 +996,22 @@ function dispatch(app, request, context, signal) {
1049
996
  const storage2 = context.storage ?? unavailableStorage;
1050
997
  return yield* storage2.mutate(native.database.schema, executeWebhook).pipe(
1051
998
  Effect_exports.catchTags({
1052
- AppDatabaseError: () => Effect_exports.fail(new HostOperationFailed()),
1053
- AppStorageUnavailable: () => Effect_exports.fail(new HostOperationFailed()),
1054
- AppStorageError: () => Effect_exports.fail(new HostOperationFailed())
999
+ AppDatabaseError: storageFailure,
1000
+ DatabaseLimitExceeded: (error) => Effect_exports.fail(error),
1001
+ AppStorageUnavailable: storageFailure,
1002
+ AppStorageError: storageFailure
1055
1003
  })
1056
1004
  );
1057
1005
  }
1058
- const kind = request.operation === "call" ? request.tool.startsWith(OperationToolPrefixes.query) ? "query" : request.tool.startsWith(OperationToolPrefixes.mutate) ? "mutate" : void 0 : request.operation;
1059
- if (kind === void 0) return yield* new HostToolNotFound();
1060
- const name = request.operation === "call" ? request.tool.slice(OperationToolPrefixes[kind].length) : request.name;
1061
- const toolName = `${OperationToolPrefixes[kind]}${name}`;
1062
- const catalog = kind === "query" ? definition.queries : definition.mutations;
1063
- const declaredTool = catalog !== void 0 && Object.hasOwn(catalog, name) ? catalog[name] : void 0;
1064
- const source = definition.dynamicTools;
1065
- const resolvedTool = source === void 0 || declaredTool !== void 0 ? void 0 : yield* evaluationSafe(source.resolve(toolName));
1066
- const tool = declaredTool ?? resolvedTool;
1067
- if (tool !== void 0 && tool.kind !== (kind === "query" ? "query" : "mutation"))
1068
- return yield* new HostDeclarationInvalid();
1006
+ const toolName = request.operation === "call" ? request.tool : request.name;
1007
+ const location = locate(definition.tools, toolName);
1008
+ const tool = location === void 0 ? void 0 : location.kind === "operation" ? location.operation : yield* evaluationSafe(location.source.resolve(location.name), secrets);
1069
1009
  if (tool === void 0)
1070
1010
  return yield* request.operation === "call" ? new HostToolNotFound() : new HostOperationNotFound();
1011
+ const requested = request.operation === "call" ? request.kind : request.operation === "query" ? "query" : "mutation";
1012
+ if (requested !== void 0 && tool.kind !== requested)
1013
+ return yield* new HostKindMismatch({ tool: toolName, requested, actual: tool.kind });
1014
+ const kind = tool.kind === "query" ? "query" : "mutate";
1071
1015
  const input = yield* Effect_exports.suspend(
1072
1016
  () => Schema_exports.decodeUnknownEffect(tool.input)(request.input)
1073
1017
  ).pipe(
@@ -1121,7 +1065,7 @@ function dispatch(app, request, context, signal) {
1121
1065
  transactionOpen = db !== void 0;
1122
1066
  const output = yield* Effect_exports.gen(function* () {
1123
1067
  running = yield* captureTelemetry;
1124
- const fetch = yield* invocationFetch(invocationSignal);
1068
+ const fetch = yield* invocationFetch(fetching.signal);
1125
1069
  return yield* tool.run(
1126
1070
  {
1127
1071
  ...bound,
@@ -1156,7 +1100,7 @@ function dispatch(app, request, context, signal) {
1156
1100
  status: response.value.status,
1157
1101
  message: response.value.message,
1158
1102
  ...response.value.recovery === void 0 ? {} : { recovery: response.value.recovery }
1159
- }) : Option_exports.isSome(failure) ? failure.value : new HostOperationFailed()
1103
+ }) : Option_exports.isSome(failure) ? failure.value : new HostOperationFailed(failureDetail(error, secrets))
1160
1104
  );
1161
1105
  }),
1162
1106
  Effect_exports.withSpan("app.operation.execute", {
@@ -1187,14 +1131,55 @@ function dispatch(app, request, context, signal) {
1187
1131
  )
1188
1132
  ).pipe(
1189
1133
  Effect_exports.catchTags({
1190
- AppDatabaseError: () => Effect_exports.fail(new HostOperationFailed()),
1191
- AppStorageUnavailable: () => Effect_exports.fail(new HostOperationFailed()),
1192
- AppStorageError: () => Effect_exports.fail(new HostOperationFailed())
1134
+ AppDatabaseError: storageFailure,
1135
+ DatabaseLimitExceeded: (error) => Effect_exports.fail(error),
1136
+ AppStorageUnavailable: storageFailure,
1137
+ AppStorageError: storageFailure
1193
1138
  })
1194
1139
  );
1195
1140
  })
1196
1141
  );
1197
1142
  }
1143
+ function checkAccount(slots, declared, requirement, context, signal) {
1144
+ return Effect_exports.gen(function* () {
1145
+ const selection = Object.hasOwn(slots, requirement) ? slots[requirement] : void 0;
1146
+ const slot = Object.hasOwn(declared.accounts, requirement) ? declared.accounts[requirement] : void 0;
1147
+ if (selection === void 0 || slot === void 0) return yield* new HostAccountsInvalid();
1148
+ const provider = selection instanceof ManyAccounts ? selection.provider : selection;
1149
+ const health = provider.health;
1150
+ if (health === void 0) return yield* new HostOperationNotFound();
1151
+ const { accounts } = yield* bindAccounts(
1152
+ { [requirement]: provider },
1153
+ { accounts: { [requirement]: { ...slot, cardinality: "one" } } },
1154
+ context
1155
+ ).pipe(Effect_exports.withSpan("app.accounts.bind"));
1156
+ const account = accounts[requirement];
1157
+ if (account === void 0 || !("id" in account)) return yield* new HostAccountsInvalid();
1158
+ const result = yield* Effect_exports.suspend(
1159
+ () => Effect_exports.gen(function* () {
1160
+ return yield* health.run({ account, fetch: yield* invocationFetch(signal), signal });
1161
+ })
1162
+ ).pipe(
1163
+ Effect_exports.catchCause((cause) => {
1164
+ if (Cause_exports.hasInterrupts(cause)) return Effect_exports.interrupt;
1165
+ const error = Cause_exports.squash(cause);
1166
+ const status = Schema_exports.decodeUnknownOption(ResponseStatusError)(error);
1167
+ const classified = Option_exports.isSome(status) ? Option_exports.fromNullishOr(httpProviderError(status.value.status)) : parseProviderError(error);
1168
+ return Effect_exports.fail(
1169
+ Option_exports.isSome(classified) ? accountProviderError(classified.value, account.id) : new HostOperationFailed()
1170
+ );
1171
+ }),
1172
+ Effect_exports.withSpan("app.account.check")
1173
+ );
1174
+ return yield* safe2(
1175
+ () => Schema_exports.decodeUnknownEffect(AccountCheckResult)(result ?? {}).pipe(
1176
+ Effect_exports.flatMap(Schema_exports.encodeEffect(AccountCheckResult)),
1177
+ Effect_exports.flatMap(Schema_exports.decodeUnknownEffect(JsonValue))
1178
+ ),
1179
+ new HostOutputInvalid()
1180
+ );
1181
+ });
1182
+ }
1198
1183
  var parseSkillLoadFailed = (error) => Schema_exports.decodeUnknownOption(SkillLoadFailed)(error).pipe(
1199
1184
  Option_exports.map(
1200
1185
  ({ reason, message, status }) => new SkillLoadFailed({
@@ -1220,11 +1205,14 @@ var errorStatus = Match_exports.type().pipe(
1220
1205
  HostAccountsInvalid: () => 422,
1221
1206
  HostInputInvalid: () => 422,
1222
1207
  HostOperationNotFound: () => 404,
1208
+ HostKindMismatch: () => 409,
1223
1209
  HostToolNotFound: () => 404,
1224
1210
  HostToolBlocked: () => 403,
1225
1211
  HostToolApprovalRequired: () => 409,
1226
1212
  HostToolPolicyFailed: () => 500,
1227
1213
  HostOperationFailed: () => 500,
1214
+ DatabaseLimitExceeded: () => 422,
1215
+ DatabaseFieldReserved: () => 422,
1228
1216
  HostDeclarationInvalid: () => 500,
1229
1217
  HostEvaluationFailed: () => 500,
1230
1218
  HostOutputInvalid: () => 500,
@@ -1270,12 +1258,17 @@ var createAppHandler = (app) => (request, context) => Effect_exports.gen(functio
1270
1258
  ),
1271
1259
  Effect_exports.catchCause(
1272
1260
  (cause) => Cause_exports.hasInterrupts(cause) ? Effect_exports.interrupt : Effect_exports.logError(cause).pipe(
1273
- Effect_exports.as(
1274
- Response.json(
1275
- { ok: false, error: { _tag: "HostDeclarationInvalid" } },
1276
- { status: 500 }
1261
+ Effect_exports.andThen(
1262
+ Schema_exports.encodeEffect(HostError)(
1263
+ declarationInvalid(
1264
+ "The app failed while it was loaded",
1265
+ Cause_exports.squash(cause),
1266
+ accountSecrets(context.accounts)
1267
+ )
1277
1268
  )
1278
- )
1269
+ ),
1270
+ Effect_exports.map((error) => Response.json({ ok: false, error }, { status: 500 })),
1271
+ Effect_exports.orDie
1279
1272
  )
1280
1273
  )
1281
1274
  );
@@ -1283,6 +1276,5 @@ var createAppHandler = (app) => (request, context) => Effect_exports.gen(functio
1283
1276
  export {
1284
1277
  prepareElicitation,
1285
1278
  ApprovalDecision,
1286
- cacheKey,
1287
1279
  createAppHandler
1288
1280
  };