apps 0.0.1-beta.4 → 0.0.1-beta.6

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 (96) hide show
  1. package/README.md +65 -43
  2. package/framework-reference.json +1 -1
  3. package/js/{chunk-SATWJKN6.js → chunk-27F7W2LG.js} +1 -1
  4. package/js/{chunk-HDJH3RPR.js → chunk-57RKNWL2.js} +2 -2
  5. package/js/{chunk-WFSQXYUT.js → chunk-5T57N25Q.js} +15 -3
  6. package/js/{chunk-EQB7JMAL.js → chunk-6BSSI67S.js} +8 -8
  7. package/js/{chunk-3M2MEDNL.js → chunk-B3EOZTK3.js} +351 -33
  8. package/js/{chunk-FW5HBOIK.js → chunk-CDL5PM2Q.js} +307 -169
  9. package/js/{chunk-Z5NMEGJN.js → chunk-ECQFRCH4.js} +21 -9
  10. package/js/{chunk-G7ZIRKMK.js → chunk-IJX4CYZO.js} +3 -3
  11. package/js/{chunk-FDNTX5QJ.js → chunk-IPI4MFSN.js} +2 -2
  12. package/js/{chunk-2VPJHFOU.js → chunk-ITM77QPO.js} +28 -9
  13. package/js/{chunk-YEJOQEII.js → chunk-JU7VHODU.js} +1 -1
  14. package/js/{chunk-NQ3OMCA5.js → chunk-KUMBKVJD.js} +2 -2
  15. package/js/{chunk-EVJUVWN2.js → chunk-M3B3DE4K.js} +2 -2
  16. package/js/{chunk-ZJWDMTE3.js → chunk-MKWZPDR6.js} +3 -3
  17. package/js/chunk-MNMNLXBL.js +507 -0
  18. package/js/{chunk-BMOIAIVR.js → chunk-N7YDVXYJ.js} +49 -1
  19. package/js/{chunk-D47C7KG5.js → chunk-NKLWZJLE.js} +2 -2
  20. package/js/{chunk-DHUDODG5.js → chunk-OE3QQTSB.js} +41 -32
  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-LGIYBDWA.js → chunk-R3EV5FTO.js} +13 -1
  24. package/js/{chunk-5MQZEB6Y.js → chunk-RFVIONFX.js} +29 -12
  25. package/js/{chunk-ZCAMUXSG.js → chunk-RJDDBDSN.js} +3 -3
  26. package/js/{chunk-6VRYO2BG.js → chunk-SB4HEPNJ.js} +191 -170
  27. package/js/chunk-T7GKZBLP.js +209 -0
  28. package/js/{chunk-QKHR7BMF.js → chunk-UK573G7W.js} +1 -1
  29. package/js/{chunk-T2LAZCAD.js → chunk-VFZKSM3T.js} +1 -1
  30. package/js/{chunk-PLCMJREA.js → chunk-ZQINWV4W.js} +60 -20
  31. package/js/client.js +10 -10
  32. package/js/contracts.js +52 -16
  33. package/js/effect.js +19 -20
  34. package/js/graphql.js +34 -40
  35. package/js/host.js +19 -20
  36. package/js/index.js +189 -178
  37. package/js/mcp/effect.js +21 -22
  38. package/js/mcp/stdio.js +25 -26
  39. package/js/mcp.js +60 -45
  40. package/js/openapi.js +182 -224
  41. package/js/react.js +3 -3
  42. package/js/skills/effect.js +3 -3
  43. package/js/skills.js +12 -13
  44. package/js/storage/facet.js +4 -4
  45. package/js/ui/auth/contracts.js +2 -2
  46. package/js/ui/auth.js +5 -5
  47. package/js/ui/contracts.js +4 -4
  48. package/js/ui/serving.js +8 -8
  49. package/package.json +1 -1
  50. package/runtime.json +1 -1
  51. package/types/app-data/src/contracts/database.d.ts +33 -6
  52. package/types/app-data/src/implementation/schema.d.ts +2 -17
  53. package/types/apps/src/contracts/app.d.ts +2 -5
  54. package/types/apps/src/contracts/failure.d.ts +25 -0
  55. package/types/apps/src/contracts/host.d.ts +18 -9
  56. package/types/apps/src/contracts/mcp.d.ts +16 -0
  57. package/types/apps/src/contracts/openapi.d.ts +5 -1
  58. package/types/apps/src/contracts/operations.d.ts +0 -5
  59. package/types/apps/src/contracts/protocol-version.d.ts +2 -2
  60. package/types/apps/src/contracts/protocols/1.d.ts +15 -1
  61. package/types/apps/src/contracts/protocols/2.d.ts +2 -2
  62. package/types/apps/src/contracts/protocols/3.d.ts +676 -0
  63. package/types/apps/src/contracts/protocols/4.d.ts +1229 -0
  64. package/types/apps/src/contracts/router.d.ts +59 -0
  65. package/types/apps/src/contracts/storage.d.ts +3 -3
  66. package/types/apps/src/contracts/workflows.d.ts +34 -3
  67. package/types/apps/src/graphql.d.ts +1 -3
  68. package/types/apps/src/implementation/account-router.d.ts +12 -0
  69. package/types/apps/src/implementation/app.d.ts +5 -4
  70. package/types/apps/src/implementation/catalog-cache.d.ts +9 -2
  71. package/types/apps/src/implementation/elicitation.d.ts +1 -1
  72. package/types/apps/src/implementation/failure-detail.d.ts +25 -0
  73. package/types/apps/src/implementation/graphql-catalog.d.ts +1 -4
  74. package/types/apps/src/implementation/mcp-catalog.d.ts +1 -4
  75. package/types/apps/src/implementation/mcp-client.d.ts +35 -19
  76. package/types/apps/src/implementation/mcp.d.ts +35 -19
  77. package/types/apps/src/implementation/openapi-compile.d.ts +2 -1
  78. package/types/apps/src/implementation/openapi-source.d.ts +2 -6
  79. package/types/apps/src/implementation/operations.d.ts +26 -3
  80. package/types/apps/src/implementation/protocol-operations.d.ts +3 -4
  81. package/types/apps/src/implementation/router-catalog.d.ts +225 -0
  82. package/types/apps/src/implementation/router.d.ts +59 -0
  83. package/types/apps/src/implementation/schema.d.ts +5 -1
  84. package/types/apps/src/implementation/storage.d.ts +5 -3
  85. package/types/apps/src/implementation/webhooks.d.ts +1 -1
  86. package/types/apps/src/implementation/workflow-context.d.ts +11 -3
  87. package/types/apps/src/index.d.ts +3 -2
  88. package/types/apps/src/mcp-stdio.d.ts +2 -5
  89. package/types/apps/src/mcp.d.ts +5 -4
  90. package/types/apps/src/openapi.d.ts +6 -6
  91. package/js/chunk-PYUYJRSK.js +0 -93
  92. package/js/chunk-SWPD52J7.js +0 -35
  93. package/js/chunk-W7D7WVSY.js +0 -18
  94. package/types/apps/src/contracts/dynamic-tools.d.ts +0 -13
  95. package/types/apps/src/implementation/account-operations.d.ts +0 -151
  96. package/types/apps/src/implementation/dynamic-tools.d.ts +0 -8
