apps 0.0.1-beta.5 → 0.0.1-beta.7

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 (66) hide show
  1. package/README.md +65 -43
  2. package/framework-reference.json +1 -1
  3. package/js/{chunk-FWQC6I3C.js → chunk-5T57N25Q.js} +13 -1
  4. package/js/{chunk-TDNYXSIX.js → chunk-72JNVHPK.js} +21 -9
  5. package/js/{chunk-UDDE5KOR.js → chunk-CMYUWAX7.js} +26 -7
  6. package/js/chunk-FL2QR3XW.js +507 -0
  7. package/js/{chunk-G7T27IWB.js → chunk-MKWZPDR6.js} +1 -1
  8. package/js/{chunk-CYYBFC2K.js → chunk-NKLWZJLE.js} +1 -1
  9. package/js/{chunk-67EVWIGJ.js → chunk-OCYUEU47.js} +4 -4
  10. package/js/{chunk-YEPYT6SD.js → chunk-R3EV5FTO.js} +12 -0
  11. package/js/{chunk-XHO2ZX6W.js → chunk-RFVIONFX.js} +27 -10
  12. package/js/{chunk-LUVSFETN.js → chunk-UESPOTUI.js} +127 -231
  13. package/js/{chunk-DQAZTA4I.js → chunk-WLE7WX2U.js} +290 -20
  14. package/js/{chunk-C3VAOK5B.js → chunk-YXQHV65J.js} +53 -26
  15. package/js/chunk-Z5M2LQOZ.js +209 -0
  16. package/js/client.js +1 -1
  17. package/js/contracts.js +34 -11
  18. package/js/effect.js +9 -11
  19. package/js/graphql.js +25 -32
  20. package/js/host.js +9 -11
  21. package/js/index.js +194 -192
  22. package/js/mcp/effect.js +11 -13
  23. package/js/mcp/stdio.js +15 -17
  24. package/js/mcp.js +50 -36
  25. package/js/openapi.js +166 -108
  26. package/js/skills.js +6 -7
  27. package/package.json +1 -1
  28. package/runtime.json +1 -1
  29. package/types/apps/src/contracts/app.d.ts +2 -5
  30. package/types/apps/src/contracts/host.d.ts +19 -7
  31. package/types/apps/src/contracts/mcp.d.ts +16 -0
  32. package/types/apps/src/contracts/openapi.d.ts +4 -0
  33. package/types/apps/src/contracts/operations.d.ts +0 -5
  34. package/types/apps/src/contracts/protocol-version.d.ts +2 -2
  35. package/types/apps/src/contracts/protocols/4.d.ts +1229 -0
  36. package/types/apps/src/contracts/protocols/5.d.ts +1090 -0
  37. package/types/apps/src/contracts/provider.d.ts +51 -5
  38. package/types/apps/src/contracts/router.d.ts +59 -0
  39. package/types/apps/src/graphql.d.ts +1 -3
  40. package/types/apps/src/implementation/account-router.d.ts +12 -0
  41. package/types/apps/src/implementation/app.d.ts +5 -4
  42. package/types/apps/src/implementation/catalog-cache.d.ts +9 -2
  43. package/types/apps/src/implementation/graphql-catalog.d.ts +1 -4
  44. package/types/apps/src/implementation/mcp-catalog.d.ts +1 -4
  45. package/types/apps/src/implementation/mcp-client.d.ts +35 -19
  46. package/types/apps/src/implementation/mcp.d.ts +35 -19
  47. package/types/apps/src/implementation/openapi-compile.d.ts +2 -1
  48. package/types/apps/src/implementation/openapi-source.d.ts +2 -6
  49. package/types/apps/src/implementation/operations.d.ts +26 -3
  50. package/types/apps/src/implementation/protocol-operations.d.ts +3 -4
  51. package/types/apps/src/implementation/provider.d.ts +9 -4
  52. package/types/apps/src/implementation/router-catalog.d.ts +225 -0
  53. package/types/apps/src/implementation/router.d.ts +59 -0
  54. package/types/apps/src/implementation/schema.d.ts +5 -1
  55. package/types/apps/src/implementation/workflow-context.d.ts +1 -1
  56. package/types/apps/src/index.d.ts +5 -4
  57. package/types/apps/src/mcp-stdio.d.ts +2 -5
  58. package/types/apps/src/mcp.d.ts +5 -4
  59. package/types/apps/src/openapi.d.ts +6 -6
  60. package/js/chunk-3XKZDQLM.js +0 -93
  61. package/js/chunk-4M277YTM.js +0 -136
  62. package/js/chunk-SB3V4YVR.js +0 -18
  63. package/js/chunk-W4DMKWAB.js +0 -35
  64. package/types/apps/src/contracts/dynamic-tools.d.ts +0 -13
  65. package/types/apps/src/implementation/account-operations.d.ts +0 -151
  66. package/types/apps/src/implementation/dynamic-tools.d.ts +0 -8
