apps 0.0.1-beta.5 → 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 (63) 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-67EVWIGJ.js → chunk-6BSSI67S.js} +4 -4
  5. package/js/{chunk-DQAZTA4I.js → chunk-B3EOZTK3.js} +212 -19
  6. package/js/{chunk-TDNYXSIX.js → chunk-ECQFRCH4.js} +21 -9
  7. package/js/{chunk-UDDE5KOR.js → chunk-ITM77QPO.js} +26 -7
  8. package/js/{chunk-G7T27IWB.js → chunk-MKWZPDR6.js} +1 -1
  9. package/js/chunk-MNMNLXBL.js +507 -0
  10. package/js/{chunk-CYYBFC2K.js → chunk-NKLWZJLE.js} +1 -1
  11. package/js/{chunk-C3VAOK5B.js → chunk-OE3QQTSB.js} +33 -26
  12. package/js/{chunk-YEPYT6SD.js → chunk-R3EV5FTO.js} +12 -0
  13. package/js/{chunk-XHO2ZX6W.js → chunk-RFVIONFX.js} +27 -10
  14. package/js/{chunk-LUVSFETN.js → chunk-SB4HEPNJ.js} +72 -228
  15. package/js/chunk-T7GKZBLP.js +209 -0
  16. package/js/client.js +1 -1
  17. package/js/contracts.js +24 -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 +184 -173
  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 +11 -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/router.d.ts +59 -0
  37. package/types/apps/src/graphql.d.ts +1 -3
  38. package/types/apps/src/implementation/account-router.d.ts +12 -0
  39. package/types/apps/src/implementation/app.d.ts +5 -4
  40. package/types/apps/src/implementation/catalog-cache.d.ts +9 -2
  41. package/types/apps/src/implementation/graphql-catalog.d.ts +1 -4
  42. package/types/apps/src/implementation/mcp-catalog.d.ts +1 -4
  43. package/types/apps/src/implementation/mcp-client.d.ts +35 -19
  44. package/types/apps/src/implementation/mcp.d.ts +35 -19
  45. package/types/apps/src/implementation/openapi-compile.d.ts +2 -1
  46. package/types/apps/src/implementation/openapi-source.d.ts +2 -6
  47. package/types/apps/src/implementation/operations.d.ts +26 -3
  48. package/types/apps/src/implementation/protocol-operations.d.ts +3 -4
  49. package/types/apps/src/implementation/router-catalog.d.ts +225 -0
  50. package/types/apps/src/implementation/router.d.ts +59 -0
  51. package/types/apps/src/implementation/schema.d.ts +5 -1
  52. package/types/apps/src/implementation/workflow-context.d.ts +1 -1
  53. package/types/apps/src/index.d.ts +3 -2
  54. package/types/apps/src/mcp-stdio.d.ts +2 -5
  55. package/types/apps/src/mcp.d.ts +5 -4
  56. package/types/apps/src/openapi.d.ts +6 -6
  57. package/js/chunk-3XKZDQLM.js +0 -93
  58. package/js/chunk-4M277YTM.js +0 -136
  59. package/js/chunk-SB3V4YVR.js +0 -18
  60. package/js/chunk-W4DMKWAB.js +0 -35
  61. package/types/apps/src/contracts/dynamic-tools.d.ts +0 -13
  62. package/types/apps/src/implementation/account-operations.d.ts +0 -151
  63. package/types/apps/src/implementation/dynamic-tools.d.ts +0 -8
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  CacheError
3
- } from "./chunk-YEPYT6SD.js";
3
+ } from "./chunk-R3EV5FTO.js";
4
4
  import {
5
5
  wrap
6
- } from "./chunk-FWQC6I3C.js";
6
+ } from "./chunk-5T57N25Q.js";
7
7
  import {
8
8
  JsonObject
9
9
  } from "./chunk-27F7W2LG.js";
@@ -18,7 +18,8 @@ var schema = (decoder) => wrap(decoder, false);
18
18
  var Manifest = Schema_exports.Struct({
19
19
  revision: Schema_exports.String,
20
20
  pages: Schema_exports.Int,
21
- summaries: Schema_exports.Int
21
+ summaries: Schema_exports.Int,
22
+ header: Schema_exports.optionalKey(JsonObject)
22
23
  });
23
24
  var invoke = (work) => Effect_exports.tryPromise({ try: work, catch: (error) => error });