@@ -1,23 +1,36 @@
1
1
  import {
2
2
  makeCache
3
- } from "./chunk-D47C7KG5.js";
3
+ } from "./chunk-NKLWZJLE.js";
4
+ import {
5
+ accountSecrets,
6
+ boundFailureMessage,
7
+ describeFailure,
8
+ failureDetail,
9
+ readCatalog,
10
+ routerSkills
11
+ } from "./chunk-MNMNLXBL.js";
4
12
  import {
5
13
  folderSkillsEffect
6
- } from "./chunk-FDNTX5QJ.js";
14
+ } from "./chunk-IPI4MFSN.js";
7
15
  import {
8
16
  authorDatabase,
9
17
  isApp,
10
18
  toEffectApp,
11
19
  unavailableStorage
12
- } from "./chunk-DHUDODG5.js";
20
+ } from "./chunk-OE3QQTSB.js";
21
+ import {
22
+ parseDatabaseSchema
23
+ } from "./chunk-ZQINWV4W.js";
13
24
  import {
25
+ declaredOperations,
14
26
  fromPromise,
27
+ locate,
15
28
  nativeOperation,
16
29
  toPromise
17
- } from "./chunk-PYUYJRSK.js";
30
+ } from "./chunk-T7GKZBLP.js";
18
31
  import {
19
32
  parseProviderError
20
- } from "./chunk-ZJWDMTE3.js";
33
+ } from "./chunk-MKWZPDR6.js";
21
34
  import {
22
35
  DeclaredProvider,
23
36
  DeclaredRequirements,
@@ -29,6 +42,7 @@ import {
29
42
  HostError,
30
43
  HostEvaluationFailed,
31
44
  HostInputInvalid,
45
+ HostKindMismatch,
32
46
  HostOperationFailed,
33
47
  HostOperationNotFound,
34
48
  HostOutputInvalid,
@@ -38,6 +52,7 @@ import {
38
52
  HostToolBlocked,
39
53
  HostToolNotFound,
40
54
  HostToolPolicyFailed,
55
+ HostedRouter,
41
56
  HostedTool,
42
57
  HostedToolSummary,
43
58
  HostedWebhook,
@@ -47,7 +62,7 @@ import {
47
62
  ManyAccounts,
48
63
  McpError,
49
64
  NonRetryableError,
50
- OperationToolPrefixes,
65
+ OpenapiResponseError,
51
66
  ResolvedAccounts,
52
67
  ToolResultObservation,
53
68
  TrustedToolApproval,
@@ -62,31 +77,29 @@ import {
62
77
  defaultWebhookTransportLimits,
63
78
  maxInputProblems,
64
79
  workflowDurationMillis
65
- } from "./chunk-3M2MEDNL.js";
80
+ } from "./chunk-B3EOZTK3.js";
66
81
  import {
67
82
  CacheError
68
- } from "./chunk-LGIYBDWA.js";
83
+ } from "./chunk-R3EV5FTO.js";
69
84
  import {
70
85
  AppSkills,
71
86
  SkillFile,
72
87
  SkillLoadFailed
73
- } from "./chunk-YEJOQEII.js";
74
- import {
75
- OpenapiResponseError
76
- } from "./chunk-SWPD52J7.js";
88
+ } from "./chunk-JU7VHODU.js";
77
89
  import {
78
90
  captureTelemetry,
79
91
  invocationFetch
80
- } from "./chunk-ZCAMUXSG.js";
92
+ } from "./chunk-RJDDBDSN.js";
81
93
  import {
82
94
  decoderOf,
83
95
  importedJsonSchema,
84
- jsonSchemaDecoder
85
- } from "./chunk-WFSQXYUT.js";
96
+ jsonSchemaDecoder,
97
+ jsonSchemaDocument
98
+ } from "./chunk-5T57N25Q.js";
86
99
  import {
87
100
  JsonObject,
88
101
  JsonValue
89
- } from "./chunk-SATWJKN6.js";
102
+ } from "./chunk-27F7W2LG.js";
90
103
  import {
91
104
  Cause_exports,
92
105
  Clock_exports,
@@ -98,7 +111,7 @@ import {
98
111
  SchemaIssue_exports,
99
112
  Schema_exports,
100
113
  Stream_exports
101
- } from "./chunk-FW5HBOIK.js";
114
+ } from "./chunk-CDL5PM2Q.js";
102
115
 