@@ -1,30 +1,41 @@
1
1
  import {
2
2
  makeCache
3
- } from "./chunk-CYYBFC2K.js";
3
+ } from "./chunk-NKLWZJLE.js";
4
+ import {
5
+ accountSecrets,
6
+ boundFailureMessage,
7
+ describeFailure,
8
+ failureDetail,
9
+ readCatalog,
10
+ routerSkills
11
+ } from "./chunk-FL2QR3XW.js";
4
12
  import {
5
13
  folderSkillsEffect
6
14
  } from "./chunk-IPI4MFSN.js";
7
15
  import {
8
- OpenapiError
9
- } from "./chunk-4M277YTM.js";
10
- import {
16
+ ResponseStatusError,
11
17
  authorDatabase,
12
18
  isApp,
13
19
  toEffectApp,
14
20
  unavailableStorage
15
- } from "./chunk-C3VAOK5B.js";
21
+ } from "./chunk-YXQHV65J.js";
16
22
  import {
17
23
  parseDatabaseSchema
18
24
  } from "./chunk-ZQINWV4W.js";
19
25
  import {
26
+ declaredOperations,
20
27
  fromPromise,
28
+ locate,
21
29
  nativeOperation,
22
30
  toPromise
23
- } from "./chunk-3XKZDQLM.js";
31
+ } from "./chunk-Z5M2LQOZ.js";
24
32
  import {
33
+ accountProviderError,
34
+ httpProviderError,
25
35
  parseProviderError
26
- } from "./chunk-G7T27IWB.js";
36
+ } from "./chunk-MKWZPDR6.js";
27
37
  import {
38
+ AccountCheckResult,
28
39
  DeclaredProvider,
29
40
  DeclaredRequirements,
30
41
  ElicitationFailed,
@@ -35,6 +46,7 @@ import {
35
46
  HostError,
36
47
  HostEvaluationFailed,
37
48
  HostInputInvalid,
49
+ HostKindMismatch,
38
50
  HostOperationFailed,
39
51
  HostOperationNotFound,
40
52
  HostOutputInvalid,
@@ -44,6 +56,7 @@ import {
44
56
  HostToolBlocked,
45
57
  HostToolNotFound,
46
58
  HostToolPolicyFailed,
59
+ HostedRouter,
47
60
  HostedTool,
48
61
  HostedToolSummary,
49
62
  HostedWebhook,
@@ -53,7 +66,7 @@ import {
53
66
  ManyAccounts,
54
67
  McpError,
55
68
  NonRetryableError,
56
- OperationToolPrefixes,
69
+ OpenapiResponseError,
57
70
  ResolvedAccounts,
58
71
  ToolResultObservation,
59
72
  TrustedToolApproval,
@@ -66,24 +79,17 @@ import {
66
79
  WorkflowValue,
67
80
  approvalElicitation,
68
81
  defaultWebhookTransportLimits,
69
- maxFailureMessageLength,
70
82
  maxInputProblems,
71
83
  workflowDurationMillis
72
- } from "./chunk-DQAZTA4I.js";
73
- import {
74
- AppDatabaseError
75
- } from "./chunk-N7YDVXYJ.js";
84
+ } from "./chunk-WLE7WX2U.js";
76
85
  import {
77
86
  CacheError
78
- } from "./chunk-YEPYT6SD.js";
87
+ } from "./chunk-R3EV5FTO.js";
79
88
  import {
80
89
  AppSkills,
81
90
  SkillFile,
82
91
  SkillLoadFailed
83
92
  } from "./chunk-JU7VHODU.js";
84
- import {
85
- OpenapiResponseError
86
- } from "./chunk-W4DMKWAB.js";
87
93
  import {
88
94
  captureTelemetry,
89
95
  invocationFetch
@@ -91,12 +97,9 @@ import {
91
97
  import {
92
98
  decoderOf,
93
99
  importedJsonSchema,
94
- jsonSchemaDecoder
95
- } from "./chunk-FWQC6I3C.js";
96
- import {
97
- AppStorageError,
98
- AppStorageUnavailable
99
- } from "./chunk-PZB6T6KU.js";
100
+ jsonSchemaDecoder,
101
+ jsonSchemaDocument
102
+ } from "./chunk-5T57N25Q.js";
100
103
  import {
101
104
  JsonObject,
102
105
  JsonValue
@@ -108,7 +111,6 @@ import {
108
111
  Encoding_exports,
109
112
  Match_exports,
110
113
  Option_exports,
111
- Predicate_exports,
112
114
  Redacted_exports,
113
115
  SchemaIssue_exports,
114
116
  Schema_exports,
@@ -153,109 +155,18 @@ var makeElicit = (handler, signal) => toPromise(
153
155
  // src/contracts/approval.ts
154
156
  var ApprovalDecision = Schema_exports.Literals(["approved", "denied", "user-approval"]);
155
157
 
156
- // src/implementation/failure-detail.ts
157
- var storageMessages = {
158
- schema: "The app's database schema is invalid.",
159
- schema_changed: "The app's database schema changed during this operation. Retry it.",
160
- table: "The operation used a table the app's database schema does not declare.",
161
- index: "The operation used an index the table does not declare, or used it incorrectly.",
162
- range: "The index range is invalid for the declared index.",
163
- value: "A value does not match the table's declared field schema.",
164
- readonly: "Queries cannot write. Move writes into a mutation.",
165
- cursor: "The pagination cursor is invalid or belongs to a different query.",
166
- limit: "The operation exceeded a per-invocation app data limit.",
167
- closed: "The database session closed before this operation finished.",
168
- storage: "App storage failed to complete the operation.",
169
- replay: "A workflow step replayed with different input than its first run."
170
- };
171
- var minimumSecretLength = 6;
172
- var secretValues = (value, found) => {
173
- if (typeof value === "string") {
174
- if (value.length >= minimumSecretLength) found.add(value);
175
- } else if (Array.isArray(value)) for (const item of value) secretValues(item, found);
176
- else if (Predicate_exports.isObject(value))
177
- for (const item of Object.values(value)) secretValues(item, found);
178
- return found;
179
- };
180
- var accountFieldSecrets = (accounts) => {
181
- const found = /* @__PURE__ */ new Set();
182
- if (Predicate_exports.isObject(accounts)) {
183
- for (const slot of Object.values(accounts))
184
- for (const account of Array.isArray(slot) ? slot : [slot])
185
- if (Predicate_exports.hasProperty(account, "fields")) secretValues(account.fields, found);
186
- }
187
- return [...found].sort((a, b) => b.length - a.length);
188
- };
189
- var accountSecrets = (accounts) => accountFieldSecrets(Redacted_exports.value(accounts));
190
- var boundFailureMessage = (message, secrets) => {
191
- let redacted = message;
192
- for (const secret of secrets) redacted = redacted.split(secret).join("[redacted]");
193
- return redacted.length <= maxFailureMessageLength ? redacted : `${redacted.slice(0, maxFailureMessageLength - 1)}\u2026`;
194
- };
195
- var errorName = (error) => (error.name.length > 0 ? error.name : "Error").slice(0, 128);
196
- var ownMessage = (error) => {
197
- const cause = error.cause;
198
- const suffix = cause instanceof Error && cause.message.length > 0 ? ` (caused by ${errorName(cause)}: ${cause.message})` : "";
199
- return error.message.length > 0 ? `${error.message}${suffix}` : void 0;
200
- };
201
- var describeFailure = (error) => error instanceof Error ? `${errorName(error)}: ${ownMessage(error) ?? "(no message)"}` : typeof error === "string" ? error : `A non-Error ${error === null ? "null" : typeof error} value was thrown`;
202
- var failureDetail = (error, secrets) => {
203
- if (Schema_exports.is(AppDatabaseError)(error))
204
- return {
205
- source: "storage",
206
- errorName: "AppDatabaseError",
207
- code: error.reason,
208
- message: boundFailureMessage(ownMessage(error) ?? storageMessages[error.reason], secrets)
209
- };
210
- if (Schema_exports.is(AppStorageUnavailable)(error))
211
- return {
212
- source: "storage",
213
- errorName: "AppStorageUnavailable",
214
- message: "App storage is not available on this host."
215
- };
216
- if (Schema_exports.is(AppStorageError)(error))
217
- return {
218
- source: "storage",
219
- errorName: "AppStorageError",
220
- message: "App storage failed to complete the operation."
221
- };
222
- if (Schema_exports.is(OpenapiError)(error))
223
- return {
224
- source: "service",
225
- errorName: "OpenapiError",
226
- code: error.reason,
227
- message: error.reason === "request" ? error.status === void 0 ? "The API request failed before a response arrived." : `The API responded with HTTP ${error.status}, which its OpenAPI document does not declare as an error with a message.` : error.reason === "invalid_input" ? "The input could not be encoded as a request for this API operation." : "The API's OpenAPI definition for this operation is invalid."
228
- };
229
- if (error instanceof Error)
230
- return {
231
- source: "app",
232
- errorName: errorName(error),
233
- message: boundFailureMessage(
234
- ownMessage(error) ?? `${errorName(error)} was thrown without a message.`,
235
- secrets
236
- )
237
- };
238
- if (typeof error === "string")
239
- return { source: "app", errorName: "string", message: boundFailureMessage(error, secrets) };
240
- return {
241
- source: "app",
242
- errorName: typeof error,
243
- message: `A non-Error ${error === null ? "null" : typeof error} value was thrown.`
244
- };
245
- };
246
-
247
158
  // src/implementation/workflow-context.ts
248
159
  var workflowSafe = (work, secrets) => work.pipe(
249
160
  Effect_exports.catchCause((cause) => {
250
161
  if (Cause_exports.hasInterrupts(cause)) return Effect_exports.interrupt;
251
162
  const error = Cause_exports.squash(cause);
252
163
  if (Schema_exports.is(WorkflowFailure)(error)) return Effect_exports.fail(error);
253
- const { errorName: errorName2, message } = failureDetail(error, secrets);
164
+ const { errorName, message } = failureDetail(error, secrets);
254
165
  return Effect_exports.fail(
255
166
  new WorkflowFailure({
256
167
  reason: "execution",
257
168
  retryable: !(error instanceof NonRetryableError),
258
- ...errorName2 === void 0 ? {} : { errorName: errorName2 },
169
+ ...errorName === void 0 ? {} : { errorName },
259
170
  ...message === void 0 ? {} : { message }
260
171
  })
261
172
  );
@@ -346,9 +257,9 @@ var makeWorkflowContext = (execution, definition, fresh, signal) => Effect_expor
346
257
  });
347
258
  const operationStep = (kind, name, operation, input, options) => Effect_exports.gen(function* () {
348
259
  const target = nativeOperation(operation);
349
- const catalog = kind === "query" ? definition.queries : definition.mutations;
350
- const match = Object.entries(catalog ?? {}).find(
351
- ([, 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
352
263
  );
353
264
  if (target === void 0 || match === void 0)
354
265
  return yield* new WorkflowFailure({ reason: "operation", retryable: false });
@@ -367,7 +278,7 @@ var makeWorkflowContext = (execution, definition, fresh, signal) => Effect_expor
367
278
  parsed,
368
279
  () => attempt(
369
280
  parsed,
370
- 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))
371
282
  )
372
283
  ).pipe(Effect_exports.mapError(inStep(name)));
373
284
  });
@@ -647,6 +558,10 @@ var authorCache = (host, accounts, signal, deadline) => {
647
558
  };
648
559
 
649
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
+ });
650
565
  function safe2(work, failure) {
651
566
  return Effect_exports.suspend(work).pipe(
652
567
  Effect_exports.catchCause(
@@ -666,16 +581,6 @@ var evaluationSafe = (work, secrets) => work.pipe(
666
581
  );
667
582
  })
668
583
  );
669
- function jsonSchema(decoder) {
670
- const imported = importedJsonSchema(decoder);
671
- if (imported !== void 0) return Schema_exports.decodeUnknownEffect(JsonObject)(imported);
672
- const document = Schema_exports.toJsonSchemaDocument(decoder);
673
- return Schema_exports.decodeUnknownEffect(JsonObject)({
674
- ...document.schema,
675
- $defs: document.definitions,
676
- $schema: "https://json-schema.org/draft/2020-12/schema"
677
- });
678
- }
679
584
  var declarationInvalid = (summary, cause, secrets = []) => new HostDeclarationInvalid({
680
585
  source: "app",
681
586
  errorName: "HostDeclarationInvalid",
@@ -699,14 +604,14 @@ function providerDeclaration(provider) {
699
604
  auth.set(name, {
700
605
  type: "secrets",
701
606
  label: method.label,
702
- fields: yield* jsonSchema(method.fields)
607
+ fields: yield* jsonSchemaDocument(method.fields)
703
608
  });
704
609
  break;
705
610
  case "oauth2":
706
611
  auth.set(name, {
707
612
  type: "oauth2",
708
613
  ...method.config,
709
- response: yield* jsonSchema(method.response)
614
+ response: yield* jsonSchemaDocument(method.response)
710
615
  });
711
616
  break;
712
617
  }
@@ -723,11 +628,11 @@ function requirements(slots, database) {
723
628
  return Effect_exports.gen(function* () {
724
629
  const accounts = /* @__PURE__ */ new Map();
725
630
  for (const [slot, selection] of Object.entries(slots)) {
631
+ const provider = selection instanceof ManyAccounts ? selection.provider : selection;
726
632
  accounts.set(slot, {
727
633
  cardinality: selection instanceof ManyAccounts ? "many" : "one",
728
- definition: yield* providerDeclaration(
729
- selection instanceof ManyAccounts ? selection.provider : selection
730
- )
634
+ definition: yield* providerDeclaration(provider),
635
+ ...provider.health === void 0 ? {} : { health: true }
731
636
  });
732
637
  }
733
638
  return yield* Schema_exports.decodeUnknownEffect(DeclaredRequirements)({
@@ -845,6 +750,14 @@ function dispatch(app, request, context, signal) {
845
750
  return yield* new WorkflowFailure({ reason: "engine", retryable: true });
846
751
  return result;
847
752
  });
753
+ if (request.operation === "account-check")
754
+ return yield* checkAccount(
755
+ native.accounts,
756
+ declared,
757
+ request.requirement,
758
+ context,
759
+ invocationSignal
760
+ ).pipe(withinDeadline);
848
761
  let running;
849
762
  let transactionOpen = false;
850
763
  const delivery = (request2, signal2) => Effect_exports.suspend(
@@ -910,27 +823,33 @@ function dispatch(app, request, context, signal) {
910
823
  const declared2 = definition.skills ?? (yield* folderSkillsEffect({ files }).pipe(
911
824
  Effect_exports.mapError(() => new HostDeclarationInvalid())
912
825
  ));
913
- const source2 = definition.dynamicSkills;
826
+ const source = definition.dynamicSkills;
914
827
  const before = cacheCommands;
915
- const dynamic = source2 === void 0 ? [] : yield* evaluationSafe(Effect_exports.suspend(source2.list), secrets).pipe(
828
+ const dynamic = source === void 0 ? [] : yield* evaluationSafe(Effect_exports.suspend(source.list), secrets).pipe(
916
829
  Effect_exports.withSpan("app.skills.load")
917
830
  );
918
- const cached = source2 !== void 0 && cacheCommands > before;
919
- const skills = yield* Schema_exports.decodeUnknownEffect(AppSkills)([...declared2, ...dynamic]).pipe(
920
- Effect_exports.mapError(() => new HostDeclarationInvalid())
921
- );
922
- return request.sources === true ? { skills, dynamic: source2 !== void 0, cached } : skills;
831
+ const cached = source !== void 0 && cacheCommands > before;
832
+ const authored = new Set([...declared2, ...dynamic].map((skill) => skill.name));
833
+ const routed = (yield* routerSkills(definition.tools).pipe(
834
+ Effect_exports.withSpan("app.skills.routers")
835
+ )).filter((skill) => !authored.has(skill.name));
836
+ const skills = yield* Schema_exports.decodeUnknownEffect(AppSkills)([
837
+ ...declared2,
838
+ ...dynamic,
839
+ ...routed
840
+ ]).pipe(Effect_exports.mapError(() => new HostDeclarationInvalid()));
841
+ return request.sources === true ? { skills, dynamic: source !== void 0, cached } : skills;
923
842
  }
924
843
  if (request.operation === "workflows") {
925
844
  return yield* Effect_exports.forEach(
926
845
  Object.entries(definition.workflows ?? {}),
927
- ([name2, entry]) => safe2(
846
+ ([name, entry]) => safe2(
928
847
  () => Effect_exports.gen(function* () {
929
848
  return yield* Schema_exports.decodeUnknownEffect(HostedWorkflow)({
930
- name: name2,
849
+ name,
931
850
  ...entry.description === void 0 ? {} : { description: entry.description },
932
- inputSchema: yield* jsonSchema(entry.input),
933
- ...entry.output === void 0 ? {} : { outputSchema: yield* jsonSchema(entry.output) }
851
+ inputSchema: yield* jsonSchemaDocument(entry.input),
852
+ ...entry.output === void 0 ? {} : { outputSchema: yield* jsonSchemaDocument(entry.output) }
934
853
  });
935
854
  }),
936
855
  new HostDeclarationInvalid()
@@ -1004,79 +923,19 @@ function dispatch(app, request, context, signal) {
1004
923
  }
1005
924
  if (request.operation === "inspect") {
1006
925
  const summary = request.detail === "summary";
1007
- const wanted = request.tools === void 0 ? void 0 : new Set(request.tools);
1008
- const metadata = [];
1009
- for (const [prefix, readOnly, catalog2] of [
1010
- [OperationToolPrefixes.query, true, definition.queries],
1011
- [OperationToolPrefixes.mutate, false, definition.mutations]
1012
- ]) {
1013
- for (const [name2, operation] of Object.entries(catalog2 ?? {})) {
1014
- if (wanted !== void 0 && !wanted.has(`${prefix}${name2}`)) continue;
1015
- const schedules = Object.entries(definition.schedules ?? {}).filter(([, schedule]) => schedule.tool === `${prefix}${name2}`).map(([name3, { tool: _tool, ...schedule }]) => ({ name: name3, ...schedule }));
1016
- if (request.scheduled === true && schedules.length === 0) continue;
1017
- metadata.push(
1018
- yield* safe2(
1019
- () => Effect_exports.gen(function* () {
1020
- const fields = {
1021
- name: `${prefix}${name2}`,
1022
- schedules,
1023
- description: operation.description ?? `${readOnly ? "Query" : "Mutate"} ${name2}`,
1024
- ...operation.title === void 0 ? {} : { title: operation.title },
1025
- readOnly,
1026
- annotations: { ...operation.annotations, readOnlyHint: readOnly }
1027
- };
1028
- if (summary)
1029
- return yield* Schema_exports.decodeUnknownEffect(HostedToolSummary)(fields);
1030
- return yield* Schema_exports.decodeUnknownEffect(HostedTool)({
1031
- ...fields,
1032
- inputSchema: yield* jsonSchema(operation.input),
1033
- ...operation.output === void 0 ? operation.outputSchema === void 0 ? {} : { outputSchema: operation.outputSchema } : { outputSchema: yield* jsonSchema(operation.output) },
1034
- ...operation._meta === void 0 ? {} : { _meta: operation._meta }
1035
- });
1036
- }),
1037
- new HostDeclarationInvalid()
1038
- )
1039
- );
1040
- }
1041
- }
1042
- const dynamic = request.scheduled === true ? void 0 : definition.dynamicTools;
1043
- if (dynamic !== void 0 && (wanted === void 0 || metadata.length < wanted.size)) {
1044
- const declared2 = new Set(metadata.map((tool2) => tool2.name));
1045
- const discover = () => {
1046
- if (summary && dynamic.summaries !== void 0) return dynamic.summaries();
1047
- if (wanted !== void 0 && dynamic.describe !== void 0) {
1048
- const describe = dynamic.describe;
1049
- return Effect_exports.forEach(
1050
- [...wanted].filter((name2) => !declared2.has(name2)),
1051
- (name2) => describe(name2),
1052
- { concurrency: "unbounded" }
1053
- ).pipe(Effect_exports.map((tools) => tools.filter((tool2) => tool2 !== void 0)));
1054
- }
1055
- return dynamic.list();
1056
- };
1057
- const discovered = yield* evaluationSafe(discover(), secrets).pipe(
1058
- Effect_exports.flatMap(
1059
- (value) => safe2(
1060
- () => summary ? Schema_exports.decodeUnknownEffect(Schema_exports.Array(HostedToolSummary))(value) : Schema_exports.decodeUnknownEffect(Schema_exports.Array(HostedTool))(value),
1061
- new HostDeclarationInvalid()
1062
- )
1063
- )
1064
- );
1065
- const names = new Set(declared2);
1066
- for (const tool2 of discovered) {
1067
- const readOnly = tool2.name.startsWith(OperationToolPrefixes.query);
1068
- if (!readOnly && !tool2.name.startsWith(OperationToolPrefixes.mutate) || tool2.name === OperationToolPrefixes.query || tool2.name === OperationToolPrefixes.mutate || names.has(tool2.name))
1069
- return yield* new HostDeclarationInvalid();
1070
- names.add(tool2.name);
1071
- if (wanted !== void 0 && !wanted.has(tool2.name)) continue;
1072
- metadata.push({
1073
- ...tool2,
1074
- readOnly,
1075
- annotations: { ...tool2.annotations, readOnlyHint: readOnly }
1076
- });
1077
- }
1078
- }
1079
- return metadata;
926
+ const catalog = yield* readCatalog(definition.tools, {
927
+ summary,
928
+ secrets,
929
+ ...request.tools === void 0 ? {} : { wanted: new Set(request.tools) },
930
+ ...request.scheduled === true ? { scheduled: true } : {},
931
+ schedules: (name) => Object.entries(definition.schedules ?? {}).filter(([, schedule]) => schedule.tool === name).map(([name2, { tool: _tool, ...schedule }]) => ({ name: name2, ...schedule }))
932
+ }).pipe(Effect_exports.withSpan("app.catalog.read"));
933
+ return yield* safe2(
934
+ () => Schema_exports.encodeEffect(WireCatalog)(catalog).pipe(
935
+ Effect_exports.flatMap(Schema_exports.decodeUnknownEffect(JsonValue))
936
+ ),
937
+ new HostDeclarationInvalid()
938
+ );
1080
939
  }
1081
940
  if (request.operation === "webhook-complete" || request.operation === "webhook-validate" || request.operation === "webhooks" || request.operation === "webhook-register" || request.operation === "webhook-handle" || request.operation === "webhook-unregister") {
1082
941
  const executeWebhook = (db) => dispatchWebhook(
@@ -1107,19 +966,15 @@ function dispatch(app, request, context, signal) {
1107
966
  })
1108
967
  );
1109
968
  }
1110
- const kind = request.operation === "call" ? request.tool.startsWith(OperationToolPrefixes.query) ? "query" : request.tool.startsWith(OperationToolPrefixes.mutate) ? "mutate" : void 0 : request.operation;
1111
- if (kind === void 0) return yield* new HostToolNotFound();
1112
- const name = request.operation === "call" ? request.tool.slice(OperationToolPrefixes[kind].length) : request.name;
1113
- const toolName = `${OperationToolPrefixes[kind]}${name}`;
1114
- const catalog = kind === "query" ? definition.queries : definition.mutations;
1115
- const declaredTool = catalog !== void 0 && Object.hasOwn(catalog, name) ? catalog[name] : void 0;
1116
- const source = definition.dynamicTools;
1117
- const resolvedTool = source === void 0 || declaredTool !== void 0 ? void 0 : yield* evaluationSafe(source.resolve(toolName), secrets);
1118
- const tool = declaredTool ?? resolvedTool;
1119
- if (tool !== void 0 && tool.kind !== (kind === "query" ? "query" : "mutation"))
1120
- return yield* new HostDeclarationInvalid();
969
+ const toolName = request.operation === "call" ? request.tool : request.name;
970
+ const location = locate(definition.tools, toolName);
971
+ const tool = location === void 0 ? void 0 : location.kind === "operation" ? location.operation : yield* evaluationSafe(location.source.resolve(location.name), secrets);
1121
972
  if (tool === void 0)
1122
973
  return yield* request.operation === "call" ? new HostToolNotFound() : new HostOperationNotFound();
974
+ const requested = request.operation === "call" ? request.kind : request.operation === "query" ? "query" : "mutation";
975
+ if (requested !== void 0 && tool.kind !== requested)
976
+ return yield* new HostKindMismatch({ tool: toolName, requested, actual: tool.kind });
977
+ const kind = tool.kind === "query" ? "query" : "mutate";
1123
978
  const input = yield* Effect_exports.suspend(
1124
979
  () => Schema_exports.decodeUnknownEffect(tool.input)(request.input)
1125
980
  ).pipe(
@@ -1248,6 +1103,46 @@ function dispatch(app, request, context, signal) {
1248
1103
  })
1249
1104
  );
1250
1105
  }
1106
+ function checkAccount(slots, declared, requirement, context, signal) {
1107
+ return Effect_exports.gen(function* () {
1108
+ const selection = Object.hasOwn(slots, requirement) ? slots[requirement] : void 0;
1109
+ const slot = Object.hasOwn(declared.accounts, requirement) ? declared.accounts[requirement] : void 0;
1110
+ if (selection === void 0 || slot === void 0) return yield* new HostAccountsInvalid();
1111
+ const provider = selection instanceof ManyAccounts ? selection.provider : selection;
1112
+ const health = provider.health;
1113
+ if (health === void 0) return yield* new HostOperationNotFound();
1114
+ const { accounts } = yield* bindAccounts(
1115
+ { [requirement]: provider },
1116
+ { accounts: { [requirement]: { ...slot, cardinality: "one" } } },
1117
+ context
1118
+ ).pipe(Effect_exports.withSpan("app.accounts.bind"));
1119
+ const account = accounts[requirement];
1120
+ if (account === void 0 || !("id" in account)) return yield* new HostAccountsInvalid();
1121
+ const result = yield* Effect_exports.suspend(
1122
+ () => Effect_exports.gen(function* () {
1123
+ return yield* health.run({ account, fetch: yield* invocationFetch(signal), signal });
1124
+ })
1125
+ ).pipe(
1126
+ Effect_exports.catchCause((cause) => {
1127
+ if (Cause_exports.hasInterrupts(cause)) return Effect_exports.interrupt;
1128
+ const error = Cause_exports.squash(cause);
1129
+ const status = Schema_exports.decodeUnknownOption(ResponseStatusError)(error);
1130
+ const classified = Option_exports.isSome(status) ? Option_exports.fromNullishOr(httpProviderError(status.value.status)) : parseProviderError(error);
1131
+ return Effect_exports.fail(
1132
+ Option_exports.isSome(classified) ? accountProviderError(classified.value, account.id) : new HostOperationFailed()
1133
+ );
1134
+ }),
1135
+ Effect_exports.withSpan("app.account.check")
1136
+ );
1137
+ return yield* safe2(
1138
+ () => Schema_exports.decodeUnknownEffect(AccountCheckResult)(result ?? {}).pipe(
1139
+ Effect_exports.flatMap(Schema_exports.encodeEffect(AccountCheckResult)),
1140
+ Effect_exports.flatMap(Schema_exports.decodeUnknownEffect(JsonValue))
1141
+ ),
1142
+ new HostOutputInvalid()
1143
+ );
1144
+ });
1145
+ }
1251
1146
  var parseSkillLoadFailed = (error) => Schema_exports.decodeUnknownOption(SkillLoadFailed)(error).pipe(
1252
1147
  Option_exports.map(
1253
1148
  ({ reason, message, status }) => new SkillLoadFailed({
@@ -1273,6 +1168,7 @@ var errorStatus = Match_exports.type().pipe(
1273
1168
  HostAccountsInvalid: () => 422,
1274
1169
  HostInputInvalid: () => 422,
1275
1170
  HostOperationNotFound: () => 404,
1171
+ HostKindMismatch: () => 409,
1276
1172
  HostToolNotFound: () => 404,
1277
1173
  HostToolBlocked: () => 403,
1278
1174
  HostToolApprovalRequired: () => 409,