24
25
  var catalogCache = (options) => Effect_exports.gen(function* () {
@@ -35,9 +36,12 @@ var catalogCache = (options) => Effect_exports.gen(function* () {
35
36
  const retention = Duration_exports.toMillis(Duration_exports.fromInputUnsafe(freshFor)) + Duration_exports.toMillis(Duration_exports.fromInputUnsafe(staleFor)) + 3e5;
36
37
  const local = yield* Effect_exports.cached(options.load());
37
38
  const refresh = (context) => Effect_exports.gen(function* () {
38
- const tools = yield* options.load(context);
39
+ const { tools, header } = yield* options.load(context);
39
40
  const digest = yield* invoke(
40
- () => crypto.subtle.digest("SHA-256", new TextEncoder().encode(JSON.stringify(tools)))
41
+ () => crypto.subtle.digest(
42
+ "SHA-256",
43
+ new TextEncoder().encode(JSON.stringify({ tools, header: header ?? null }))
44
+ )
41
45
  );
42
46
  const revision = Array.from(
43
47
  new Uint8Array(digest),
@@ -104,7 +108,12 @@ var catalogCache = (options) => Effect_exports.gen(function* () {
104
108
  yield* pageOut();
105
109
  yield* summaryOut();
106
110
  yield* flush();
107
- return { revision, pages: pages2, summaries };
111
+ return {
112
+ revision,
113
+ pages: pages2,
114
+ summaries,
115
+ ...header === void 0 ? {} : { header: yield* json(header) }
116
+ };
108
117
  });
109
118
  const getOptions = {
110
119
  key,
@@ -113,7 +122,12 @@ var catalogCache = (options) => Effect_exports.gen(function* () {
113
122
  staleFor,
114
123
  load: (context) => Effect_exports.runPromise(refresh(context), { signal: context.signal })
115
124
  };
116
- const current = () => cache === void 0 ? Effect_exports.fail(new CacheError({ reason: "unavailable" })) : invoke(() => cache.get(getOptions));
125
+ let reading;
126
+ const current = () => cache === void 0 ? Effect_exports.fail(new CacheError({ reason: "unavailable" })) : invoke(
127
+ () => reading ??= cache.get(getOptions).finally(() => {
128
+ reading = void 0;
129
+ })
130
+ );
117
131
  if (options.revalidate) {
118
132
  if (cache === void 0) yield* local;
119
133
  else yield* invoke(() => cache.revalidate(getOptions));
@@ -140,14 +154,17 @@ var catalogCache = (options) => Effect_exports.gen(function* () {
140
154
  return values;
141
155
  });
142
156
  const metadata = () => Effect_exports.gen(function* () {
143
- if (cache === void 0) return yield* local;
157
+ if (cache === void 0) return (yield* local).tools;
144
158
  const manifest = yield* current();
145
159
  return yield* pages(cache, manifest.revision, "page", manifest.pages, options.schema);
146
160
  });
147
161
  return {
148
162
  list: metadata,
163
+ /** The record stored with the current revision, if the source supplied one. */
164
+ header: () => cache === void 0 ? local.pipe(Effect_exports.map(({ header }) => header)) : current().pipe(Effect_exports.map((manifest) => manifest.header)),
149
165
  summaries: () => Effect_exports.gen(function* () {
150
- if (cache === void 0) return (yield* local).map((tool) => options.summary.of(tool));
166
+ if (cache === void 0)
167
+ return (yield* local).tools.map((tool) => options.summary.of(tool));
151
168
  const manifest = yield* current();
152
169
  return yield* pages(
153
170
  cache,
@@ -157,7 +174,7 @@ var catalogCache = (options) => Effect_exports.gen(function* () {
157
174
  options.summary.schema
158
175
  );
159
176
  }),
160
- resolve: (name) => cache === void 0 ? local.pipe(Effect_exports.map((tools) => tools.find((tool) => tool.name === name))) : current().pipe(
177
+ resolve: (name) => cache === void 0 ? local.pipe(Effect_exports.map(({ tools }) => tools.find((tool) => tool.name === name))) : current().pipe(
161
178
  Effect_exports.flatMap(
162
179
  (manifest) => invoke(
163
180
  () => cache.read(part(manifest.revision, "tool", name), schema(options.schema))
@@ -1,29 +1,36 @@
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-MNMNLXBL.js";
4
12
  import {
5
13
  folderSkillsEffect
6
14
  } from "./chunk-IPI4MFSN.js";
7
- import {
8
- OpenapiError
9
- } from "./chunk-4M277YTM.js";
10
15
  import {
11
16
  authorDatabase,
12
17
  isApp,
13
18
  toEffectApp,
14
19
  unavailableStorage
15
- } from "./chunk-C3VAOK5B.js";
20
+ } from "./chunk-OE3QQTSB.js";
16
21
  import {
17
22
  parseDatabaseSchema
18
23
  } from "./chunk-ZQINWV4W.js";
19
24
  import {
25
+ declaredOperations,
20
26
  fromPromise,
27
+ locate,
21
28
  nativeOperation,
22
29
  toPromise
23
- } from "./chunk-3XKZDQLM.js";
30
+ } from "./chunk-T7GKZBLP.js";
24
31
  import {
25
32
  parseProviderError
26
- } from "./chunk-G7T27IWB.js";
33
+ } from "./chunk-MKWZPDR6.js";
27
34
  import {
28
35
  DeclaredProvider,
29
36
  DeclaredRequirements,
@@ -35,6 +42,7 @@ import {
35
42
  HostError,
36
43
  HostEvaluationFailed,
37
44
  HostInputInvalid,
45
+ HostKindMismatch,
38
46
  HostOperationFailed,
39
47
  HostOperationNotFound,
40
48
  HostOutputInvalid,
@@ -44,6 +52,7 @@ import {
44
52
  HostToolBlocked,
45
53
  HostToolNotFound,
46
54
  HostToolPolicyFailed,
55
+ HostedRouter,
47
56
  HostedTool,
48
57
  HostedToolSummary,
49
58
  HostedWebhook,
@@ -53,7 +62,7 @@ import {
53
62
  ManyAccounts,
54
63
  McpError,
55
64
  NonRetryableError,
56
- OperationToolPrefixes,
65
+ OpenapiResponseError,
57
66
  ResolvedAccounts,
58
67
  ToolResultObservation,
59
68
  TrustedToolApproval,
@@ -66,24 +75,17 @@ import {
66
75
  WorkflowValue,
67
76
  approvalElicitation,
68
77
  defaultWebhookTransportLimits,
69
- maxFailureMessageLength,
70
78
  maxInputProblems,
71
79
  workflowDurationMillis
72
- } from "./chunk-DQAZTA4I.js";
73
- import {
74
- AppDatabaseError
75
- } from "./chunk-N7YDVXYJ.js";
80
+ } from "./chunk-B3EOZTK3.js";
76
81
  import {
77
82
  CacheError
78
- } from "./chunk-YEPYT6SD.js";
83
+ } from "./chunk-R3EV5FTO.js";
79
84
  import {
80
85
  AppSkills,
81
86
  SkillFile,
82
87
  SkillLoadFailed
83
88
  } from "./chunk-JU7VHODU.js";
84
- import {
85
- OpenapiResponseError
86
- } from "./chunk-W4DMKWAB.js";
87
89
  import {
88
90
  captureTelemetry,
89
91
  invocationFetch
@@ -91,12 +93,9 @@ import {
91
93
  import {
92
94
  decoderOf,
93
95
  importedJsonSchema,
94
- jsonSchemaDecoder
95
- } from "./chunk-FWQC6I3C.js";
96
- import {
97
- AppStorageError,
98
- AppStorageUnavailable
99
- } from "./chunk-PZB6T6KU.js";
96
+ jsonSchemaDecoder,
97
+ jsonSchemaDocument
98
+ } from "./chunk-5T57N25Q.js";
100
99
  import {
101
100
  JsonObject,
102
101
  JsonValue
@@ -108,7 +107,6 @@ import {
108
107
  Encoding_exports,
109
108
  Match_exports,
110
109
  Option_exports,
111
- Predicate_exports,
112
110
  Redacted_exports,
113
111
  SchemaIssue_exports,
114
112
  Schema_exports,
@@ -153,109 +151,18 @@ var makeElicit = (handler, signal) => toPromise(
153
151
  // src/contracts/approval.ts
154
152
  var ApprovalDecision = Schema_exports.Literals(["approved", "denied", "user-approval"]);
155
153
 
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
154
  // src/implementation/workflow-context.ts
248
155
  var workflowSafe = (work, secrets) => work.pipe(
249
156
  Effect_exports.catchCause((cause) => {
250
157
  if (Cause_exports.hasInterrupts(cause)) return Effect_exports.interrupt;
251
158
  const error = Cause_exports.squash(cause);
252
159
  if (Schema_exports.is(WorkflowFailure)(error)) return Effect_exports.fail(error);
253
- const { errorName: errorName2, message } = failureDetail(error, secrets);
160
+ const { errorName, message } = failureDetail(error, secrets);
254
161
  return Effect_exports.fail(
255
162
  new WorkflowFailure({
256
163
  reason: "execution",
257
164
  retryable: !(error instanceof NonRetryableError),
258
- ...errorName2 === void 0 ? {} : { errorName: errorName2 },
165
+ ...errorName === void 0 ? {} : { errorName },
259
166
  ...message === void 0 ? {} : { message }
260
167
  })
261
168
  );
@@ -346,9 +253,9 @@ var makeWorkflowContext = (execution, definition, fresh, signal) => Effect_expor
346
253
  });
347
254
  const operationStep = (kind, name, operation, input, options) => Effect_exports.gen(function* () {
348
255
  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
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
352
259
  );
353
260
  if (target === void 0 || match === void 0)
354
261
  return yield* new WorkflowFailure({ reason: "operation", retryable: false });
@@ -367,7 +274,7 @@ var makeWorkflowContext = (execution, definition, fresh, signal) => Effect_expor
367
274
  parsed,
368
275
  () => attempt(
369
276
  parsed,
370
- 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))
371
278
  )
372
279
  ).pipe(Effect_exports.mapError(inStep(name)));
373
280
  });
@@ -647,6 +554,10 @@ var authorCache = (host, accounts, signal, deadline) => {
647
554
  };
648
555
 
649
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
+ });
650
561
  function safe2(work, failure) {
651
562
  return Effect_exports.suspend(work).pipe(
652
563
  Effect_exports.catchCause(
@@ -666,16 +577,6 @@ var evaluationSafe = (work, secrets) => work.pipe(
666
577
  );
667
578
  })
668
579
  );
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
580
  var declarationInvalid = (summary, cause, secrets = []) => new HostDeclarationInvalid({
680
581
  source: "app",
681
582
  errorName: "HostDeclarationInvalid",
@@ -699,14 +600,14 @@ function providerDeclaration(provider) {
699
600
  auth.set(name, {
700
601
  type: "secrets",
701
602
  label: method.label,
702
- fields: yield* jsonSchema(method.fields)
603
+ fields: yield* jsonSchemaDocument(method.fields)
703
604
  });
704
605
  break;
705
606
  case "oauth2":
706
607
  auth.set(name, {
707
608
  type: "oauth2",
708
609
  ...method.config,
709
- response: yield* jsonSchema(method.response)
610
+ response: yield* jsonSchemaDocument(method.response)
710
611
  });
711
612
  break;
712
613
  }
@@ -910,27 +811,33 @@ function dispatch(app, request, context, signal) {
910
811
  const declared2 = definition.skills ?? (yield* folderSkillsEffect({ files }).pipe(
911
812
  Effect_exports.mapError(() => new HostDeclarationInvalid())
912
813
  ));
913
- const source2 = definition.dynamicSkills;
814
+ const source = definition.dynamicSkills;
914
815
  const before = cacheCommands;
915
- const dynamic = source2 === void 0 ? [] : yield* evaluationSafe(Effect_exports.suspend(source2.list), secrets).pipe(
816
+ const dynamic = source === void 0 ? [] : yield* evaluationSafe(Effect_exports.suspend(source.list), secrets).pipe(
916
817
  Effect_exports.withSpan("app.skills.load")
917
818
  );
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;
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;
923
830
  }
924
831
  if (request.operation === "workflows") {
925
832
  return yield* Effect_exports.forEach(
926
833
  Object.entries(definition.workflows ?? {}),
927
- ([name2, entry]) => safe2(
834
+ ([name, entry]) => safe2(
928
835
  () => Effect_exports.gen(function* () {
929
836
  return yield* Schema_exports.decodeUnknownEffect(HostedWorkflow)({
930
- name: name2,
837
+ name,
931
838
  ...entry.description === void 0 ? {} : { description: entry.description },
932
- inputSchema: yield* jsonSchema(entry.input),
933
- ...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) }
934
841
  });
935
842
  }),
936
843
  new HostDeclarationInvalid()
@@ -1004,79 +911,19 @@ function dispatch(app, request, context, signal) {
1004
911
  }
1005
912
  if (request.operation === "inspect") {
1006
913
  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;
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
+ );
1080
927
  }
1081
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") {
1082
929
  const executeWebhook = (db) => dispatchWebhook(
@@ -1107,19 +954,15 @@ function dispatch(app, request, context, signal) {
1107
954
  })
1108
955
  );
1109
956
  }
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();
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);
1121
960
  if (tool === void 0)
1122
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";
1123
966
  const input = yield* Effect_exports.suspend(
1124
967
  () => Schema_exports.decodeUnknownEffect(tool.input)(request.input)
1125
968
  ).pipe(
@@ -1273,6 +1116,7 @@ var errorStatus = Match_exports.type().pipe(
1273
1116
  HostAccountsInvalid: () => 422,
1274
1117
  HostInputInvalid: () => 422,
1275
1118
  HostOperationNotFound: () => 404,
1119
+ HostKindMismatch: () => 409,
1276
1120
  HostToolNotFound: () => 404,
1277
1121
  HostToolBlocked: () => 403,
1278
1122
  HostToolApprovalRequired: () => 409,