103
116
  // src/implementation/elicitation.ts
104
117
  var prepareElicitation = (input) => Effect_exports.gen(function* () {
@@ -139,19 +152,29 @@ var makeElicit = (handler, signal) => toPromise(
139
152
  var ApprovalDecision = Schema_exports.Literals(["approved", "denied", "user-approval"]);
140
153
 
141
154
  // src/implementation/workflow-context.ts
142
- var workflowSafe = (work) => work.pipe(
155
+ var workflowSafe = (work, secrets) => work.pipe(
143
156
  Effect_exports.catchCause((cause) => {
144
157
  if (Cause_exports.hasInterrupts(cause)) return Effect_exports.interrupt;
145
158
  const error = Cause_exports.squash(cause);
146
159
  if (Schema_exports.is(WorkflowFailure)(error)) return Effect_exports.fail(error);
160
+ const { errorName, message } = failureDetail(error, secrets);
147
161
  return Effect_exports.fail(
148
162
  new WorkflowFailure({
149
163
  reason: "execution",
150
- retryable: !(error instanceof NonRetryableError)
164
+ retryable: !(error instanceof NonRetryableError),
165
+ ...errorName === void 0 ? {} : { errorName },
166
+ ...message === void 0 ? {} : { message }
151
167
  })
152
168
  );
153
169
  })
154
170
  );
171
+ var inStep = (step) => (failure) => failure.step === void 0 ? new WorkflowFailure({
172
+ reason: failure.reason,
173
+ retryable: failure.retryable,
174
+ step: step.slice(0, 200),
175
+ ...failure.errorName === void 0 ? {} : { errorName: failure.errorName },
176
+ ...failure.message.length === 0 ? {} : { message: failure.message }
177
+ }) : failure;
155
178
  var makeWorkflowContext = (execution, definition, fresh, signal) => Effect_exports.gen(function* () {
156
179
  const services = yield* Effect_exports.context();
157
180
  const counts = /* @__PURE__ */ new Map();
@@ -206,25 +229,33 @@ var makeWorkflowContext = (execution, definition, fresh, signal) => Effect_expor
206
229
  Effect_exports.sync(() => new AbortController()),
207
230
  (controller2) => Effect_exports.sync(() => controller2.abort())
208
231
  );
209
- const ctx = yield* fresh(stepId, AbortSignal.any([signal, controller.signal]));
232
+ const step2 = yield* fresh(stepId, AbortSignal.any([signal, controller.signal]));
210
233
  const result = yield* workflowSafe(
211
- Effect_exports.tryPromise({ try: () => callback(ctx), catch: (error) => error })
234
+ Effect_exports.tryPromise({
235
+ try: () => callback(step2.context),
236
+ catch: (error) => error
237
+ }),
238
+ step2.secrets
212
239
  );
213
240
  return yield* Schema_exports.decodeUnknownEffect(WorkflowValue)(result).pipe(
214
241
  Effect_exports.mapError(
215
- () => new WorkflowFailure({ reason: "output", retryable: false })
242
+ () => new WorkflowFailure({
243
+ reason: "output",
244
+ retryable: false,
245
+ message: "The step returned a value that is not JSON, such as undefined, or is larger than 1 MiB. Return null for no result."
246
+ })
216
247
  )
217
248
  );
218
249
  })
219
250
  ).pipe(Effect_exports.provideContext(services))
220
251
  )
221
- );
252
+ ).pipe(Effect_exports.mapError(inStep(name)));
222
253
  });
