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