223
254
  const operationStep = (kind, name, operation, input, options) => Effect_exports.gen(function* () {
224
255
  const target = nativeOperation(operation);
225
- const catalog = kind === "query" ? definition.queries : definition.mutations;
226
- const match = Object.entries(catalog ?? {}).find(
227
- ([, value]) => value === target && value.kind === kind
256
+ const root = definition.tools?.kind === "router" ? definition.tools : void 0;
257
+ const match = declaredOperations(root).find(
258
+ (entry) => entry.operation === target && entry.operation.kind === kind
228
259
  );
229
260
  if (target === void 0 || match === void 0)
230
261
  return yield* new WorkflowFailure({ reason: "operation", retryable: false });
@@ -243,9 +274,9 @@ var makeWorkflowContext = (execution, definition, fresh, signal) => Effect_expor
243
274
  parsed,
244
275
  () => attempt(
245
276
  parsed,
246
- execution.invoke({ kind, name: match[0], input: args, stepId, timeout }).pipe(Effect_exports.provideContext(services))
277
+ execution.invoke({ kind, name: match.name, input: args, stepId, timeout }).pipe(Effect_exports.provideContext(services))
247
278
  )
248
- );
279
+ ).pipe(Effect_exports.mapError(inStep(name)));
249
280
  });
250
281
  const invoke = (effect) => toPromise(() => effect.pipe(Effect_exports.provideContext(services)), signal)();
251
282
  const step = {
@@ -523,6 +554,10 @@ var authorCache = (host, accounts, signal, deadline) => {
523
554
  };
524
555
 
525
556
  // src/implementation/host.ts
557
+ var WireCatalog = Schema_exports.Struct({
558
+ tools: Schema_exports.Array(Schema_exports.Union([HostedTool, HostedToolSummary])),
559
+ routers: Schema_exports.Array(HostedRouter)
560
+ });
526
561
  function safe2(work, failure) {
527
562
  return Effect_exports.suspend(work).pipe(
528
563
  Effect_exports.catchCause(
@@ -530,7 +565,7 @@ function safe2(work, failure) {
530
565
  )
531
566
  );
532
567
  }
533
- var evaluationSafe = (work) => work.pipe(
568
+ var evaluationSafe = (work, secrets) => work.pipe(
534
569
  Effect_exports.catchCause((cause) => {
535
570
  if (Cause_exports.hasInterrupts(cause)) return Effect_exports.interrupt;
536
571
  const error = Cause_exports.squash(cause);
@@ -538,22 +573,25 @@ var evaluationSafe = (work) => work.pipe(
538
573
  const skills = parseSkillLoadFailed(error);
539
574
  const mcp = parseMcpError(error);
540
575
  return Effect_exports.fail(
541
- Option_exports.isSome(provider) ? provider.value : Option_exports.isSome(skills) ? skills.value : Option_exports.isSome(mcp) ? mcp.value : new HostEvaluationFailed()
576
+ Option_exports.isSome(provider) ? provider.value : Option_exports.isSome(skills) ? skills.value : Option_exports.isSome(mcp) ? mcp.value : new HostEvaluationFailed(failureDetail(error, secrets))
542
577
  );
543
578
  })
544
579
  );
545
- function jsonSchema(decoder) {
546
- const imported = importedJsonSchema(decoder);
547
- if (imported !== void 0) return Schema_exports.decodeUnknownEffect(JsonObject)(imported);
548
- const document = Schema_exports.toJsonSchemaDocument(decoder);
549
- return Schema_exports.decodeUnknownEffect(JsonObject)({
550
- ...document.schema,
551
- $defs: document.definitions,
552
- $schema: "https://json-schema.org/draft/2020-12/schema"
553
- });
554
- }
580
+ var declarationInvalid = (summary, cause, secrets = []) => new HostDeclarationInvalid({
581
+ source: "app",
582
+ errorName: "HostDeclarationInvalid",
583
+ message: boundFailureMessage(
584
+ cause === void 0 ? summary : `${summary}: ${describeFailure(cause)}`,
585
+ secrets
586
+ )
587
+ });
588
+ var declarationSafe = (work, summary) => Effect_exports.suspend(work).pipe(
589
+ Effect_exports.catchCause(
590
+ (cause) => Cause_exports.hasInterrupts(cause) ? Effect_exports.interrupt : Effect_exports.fail(declarationInvalid(summary, Cause_exports.squash(cause)))
591
+ )
592
+ );
555
593
  function providerDeclaration(provider) {
556
- return safe2(
594
+ return declarationSafe(
557
595
  () => Effect_exports.gen(function* () {
558
596
  const auth = /* @__PURE__ */ new Map();
559
597
  for (const [name, method] of Object.entries(provider.auth)) {
@@ -562,14 +600,14 @@ function providerDeclaration(provider) {
562
600
  auth.set(name, {
563
601
  type: "secrets",
564
602
  label: method.label,
565
- fields: yield* jsonSchema(method.fields)
603
+ fields: yield* jsonSchemaDocument(method.fields)
566
604
  });
567
605
  break;
568
606
  case "oauth2":
569
607
  auth.set(name, {
570
608
  type: "oauth2",
571
609
  ...method.config,
572
- response: yield* jsonSchema(method.response)
610
+ response: yield* jsonSchemaDocument(method.response)
573
611
  });
574
612
  break;
575
613
  }
@@ -579,7 +617,7 @@ function providerDeclaration(provider) {
579
617
  auth: Object.fromEntries(auth)
580
618
  });
581
619
  }),
582
- new HostDeclarationInvalid()
620
+ `Account provider "${provider.name}" has an invalid declaration`
583
621
  );
584
622
  }
585
623
  function requirements(slots, database) {
@@ -597,7 +635,11 @@ function requirements(slots, database) {
597
635
  accounts: Object.fromEntries(accounts),
598
636
  capabilities: { skills: true, toolIndex: true, skillSources: true, scheduledTools: true },
599
637
  ...database === void 0 ? {} : { database }
600
- }).pipe(Effect_exports.mapError(() => new HostDeclarationInvalid()));
638
+ }).pipe(
639
+ Effect_exports.mapError(
640
+ (cause) => declarationInvalid("The app's account or database declarations are invalid", cause)
641
+ )
642
+ );
601
643
  });
602
644
  }
603
645
  function canonical(value) {
@@ -656,14 +698,29 @@ function bindAccounts(slots, declarations, context) {
656
698
  function dispatch(app, request, context, signal) {
657
699
  return Effect_exports.scoped(
658
700
  Effect_exports.gen(function* () {
659
- if (!isApp(app)) return yield* Effect_exports.fail(new HostDeclarationInvalid());
701
+ if (!isApp(app))
702
+ return yield* Effect_exports.fail(
703
+ declarationInvalid("The app module's default export is not an app created by defineApp")
704
+ );
660
705
  const native = toEffectApp(app);
706
+ const secrets = accountSecrets(context.accounts);
707
+ const storageFailure = (error) => Effect_exports.fail(new HostOperationFailed(failureDetail(error, secrets)));
661
708
  const declared = yield* requirements(native.accounts, native.database?.schema);
662
- if (request.operation === "requirements")
709
+ if (request.operation === "requirements") {
710
+ if (native.database !== void 0)
711
+ yield* parseDatabaseSchema(native.database.schema).pipe(
712
+ Effect_exports.catchTag(
713
+ "AppDatabaseError",
714
+ (cause) => Effect_exports.fail(
715
+ declarationInvalid("The app's account or database declarations are invalid", cause)
716
+ )
717
+ )
718
+ );
663
719
  return yield* safe2(
664
720
  () => Schema_exports.decodeUnknownEffect(JsonValue)(declared),
665
721
  new HostDeclarationInvalid()
666
722
  );
723
+ }
667
724
  const lifetime = yield* Effect_exports.acquireRelease(
668
725
  Effect_exports.sync(() => new AbortController()),
669
726
  (controller) => Effect_exports.sync(() => controller.abort())
@@ -747,34 +804,40 @@ function dispatch(app, request, context, signal) {
747
804
  fetch: yield* invocationFetch(invocationSignal),
748
805
  elicit: makeElicit(delivery, invocationSignal)
749
806
  };
750
- const definition = yield* evaluationSafe(native.evaluate(bound)).pipe(
807
+ const definition = yield* evaluationSafe(native.evaluate(bound), secrets).pipe(
751
808
  Effect_exports.withSpan("app.evaluate")
752
809
  );
753
810
  if (request.operation === "skills") {
754
811
  const declared2 = definition.skills ?? (yield* folderSkillsEffect({ files }).pipe(
755
812
  Effect_exports.mapError(() => new HostDeclarationInvalid())
756
813
  ));
757
- const source2 = definition.dynamicSkills;
814
+ const source = definition.dynamicSkills;
758
815
  const before = cacheCommands;
759
- const dynamic = source2 === void 0 ? [] : yield* evaluationSafe(Effect_exports.suspend(source2.list)).pipe(
816
+ const dynamic = source === void 0 ? [] : yield* evaluationSafe(Effect_exports.suspend(source.list), secrets).pipe(
760
817
  Effect_exports.withSpan("app.skills.load")
761
818
  );
762
- const cached = source2 !== void 0 && cacheCommands > before;
763
- const skills = yield* Schema_exports.decodeUnknownEffect(AppSkills)([...declared2, ...dynamic]).pipe(
764
- Effect_exports.mapError(() => new HostDeclarationInvalid())
765
- );
766
- return request.sources === true ? { skills, dynamic: source2 !== void 0, cached } : skills;
819
+ const cached = source !== void 0 && cacheCommands > before;
820
+ const authored = new Set([...declared2, ...dynamic].map((skill) => skill.name));
821
+ const routed = (yield* routerSkills(definition.tools).pipe(
822
+ Effect_exports.withSpan("app.skills.routers")
823
+ )).filter((skill) => !authored.has(skill.name));
824
+ const skills = yield* Schema_exports.decodeUnknownEffect(AppSkills)([
825
+ ...declared2,
826
+ ...dynamic,
827
+ ...routed
828
+ ]).pipe(Effect_exports.mapError(() => new HostDeclarationInvalid()));
829
+ return request.sources === true ? { skills, dynamic: source !== void 0, cached } : skills;
767
830
  }
768
831
  if (request.operation === "workflows") {
769
832
  return yield* Effect_exports.forEach(
770
833
  Object.entries(definition.workflows ?? {}),
771
- ([name2, entry]) => safe2(
834
+ ([name, entry]) => safe2(
772
835
  () => Effect_exports.gen(function* () {
773
836
  return yield* Schema_exports.decodeUnknownEffect(HostedWorkflow)({
774
- name: name2,
837
+ name,
775
838
  ...entry.description === void 0 ? {} : { description: entry.description },
776
- inputSchema: yield* jsonSchema(entry.input),
777
- ...entry.output === void 0 ? {} : { outputSchema: yield* jsonSchema(entry.output) }
839
+ inputSchema: yield* jsonSchemaDocument(entry.input),
840
+ ...entry.output === void 0 ? {} : { outputSchema: yield* jsonSchemaDocument(entry.output) }
778
841
  });
779
842
  }),
780
843
  new HostDeclarationInvalid()
@@ -807,108 +870,60 @@ function dispatch(app, request, context, signal) {
807
870
  new WorkflowFailure({ reason: "credentials", retryable: false })
808
871
  );
809
872
  return {
810
- ...accounts,
811
- cache: authorCache(
812
- context.cache ?? unavailableCache,
813
- Redacted_exports.value(current.accounts),
814
- signal2
815
- ),
816
- files,
817
- fetch: yield* invocationFetch(signal2),
818
- signal: signal2,
819
- runId: execution.runId,
820
- stepId,
821
- idempotencyKey: stepId
873
+ context: {
874
+ ...accounts,
875
+ cache: authorCache(
876
+ context.cache ?? unavailableCache,
877
+ Redacted_exports.value(current.accounts),
878
+ signal2
879
+ ),
880
+ files,
881
+ fetch: yield* invocationFetch(signal2),
882
+ signal: signal2,
883
+ runId: execution.runId,
884
+ stepId,
885
+ idempotencyKey: stepId
886
+ },
887
+ // The resolved values, not the app's decoded fields, which may be `Redacted`.
888
+ secrets: accountSecrets(current.accounts)
822
889
  };
823
890
  }),
824
891
  invocationSignal
825
892
  );
826
- const output = yield* workflowSafe(entry.run(workflowContext, input2));
893
+ const output = yield* workflowSafe(entry.run(workflowContext, input2), secrets);
827
894
  const outputSchema = entry.output;
828
895
  const decoded = outputSchema === void 0 ? output : yield* safe2(
829
896
  () => Schema_exports.decodeUnknownEffect(outputSchema)(output),
830
- new WorkflowFailure({ reason: "output", retryable: false })
897
+ new WorkflowFailure({
898
+ reason: "output",
899
+ retryable: false,
900
+ message: "The workflow's result does not match its declared output schema."
901
+ })
831
902
  );
832
903
  return yield* safe2(
833
904
  () => Schema_exports.decodeUnknownEffect(WorkflowValue)(decoded),
834
- new WorkflowFailure({ reason: "output", retryable: false })
905
+ new WorkflowFailure({
906
+ reason: "output",
907
+ retryable: false,
908
+ message: "The workflow returned a value that is not JSON, such as undefined, or is larger than 1 MiB. Return null for no result."
909
+ })
835
910
  );
836
911
  }
837
912
  if (request.operation === "inspect") {
838
913
  const summary = request.detail === "summary";
839
- const wanted = request.tools === void 0 ? void 0 : new Set(request.tools);
840
- const metadata = [];
841
- for (const [prefix, readOnly, catalog2] of [
842
- [OperationToolPrefixes.query, true, definition.queries],
843
- [OperationToolPrefixes.mutate, false, definition.mutations]
844
- ]) {
845
- for (const [name2, operation] of Object.entries(catalog2 ?? {})) {
846
- if (wanted !== void 0 && !wanted.has(`${prefix}${name2}`)) continue;
847
- const schedules = Object.entries(definition.schedules ?? {}).filter(([, schedule]) => schedule.tool === `${prefix}${name2}`).map(([name3, { tool: _tool, ...schedule }]) => ({ name: name3, ...schedule }));
848
- if (request.scheduled === true && schedules.length === 0) continue;
849
- metadata.push(
850
- yield* safe2(
851
- () => Effect_exports.gen(function* () {
852
- const fields = {
853
- name: `${prefix}${name2}`,
854
- schedules,
855
- description: operation.description ?? `${readOnly ? "Query" : "Mutate"} ${name2}`,
856
- ...operation.title === void 0 ? {} : { title: operation.title },
857
- readOnly,
858
- annotations: { ...operation.annotations, readOnlyHint: readOnly }
859
- };
860
- if (summary)
861
- return yield* Schema_exports.decodeUnknownEffect(HostedToolSummary)(fields);
862
- return yield* Schema_exports.decodeUnknownEffect(HostedTool)({
863
- ...fields,
864
- inputSchema: yield* jsonSchema(operation.input),
865
- ...operation.output === void 0 ? operation.outputSchema === void 0 ? {} : { outputSchema: operation.outputSchema } : { outputSchema: yield* jsonSchema(operation.output) },
866
- ...operation._meta === void 0 ? {} : { _meta: operation._meta }
867
- });
868
- }),
869
- new HostDeclarationInvalid()
870
- )
871
- );
872
- }
873
- }
874
- const dynamic = request.scheduled === true ? void 0 : definition.dynamicTools;
875
- if (dynamic !== void 0 && (wanted === void 0 || metadata.length < wanted.size)) {
876
- const declared2 = new Set(metadata.map((tool2) => tool2.name));
877
- const discover = () => {
878
- if (summary && dynamic.summaries !== void 0) return dynamic.summaries();
879
- if (wanted !== void 0 && dynamic.describe !== void 0) {
880
- const describe = dynamic.describe;
881
- return Effect_exports.forEach(
882
- [...wanted].filter((name2) => !declared2.has(name2)),
883
- (name2) => describe(name2),
884
- { concurrency: "unbounded" }
885
- ).pipe(Effect_exports.map((tools) => tools.filter((tool2) => tool2 !== void 0)));
886
- }
887
- return dynamic.list();
888
- };
889
- const discovered = yield* evaluationSafe(discover()).pipe(
890
- Effect_exports.flatMap(
891
- (value) => safe2(
892
- () => summary ? Schema_exports.decodeUnknownEffect(Schema_exports.Array(HostedToolSummary))(value) : Schema_exports.decodeUnknownEffect(Schema_exports.Array(HostedTool))(value),
893
- new HostDeclarationInvalid()
894
- )
895
- )
896
- );
897
- const names = new Set(declared2);
898
- for (const tool2 of discovered) {
899
- const readOnly = tool2.name.startsWith(OperationToolPrefixes.query);
900
- if (!readOnly && !tool2.name.startsWith(OperationToolPrefixes.mutate) || tool2.name === OperationToolPrefixes.query || tool2.name === OperationToolPrefixes.mutate || names.has(tool2.name))
901
- return yield* new HostDeclarationInvalid();
902
- names.add(tool2.name);
903
- if (wanted !== void 0 && !wanted.has(tool2.name)) continue;
904
- metadata.push({
905
- ...tool2,
906
- readOnly,
907
- annotations: { ...tool2.annotations, readOnlyHint: readOnly }
908
- });
909
- }
910
- }
911
- return metadata;
914
+ const catalog = yield* readCatalog(definition.tools, {
915
+ summary,
916
+ secrets,
917
+ ...request.tools === void 0 ? {} : { wanted: new Set(request.tools) },
918
+ ...request.scheduled === true ? { scheduled: true } : {},
919
+ schedules: (name) => Object.entries(definition.schedules ?? {}).filter(([, schedule]) => schedule.tool === name).map(([name2, { tool: _tool, ...schedule }]) => ({ name: name2, ...schedule }))
920
+ }).pipe(Effect_exports.withSpan("app.catalog.read"));
921
+ return yield* safe2(
922
+ () => Schema_exports.encodeEffect(WireCatalog)(catalog).pipe(
923
+ Effect_exports.flatMap(Schema_exports.decodeUnknownEffect(JsonValue))
924
+ ),
925
+ new HostDeclarationInvalid()
926
+ );
912
927
  }
913
928
  if (request.operation === "webhook-complete" || request.operation === "webhook-validate" || request.operation === "webhooks" || request.operation === "webhook-register" || request.operation === "webhook-handle" || request.operation === "webhook-unregister") {
914
929
  const executeWebhook = (db) => dispatchWebhook(
@@ -932,25 +947,22 @@ function dispatch(app, request, context, signal) {
932
947
  const storage2 = context.storage ?? unavailableStorage;
933
948
  return yield* storage2.mutate(native.database.schema, executeWebhook).pipe(
934
949
  Effect_exports.catchTags({
935
- AppDatabaseError: () => Effect_exports.fail(new HostOperationFailed()),
936
- AppStorageUnavailable: () => Effect_exports.fail(new HostOperationFailed()),
937
- AppStorageError: () => Effect_exports.fail(new HostOperationFailed())
950
+ AppDatabaseError: storageFailure,
951
+ DatabaseLimitExceeded: (error) => Effect_exports.fail(error),
952
+ AppStorageUnavailable: storageFailure,
953
+ AppStorageError: storageFailure
938
954
  })
939
955
  );
940
956
  }
941
- const kind = request.operation === "call" ? request.tool.startsWith(OperationToolPrefixes.query) ? "query" : request.tool.startsWith(OperationToolPrefixes.mutate) ? "mutate" : void 0 : request.operation;
942
- if (kind === void 0) return yield* new HostToolNotFound();
943
- const name = request.operation === "call" ? request.tool.slice(OperationToolPrefixes[kind].length) : request.name;
944
- const toolName = `${OperationToolPrefixes[kind]}${name}`;
945
- const catalog = kind === "query" ? definition.queries : definition.mutations;
946
- const declaredTool = catalog !== void 0 && Object.hasOwn(catalog, name) ? catalog[name] : void 0;
947
- const source = definition.dynamicTools;
948
- const resolvedTool = source === void 0 || declaredTool !== void 0 ? void 0 : yield* evaluationSafe(source.resolve(toolName));
949
- const tool = declaredTool ?? resolvedTool;
950
- if (tool !== void 0 && tool.kind !== (kind === "query" ? "query" : "mutation"))
951
- return yield* new HostDeclarationInvalid();
957
+ const toolName = request.operation === "call" ? request.tool : request.name;
958
+ const location = locate(definition.tools, toolName);
959
+ const tool = location === void 0 ? void 0 : location.kind === "operation" ? location.operation : yield* evaluationSafe(location.source.resolve(location.name), secrets);
952
960
  if (tool === void 0)
953
961
  return yield* request.operation === "call" ? new HostToolNotFound() : new HostOperationNotFound();
962
+ const requested = request.operation === "call" ? request.kind : request.operation === "query" ? "query" : "mutation";
963
+ if (requested !== void 0 && tool.kind !== requested)
964
+ return yield* new HostKindMismatch({ tool: toolName, requested, actual: tool.kind });
965
+ const kind = tool.kind === "query" ? "query" : "mutate";
954
966
  const input = yield* Effect_exports.suspend(
955
967
  () => Schema_exports.decodeUnknownEffect(tool.input)(request.input)
956
968
  ).pipe(
@@ -1039,7 +1051,7 @@ function dispatch(app, request, context, signal) {
1039
1051
  status: response.value.status,
1040
1052
  message: response.value.message,
1041
1053
  ...response.value.recovery === void 0 ? {} : { recovery: response.value.recovery }
1042
- }) : Option_exports.isSome(failure) ? failure.value : new HostOperationFailed()
1054
+ }) : Option_exports.isSome(failure) ? failure.value : new HostOperationFailed(failureDetail(error, secrets))
1043
1055
  );
1044
1056
  }),
1045
1057
  Effect_exports.withSpan("app.operation.execute", {
@@ -1070,9 +1082,10 @@ function dispatch(app, request, context, signal) {
1070
1082
  )
1071
1083
  ).pipe(
1072
1084
  Effect_exports.catchTags({
1073
- AppDatabaseError: () => Effect_exports.fail(new HostOperationFailed()),
1074
- AppStorageUnavailable: () => Effect_exports.fail(new HostOperationFailed()),
1075
- AppStorageError: () => Effect_exports.fail(new HostOperationFailed())
1085
+ AppDatabaseError: storageFailure,
1086
+ DatabaseLimitExceeded: (error) => Effect_exports.fail(error),
1087
+ AppStorageUnavailable: storageFailure,
1088
+ AppStorageError: storageFailure
1076
1089
  })
1077
1090
  );
1078
1091
  })
@@ -1103,11 +1116,14 @@ var errorStatus = Match_exports.type().pipe(
1103
1116
  HostAccountsInvalid: () => 422,
1104
1117
  HostInputInvalid: () => 422,
1105
1118
  HostOperationNotFound: () => 404,
1119
+ HostKindMismatch: () => 409,
1106
1120
  HostToolNotFound: () => 404,
1107
1121
  HostToolBlocked: () => 403,
1108
1122
  HostToolApprovalRequired: () => 409,
1109
1123
  HostToolPolicyFailed: () => 500,
1110
1124
  HostOperationFailed: () => 500,
1125
+ DatabaseLimitExceeded: () => 422,
1126
+ DatabaseFieldReserved: () => 422,
1111
1127
  HostDeclarationInvalid: () => 500,
1112
1128
  HostEvaluationFailed: () => 500,
1113
1129
  HostOutputInvalid: () => 500,
@@ -1153,12 +1169,17 @@ var createAppHandler = (app) => (request, context) => Effect_exports.gen(functio
1153
1169
  ),
1154
1170
  Effect_exports.catchCause(
1155
1171
  (cause) => Cause_exports.hasInterrupts(cause) ? Effect_exports.interrupt : Effect_exports.logError(cause).pipe(
1156
- Effect_exports.as(
1157
- Response.json(
1158
- { ok: false, error: { _tag: "HostDeclarationInvalid" } },
1159
- { status: 500 }
1172
+ Effect_exports.andThen(
1173
+ Schema_exports.encodeEffect(HostError)(
1174
+ declarationInvalid(
1175
+ "The app failed while it was loaded",
1176
+ Cause_exports.squash(cause),
1177
+ accountSecrets(context.accounts)
1178
+ )
1160
1179
  )
1161
- )
1180
+ ),
1181
+ Effect_exports.map((error) => Response.json({ ok: false, error }, { status: 500 })),
1182
+ Effect_exports.orDie
1162
1183
  )
1163
1184
  )
1164
1185
  );