@dxos/functions 0.8.4-main.3eb6e50203 → 0.8.4-main.3fbcb4aa9b

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 (78) hide show
  1. package/README.md +4 -6
  2. package/dist/lib/neutral/index.mjs +283 -924
  3. package/dist/lib/neutral/index.mjs.map +4 -4
  4. package/dist/lib/neutral/meta.json +1 -1
  5. package/dist/types/src/index.d.ts +0 -2
  6. package/dist/types/src/index.d.ts.map +1 -1
  7. package/dist/types/src/protocol/functions-ai-http-client.d.ts.map +1 -1
  8. package/dist/types/src/protocol/functions-ai-http-client.test.d.ts +2 -0
  9. package/dist/types/src/protocol/functions-ai-http-client.test.d.ts.map +1 -0
  10. package/dist/types/src/protocol/protocol.d.ts +14 -2
  11. package/dist/types/src/protocol/protocol.d.ts.map +1 -1
  12. package/dist/types/src/sdk.d.ts +5 -109
  13. package/dist/types/src/sdk.d.ts.map +1 -1
  14. package/dist/types/src/services/credentials.d.ts +15 -38
  15. package/dist/types/src/services/credentials.d.ts.map +1 -1
  16. package/dist/types/src/services/function-invocation-service.d.ts +5 -6
  17. package/dist/types/src/services/function-invocation-service.d.ts.map +1 -1
  18. package/dist/types/src/services/index.d.ts +1 -4
  19. package/dist/types/src/services/index.d.ts.map +1 -1
  20. package/dist/types/src/services/queues.d.ts +1 -46
  21. package/dist/types/src/services/queues.d.ts.map +1 -1
  22. package/dist/types/src/services/tracing.d.ts +1 -84
  23. package/dist/types/src/services/tracing.d.ts.map +1 -1
  24. package/dist/types/src/types/index.d.ts +0 -4
  25. package/dist/types/src/types/index.d.ts.map +1 -1
  26. package/dist/types/src/types/url.d.ts +3 -3
  27. package/dist/types/src/types/url.d.ts.map +1 -1
  28. package/dist/types/tsconfig.tsbuildinfo +1 -1
  29. package/package.json +17 -16
  30. package/src/index.ts +0 -2
  31. package/src/protocol/functions-ai-http-client.test.ts +105 -0
  32. package/src/protocol/functions-ai-http-client.ts +75 -1
  33. package/src/protocol/protocol.test.ts +9 -10
  34. package/src/protocol/protocol.ts +224 -58
  35. package/src/sdk.ts +12 -270
  36. package/src/services/credentials.ts +75 -118
  37. package/src/services/function-invocation-service.ts +6 -10
  38. package/src/services/index.ts +1 -4
  39. package/src/services/queues.ts +1 -78
  40. package/src/services/tracing.ts +0 -159
  41. package/src/types/index.ts +0 -4
  42. package/src/types/url.ts +3 -3
  43. package/dist/types/src/errors.d.ts +0 -121
  44. package/dist/types/src/errors.d.ts.map +0 -1
  45. package/dist/types/src/example/fib.d.ts +0 -7
  46. package/dist/types/src/example/fib.d.ts.map +0 -1
  47. package/dist/types/src/example/forex-effect.d.ts +0 -3
  48. package/dist/types/src/example/forex-effect.d.ts.map +0 -1
  49. package/dist/types/src/example/index.d.ts +0 -12
  50. package/dist/types/src/example/index.d.ts.map +0 -1
  51. package/dist/types/src/example/reply.d.ts +0 -3
  52. package/dist/types/src/example/reply.d.ts.map +0 -1
  53. package/dist/types/src/example/sleep.d.ts +0 -5
  54. package/dist/types/src/example/sleep.d.ts.map +0 -1
  55. package/dist/types/src/operation-compatibility.test.d.ts +0 -2
  56. package/dist/types/src/operation-compatibility.test.d.ts.map +0 -1
  57. package/dist/types/src/services/event-logger.d.ts +0 -81
  58. package/dist/types/src/services/event-logger.d.ts.map +0 -1
  59. package/dist/types/src/types/Function.d.ts +0 -52
  60. package/dist/types/src/types/Function.d.ts.map +0 -1
  61. package/dist/types/src/types/Script.d.ts +0 -21
  62. package/dist/types/src/types/Script.d.ts.map +0 -1
  63. package/dist/types/src/types/Trigger.d.ts +0 -122
  64. package/dist/types/src/types/Trigger.d.ts.map +0 -1
  65. package/dist/types/src/types/TriggerEvent.d.ts +0 -74
  66. package/dist/types/src/types/TriggerEvent.d.ts.map +0 -1
  67. package/src/errors.ts +0 -21
  68. package/src/example/fib.ts +0 -32
  69. package/src/example/forex-effect.ts +0 -40
  70. package/src/example/index.ts +0 -13
  71. package/src/example/reply.ts +0 -21
  72. package/src/example/sleep.ts +0 -24
  73. package/src/operation-compatibility.test.ts +0 -185
  74. package/src/services/event-logger.ts +0 -127
  75. package/src/types/Function.ts +0 -82
  76. package/src/types/Script.ts +0 -34
  77. package/src/types/Trigger.ts +0 -152
  78. package/src/types/TriggerEvent.ts +0 -62
@@ -1,613 +1,13 @@
1
- var __defProp = Object.defineProperty;
2
- var __export = (target, all) => {
3
- for (var name in all)
4
- __defProp(target, name, { get: all[name], enumerable: true });
5
- };
6
-
7
- // src/errors.ts
8
- import { BaseError } from "@dxos/errors";
9
- var ServiceNotAvailableError = class extends BaseError.extend("ServiceNotAvailable", "Service not available") {
10
- constructor(service, options) {
11
- super({
12
- context: {
13
- service
14
- },
15
- ...options
16
- });
17
- }
18
- };
19
- var FunctionNotFoundError = class extends BaseError.extend("FunctionNotFound", "Function not found") {
20
- constructor(functionKey, options) {
21
- super({
22
- context: {
23
- function: functionKey
24
- },
25
- ...options
26
- });
27
- }
28
- };
29
- var FunctionError = class extends BaseError.extend("FunctionError", "Function invocation error") {
30
- };
31
- var TriggerStateNotFoundError = class extends BaseError.extend("TriggerStateNotFound", "Trigger state not found") {
32
- };
33
-
34
- // src/example/fib.ts
35
- import * as Effect2 from "effect/Effect";
36
- import * as Schema6 from "effect/Schema";
37
-
38
- // src/sdk.ts
39
- import * as Effect from "effect/Effect";
40
- import * as Schema5 from "effect/Schema";
41
- import { Obj as Obj4, Type as Type5 } from "@dxos/echo";
42
- import { assertArgument, failedInvariant } from "@dxos/invariant";
43
- import { Operation } from "@dxos/operation";
44
-
45
- // src/types/Function.ts
46
- var Function_exports = {};
47
- __export(Function_exports, {
48
- Function: () => Function,
49
- make: () => make2,
50
- setFrom: () => setFrom
51
- });
52
- import * as Schema2 from "effect/Schema";
53
- import { Annotation as Annotation2, JsonSchema, Obj as Obj2, Type as Type2 } from "@dxos/echo";
54
- import { SystemTypeAnnotation } from "@dxos/echo/internal";
55
-
56
- // src/types/Script.ts
57
- var Script_exports = {};
58
- __export(Script_exports, {
59
- Script: () => Script,
60
- make: () => make
61
- });
62
- import * as Schema from "effect/Schema";
63
- import { Annotation, Obj, Ref, Type } from "@dxos/echo";
64
- import { FormInputAnnotation } from "@dxos/echo/internal";
65
- import { Text } from "@dxos/schema";
66
- var Script = Schema.Struct({
67
- name: Schema.String.pipe(Schema.optional),
68
- description: Schema.String.pipe(Schema.optional),
69
- // TODO(burdon): Change to hash of deployed content.
70
- // Whether source has changed since last deploy.
71
- changed: Schema.Boolean.pipe(FormInputAnnotation.set(false), Schema.optional),
72
- source: Type.Ref(Text.Text).pipe(FormInputAnnotation.set(false))
73
- }).pipe(Type.object({
74
- typename: "dxos.org/type/Script",
75
- version: "0.1.0"
76
- }), Annotation.LabelAnnotation.set([
77
- "name"
78
- ]));
79
- var make = ({ source = "", ...props } = {}) => Obj.make(Script, {
80
- ...props,
81
- source: Ref.make(Text.make(source))
82
- });
83
-
84
- // src/types/Function.ts
85
- var Function = Schema2.Struct({
86
- /**
87
- * Global registry ID.
88
- * NOTE: The `key` property refers to the original registry entry.
89
- */
90
- // TODO(burdon): Create Format type for DXN-like ids, such as this and schema type.
91
- // TODO(dmaretskyi): Consider making it part of ECHO meta.
92
- // TODO(dmaretskyi): Make required.
93
- key: Schema2.optional(Schema2.String).annotations({
94
- description: "Unique registration key for the blueprint"
95
- }),
96
- name: Schema2.NonEmptyString,
97
- version: Schema2.String,
98
- description: Schema2.optional(Schema2.String),
99
- /**
100
- * ISO date string of the last deployment.
101
- */
102
- updated: Schema2.optional(Schema2.String),
103
- // Reference to a source script if it exists within ECHO.
104
- // TODO(burdon): Don't ref ScriptType directly (core).
105
- source: Schema2.optional(Type2.Ref(Script)),
106
- inputSchema: Schema2.optional(JsonSchema.JsonSchema),
107
- outputSchema: Schema2.optional(JsonSchema.JsonSchema),
108
- /**
109
- * List of required services.
110
- * Match the Context.Tag keys of the FunctionServices variants.
111
- */
112
- services: Schema2.optional(Schema2.Array(Schema2.String)),
113
- // Local binding to a function name.
114
- binding: Schema2.optional(Schema2.String)
115
- }).pipe(Type2.object({
116
- typename: "dxos.org/type/Function",
117
- version: "0.1.0"
118
- }), Annotation2.LabelAnnotation.set([
119
- "name"
120
- ]), SystemTypeAnnotation.set(true));
121
- var make2 = (props) => Obj2.make(Function, props);
122
- var setFrom = (target, source) => {
123
- Obj2.change(target, (t) => {
124
- t.key = source.key ?? target.key;
125
- t.name = source.name ?? target.name;
126
- t.version = source.version;
127
- t.description = source.description;
128
- t.updated = source.updated;
129
- t.inputSchema = source.inputSchema ? JSON.parse(JSON.stringify(source.inputSchema)) : void 0;
130
- t.outputSchema = source.outputSchema ? JSON.parse(JSON.stringify(source.outputSchema)) : void 0;
131
- Obj2.getMeta(t).keys = JSON.parse(JSON.stringify(Obj2.getMeta(source).keys));
132
- });
133
- };
134
-
135
- // src/types/Trigger.ts
136
- var Trigger_exports = {};
137
- __export(Trigger_exports, {
138
- EmailSpec: () => EmailSpec,
139
- Kinds: () => Kinds,
140
- QueueSpec: () => QueueSpec,
141
- Spec: () => Spec,
142
- SubscriptionSpec: () => SubscriptionSpec,
143
- TimerSpec: () => TimerSpec,
144
- Trigger: () => Trigger,
145
- WebhookSpec: () => WebhookSpec,
146
- make: () => make3
147
- });
148
- import * as Schema3 from "effect/Schema";
149
- import * as SchemaAST from "effect/SchemaAST";
150
- import { Obj as Obj3, QueryAST, Type as Type3 } from "@dxos/echo";
151
- import { OptionsAnnotationId, SystemTypeAnnotation as SystemTypeAnnotation2 } from "@dxos/echo/internal";
152
- import { DXN } from "@dxos/keys";
153
- import { Expando } from "@dxos/schema";
154
- var Kinds = [
155
- "email",
156
- "queue",
157
- "subscription",
158
- "timer",
159
- "webhook"
160
- ];
161
- var kindLiteralAnnotations = {
162
- title: "Kind"
163
- };
164
- var EmailSpec = Schema3.Struct({
165
- kind: Schema3.Literal("email").annotations(kindLiteralAnnotations)
166
- });
167
- var QueueSpec = Schema3.Struct({
168
- kind: Schema3.Literal("queue").annotations(kindLiteralAnnotations),
169
- // TODO(dmaretskyi): Change to a reference.
170
- queue: DXN.Schema
171
- });
172
- var SubscriptionSpec = Schema3.Struct({
173
- kind: Schema3.Literal("subscription").annotations(kindLiteralAnnotations),
174
- query: Schema3.Struct({
175
- raw: Schema3.optional(Schema3.String.annotations({
176
- title: "Query"
177
- })),
178
- ast: QueryAST.Query
179
- }),
180
- options: Schema3.optional(Schema3.Struct({
181
- // Watch changes to object (not just creation).
182
- deep: Schema3.optional(Schema3.Boolean.annotations({
183
- title: "Nested"
184
- })),
185
- // Debounce changes (delay in ms).
186
- delay: Schema3.optional(Schema3.Number.annotations({
187
- title: "Delay"
188
- }))
189
- }).annotations({
190
- title: "Options"
191
- }))
192
- });
193
- var TimerSpec = Schema3.Struct({
194
- kind: Schema3.Literal("timer").annotations(kindLiteralAnnotations),
195
- cron: Schema3.String.annotations({
196
- title: "Cron",
197
- [SchemaAST.ExamplesAnnotationId]: [
198
- "0 0 * * *"
199
- ]
200
- })
201
- });
202
- var WebhookSpec = Schema3.Struct({
203
- kind: Schema3.Literal("webhook").annotations(kindLiteralAnnotations),
204
- method: Schema3.optional(Schema3.String.annotations({
205
- title: "Method",
206
- [OptionsAnnotationId]: [
207
- "GET",
208
- "POST"
209
- ]
210
- })),
211
- port: Schema3.optional(Schema3.Number.annotations({
212
- title: "Port"
213
- }))
214
- });
215
- var Spec = Schema3.Union(EmailSpec, QueueSpec, SubscriptionSpec, TimerSpec, WebhookSpec).annotations({
216
- title: "Trigger"
217
- });
218
- var TriggerSchema = Schema3.Struct({
219
- /**
220
- * Function or workflow to invoke.
221
- */
222
- // TODO(dmaretskyi): Can be a Ref(FunctionType) or Ref(ComputeGraphType).
223
- function: Schema3.optional(Type3.Ref(Expando.Expando).annotations({
224
- title: "Function"
225
- })),
226
- /**
227
- * Only used for workflowSchema.
228
- * Specifies the input node in the circuit.
229
- * @deprecated Remove and enforce a single input node in all compute graphSchema.
230
- */
231
- inputNodeId: Schema3.optional(Schema3.String.annotations({
232
- title: "Input Node ID"
233
- })),
234
- // TODO(burdon): NO BOOLEAN PROPERTIES (enabld/disabled/paused, etc.)
235
- // Need lint rule; or agent rule to require PR review for "boolean" key word.
236
- enabled: Schema3.optional(Schema3.Boolean.annotations({
237
- title: "Enabled"
238
- })),
239
- spec: Schema3.optional(Spec),
240
- concurrency: Schema3.optional(Schema3.Number.annotations({
241
- title: "Concurrency",
242
- default: 1,
243
- description: "Maximum number of concurrent invocations of the trigger. For queue triggers, this will process queue items in parallel."
244
- })),
245
- /**
246
- * Passed as the input data to the function.
247
- * Must match the function's input schema.
248
- *
249
- * @example
250
- * {
251
- * item: '{{$.trigger.event}}',
252
- * instructions: 'Summarize and perform entity-extraction'
253
- * mailbox: { '/': 'dxn:echo:AAA:ZZZ' }
254
- * }
255
- */
256
- input: Schema3.optional(Schema3.Record({
257
- key: Schema3.String,
258
- value: Schema3.Any
259
- }))
260
- }).pipe(Type3.object({
261
- typename: "dxos.org/type/Trigger",
262
- version: "0.1.0"
263
- }), SystemTypeAnnotation2.set(true));
264
- var Trigger = TriggerSchema;
265
- var make3 = (props) => Obj3.make(Trigger, props);
266
-
267
- // src/types/TriggerEvent.ts
268
- var TriggerEvent_exports = {};
269
- __export(TriggerEvent_exports, {
270
- EmailEvent: () => EmailEvent,
271
- QueueEvent: () => QueueEvent,
272
- SubscriptionEvent: () => SubscriptionEvent,
273
- TimerEvent: () => TimerEvent,
274
- TriggerEvent: () => TriggerEvent,
275
- WebhookEvent: () => WebhookEvent
276
- });
277
- import * as Schema4 from "effect/Schema";
278
- import { DXN as DXN2, Type as Type4 } from "@dxos/echo";
279
- var EmailEvent = Schema4.Struct({
280
- from: Schema4.String,
281
- to: Schema4.String,
282
- subject: Schema4.String,
283
- created: Schema4.String,
284
- body: Schema4.String
285
- });
286
- var QueueEvent = Schema4.Struct({
287
- queue: DXN2.Schema,
288
- item: Schema4.Any,
289
- cursor: Schema4.String
290
- });
291
- var SubscriptionEvent = Schema4.Struct({
292
- /**
293
- * Type of the mutation.
294
- */
295
- // TODO(dmaretskyi): Specify enum.
296
- type: Schema4.String,
297
- /**
298
- * Reference to the object that was changed or created.
299
- */
300
- subject: Type4.Ref(Type4.Obj),
301
- /**
302
- * @deprecated
303
- */
304
- changedObjectId: Schema4.optional(Schema4.String)
305
- });
306
- var TimerEvent = Schema4.Struct({
307
- tick: Schema4.Number
308
- });
309
- var WebhookEvent = Schema4.Struct({
310
- url: Schema4.String,
311
- method: Schema4.Literal("GET", "POST"),
312
- headers: Schema4.Record({
313
- key: Schema4.String,
314
- value: Schema4.String
315
- }),
316
- bodyText: Schema4.String
317
- });
318
- var TriggerEvent = Schema4.Union(EmailEvent, QueueEvent, SubscriptionEvent, TimerEvent, WebhookEvent);
319
-
320
- // src/types/url.ts
321
- var FUNCTIONS_META_KEY = "dxos.org/service/function";
322
- var FUNCTIONS_PRESET_META_KEY = "dxos.org/service/function-preset";
323
- var getUserFunctionIdInMetadata = (meta) => {
324
- return meta.keys.find((key) => key.source === FUNCTIONS_META_KEY)?.id;
325
- };
326
- var setUserFunctionIdInMetadata = (meta, functionId) => {
327
- const key = meta.keys.find((key2) => key2.source === FUNCTIONS_META_KEY);
328
- if (key) {
329
- if (key.id !== functionId) {
330
- throw new Error("Metadata mismatch");
331
- }
332
- } else {
333
- meta.keys.push({
334
- source: FUNCTIONS_META_KEY,
335
- id: functionId
336
- });
337
- }
338
- };
339
-
340
- // src/sdk.ts
341
- var typeId = Symbol.for("@dxos/functions/FunctionDefinition");
342
- var defineFunction = ({ key, name, description, inputSchema, outputSchema = Schema5.Any, handler, types, services }) => {
343
- if (!Schema5.isSchema(inputSchema)) {
344
- throw new Error("Input schema must be a valid schema");
345
- }
346
- if (typeof handler !== "function") {
347
- throw new Error("Handler must be a function");
348
- }
349
- const limit = Error.stackTraceLimit;
350
- Error.stackTraceLimit = 2;
351
- const traceError = new Error();
352
- Error.stackTraceLimit = limit;
353
- let cache = false;
354
- const captureStackTrace = () => {
355
- if (cache !== false) {
356
- return cache;
357
- }
358
- if (traceError.stack !== void 0) {
359
- const stack = traceError.stack.split("\n");
360
- if (stack[2] !== void 0) {
361
- cache = stack[2].trim();
362
- return cache;
363
- }
364
- }
365
- };
366
- const handlerWithSpan = (...args) => {
367
- const result = handler(...args);
368
- if (Effect.isEffect(result)) {
369
- return Effect.withSpan(result, `${key ?? name}`, {
370
- captureStackTrace
371
- });
372
- }
373
- return result;
374
- };
375
- return {
376
- [typeId]: true,
377
- key,
378
- name,
379
- description,
380
- inputSchema,
381
- outputSchema,
382
- handler: handlerWithSpan,
383
- types: types ?? [],
384
- services: !services ? [] : getServiceKeys(services)
385
- };
386
- };
387
- var getServiceKeys = (services) => {
388
- return services.map((tag) => {
389
- if (typeof tag.key === "string") {
390
- return tag.key;
391
- }
392
- failedInvariant();
393
- });
394
- };
395
- var toOperation = (functionDef) => {
396
- const op = Operation.make({
397
- schema: {
398
- input: functionDef.inputSchema,
399
- output: functionDef.outputSchema ?? Schema5.Any
400
- },
401
- meta: {
402
- key: functionDef.key,
403
- name: functionDef.name,
404
- description: functionDef.description
405
- }
406
- });
407
- const operationHandler = (input) => {
408
- const result = functionDef.handler({
409
- context: {},
410
- data: input
411
- });
412
- if (Effect.isEffect(result)) {
413
- return result;
414
- }
415
- if (result instanceof Promise) {
416
- return Effect.tryPromise(() => result);
417
- }
418
- return Effect.succeed(result);
419
- };
420
- return {
421
- ...op,
422
- handler: operationHandler
423
- };
424
- };
425
- var FunctionDefinition = {
426
- make: defineFunction,
427
- isFunction: (value2) => {
428
- return typeof value2 === "object" && value2 !== null && Symbol.for("@dxos/functions/FunctionDefinition") in value2;
429
- },
430
- serialize: (functionDef) => {
431
- assertArgument(FunctionDefinition.isFunction(functionDef), "functionDef");
432
- return serializeFunction(functionDef);
433
- },
434
- deserialize: (functionObj) => {
435
- assertArgument(Obj4.instanceOf(Function_exports.Function, functionObj), "functionObj");
436
- return deserializeFunction(functionObj);
437
- },
438
- toOperation
439
- };
440
- var serializeFunction = (functionDef) => {
441
- const fn4 = Function_exports.make({
442
- key: functionDef.key,
443
- name: functionDef.name,
444
- version: "0.1.0",
445
- description: functionDef.description,
446
- inputSchema: Type5.toJsonSchema(functionDef.inputSchema),
447
- outputSchema: !functionDef.outputSchema ? void 0 : Type5.toJsonSchema(functionDef.outputSchema),
448
- services: functionDef.services
449
- });
450
- if (functionDef.meta?.deployedFunctionId) {
451
- Obj4.change(fn4, (fn5) => setUserFunctionIdInMetadata(Obj4.getMeta(fn5), functionDef.meta.deployedFunctionId));
452
- }
453
- return fn4;
454
- };
455
- var deserializeFunction = (functionObj) => {
456
- return {
457
- [typeId]: true,
458
- // TODO(dmaretskyi): Fix key.
459
- key: functionObj.key ?? functionObj.name,
460
- name: functionObj.name,
461
- description: functionObj.description,
462
- inputSchema: !functionObj.inputSchema ? Schema5.Unknown : Type5.toEffectSchema(functionObj.inputSchema),
463
- outputSchema: !functionObj.outputSchema ? void 0 : Type5.toEffectSchema(functionObj.outputSchema),
464
- // TODO(dmaretskyi): This should throw error.
465
- handler: () => {
466
- },
467
- services: functionObj.services ?? [],
468
- types: [],
469
- meta: {
470
- deployedFunctionId: getUserFunctionIdInMetadata(Obj4.getMeta(functionObj))
471
- }
472
- };
473
- };
474
-
475
- // src/example/fib.ts
476
- var fib_default = defineFunction({
477
- key: "example.org/function/fib",
478
- name: "Fibonacci",
479
- description: "Function that calculates a Fibonacci number",
480
- inputSchema: Schema6.Struct({
481
- iterations: Schema6.optional(Schema6.Number).annotations({
482
- description: "Number of iterations",
483
- default: 1e5
484
- })
485
- }),
486
- outputSchema: Schema6.Struct({
487
- result: Schema6.String
488
- }),
489
- handler: Effect2.fn(function* ({ data: { iterations = 1e5 } }) {
490
- let a = 0n;
491
- let b = 1n;
492
- for (let i = 0; i < iterations; i++) {
493
- a += b;
494
- b = a - b;
495
- }
496
- return {
497
- result: a.toString()
498
- };
499
- })
500
- });
501
-
502
- // src/example/reply.ts
503
- import * as Console from "effect/Console";
504
- import * as Effect3 from "effect/Effect";
505
- import * as Schema7 from "effect/Schema";
506
- var reply_default = defineFunction({
507
- key: "example.org/function/reply",
508
- name: "Reply",
509
- description: "Function that echoes the input",
510
- inputSchema: Schema7.Any,
511
- outputSchema: Schema7.Any,
512
- handler: Effect3.fn(function* ({ data }) {
513
- yield* Console.log("reply", {
514
- data
515
- });
516
- return data;
517
- })
518
- });
519
-
520
- // src/example/sleep.ts
521
- import * as Effect4 from "effect/Effect";
522
- import * as Schema8 from "effect/Schema";
523
- var sleep_default = defineFunction({
524
- key: "example.org/function/sleep",
525
- name: "Sleep",
526
- description: "Function that sleeps for a given amount of time",
527
- inputSchema: Schema8.Struct({
528
- duration: Schema8.optional(Schema8.Number).annotations({
529
- description: "Milliseconds to sleep",
530
- default: 1e5
531
- })
532
- }),
533
- outputSchema: Schema8.Void,
534
- handler: Effect4.fn(function* ({ data: { duration = 1e5 } }) {
535
- yield* Effect4.sleep(duration);
536
- })
537
- });
538
-
539
- // src/example/index.ts
540
- (function(Example2) {
541
- Example2.fib = fib_default;
542
- Example2.reply = reply_default;
543
- Example2.sleep = sleep_default;
544
- })(Example || (Example = {}));
545
- var Example;
546
-
547
1
  // src/services/credentials.ts
548
2
  import * as HttpClient from "@effect/platform/HttpClient";
549
3
  import * as HttpClientRequest from "@effect/platform/HttpClientRequest";
550
- import * as Context from "effect/Context";
551
- import * as Effect5 from "effect/Effect";
4
+ import * as Effect from "effect/Effect";
552
5
  import * as Layer from "effect/Layer";
553
6
  import * as Redacted from "effect/Redacted";
7
+ import { Credential } from "@dxos/compute";
554
8
  import { Query } from "@dxos/echo";
555
9
  import { Database } from "@dxos/echo";
556
10
  import { AccessToken } from "@dxos/types";
557
- var CredentialsService = class _CredentialsService extends Context.Tag("@dxos/functions/CredentialsService")() {
558
- static getCredential = (query) => Effect5.gen(function* () {
559
- const credentials = yield* _CredentialsService;
560
- return yield* Effect5.promise(() => credentials.getCredential(query));
561
- });
562
- static getApiKey = (query) => Effect5.gen(function* () {
563
- const credential = yield* _CredentialsService.getCredential(query);
564
- if (!credential.apiKey) {
565
- throw new Error(`API key not found for service: ${query.service}`);
566
- }
567
- return Redacted.make(credential.apiKey);
568
- });
569
- static configuredLayer = (credentials) => Layer.succeed(_CredentialsService, new ConfiguredCredentialsService(credentials));
570
- static layerConfig = (credentials) => Layer.effect(_CredentialsService, Effect5.gen(function* () {
571
- const serviceCredentials = yield* Effect5.forEach(credentials, ({ service, apiKey }) => Effect5.gen(function* () {
572
- return {
573
- service,
574
- apiKey: Redacted.value(yield* apiKey)
575
- };
576
- }));
577
- return new ConfiguredCredentialsService(serviceCredentials);
578
- }));
579
- static layerFromDatabase = ({ caching = false } = {}) => Layer.effect(_CredentialsService, Effect5.gen(function* () {
580
- const dbService = yield* Database.Service;
581
- const cache = /* @__PURE__ */ new Map();
582
- const queryCredentials = async (query) => {
583
- const cacheKey = JSON.stringify(query);
584
- if (caching && cache.has(cacheKey)) {
585
- return cache.get(cacheKey);
586
- }
587
- const accessTokens = await dbService.db.query(Query.type(AccessToken.AccessToken)).run();
588
- const credentials = accessTokens.filter((accessToken) => accessToken.source === query.service).map((accessToken) => ({
589
- service: accessToken.source,
590
- apiKey: accessToken.token
591
- }));
592
- if (caching) {
593
- cache.set(cacheKey, credentials);
594
- }
595
- return credentials;
596
- };
597
- return {
598
- getCredential: async (query) => {
599
- const credentials = await queryCredentials(query);
600
- if (credentials.length === 0) {
601
- throw new Error(`Credential not found for service: ${query.service}`);
602
- }
603
- return credentials[0];
604
- },
605
- queryCredentials: async (query) => {
606
- return queryCredentials(query);
607
- }
608
- };
609
- }));
610
- };
611
11
  var ConfiguredCredentialsService = class {
612
12
  credentials;
613
13
  constructor(credentials = []) {
@@ -632,277 +32,127 @@ var withAuthorization = (token, kind) => HttpClient.mapRequest((request) => {
632
32
  const authorization = kind ? `${kind} ${token}` : token;
633
33
  return HttpClientRequest.setHeader(request, "Authorization", authorization);
634
34
  });
635
-
636
- // src/services/event-logger.ts
637
- import * as Context3 from "effect/Context";
638
- import * as Effect7 from "effect/Effect";
639
- import * as Layer3 from "effect/Layer";
640
- import * as Schema9 from "effect/Schema";
641
- import { Obj as Obj6, Type as Type6 } from "@dxos/echo";
642
- import { invariant } from "@dxos/invariant";
643
- import { LogLevel, log as log2 } from "@dxos/log";
644
-
645
- // src/services/tracing.ts
646
- import * as Context2 from "effect/Context";
647
- import * as Effect6 from "effect/Effect";
648
- import * as Layer2 from "effect/Layer";
649
- import { AgentStatus } from "@dxos/ai";
650
- import { Obj as Obj5 } from "@dxos/echo";
651
- import { ObjectId } from "@dxos/keys";
652
- import { Message } from "@dxos/types";
653
- var TracingService = class _TracingService extends Context2.Tag("@dxos/functions/TracingService")() {
654
- static noop = {
655
- getTraceContext: () => ({}),
656
- write: () => {
657
- },
658
- traceInvocationStart: () => Effect6.sync(() => ({
659
- invocationId: ObjectId.random(),
660
- invocationTraceQueue: void 0
661
- })),
662
- traceInvocationEnd: () => Effect6.sync(() => {
663
- })
664
- };
665
- static layerNoop = Layer2.succeed(_TracingService, _TracingService.noop);
666
- /**
667
- * Creates a TracingService layer that emits events to the parent tracing service.
668
- */
669
- static layerSubframe = (mapContext) => Layer2.effect(_TracingService, Effect6.gen(function* () {
670
- const tracing = yield* _TracingService;
671
- const context = mapContext(tracing.getTraceContext());
35
+ var configuredCredentialsLayer = (credentials) => Layer.succeed(Credential.CredentialsService, new ConfiguredCredentialsService(credentials));
36
+ var credentialsLayerConfig = (credentials) => Layer.effect(Credential.CredentialsService, Effect.gen(function* () {
37
+ const serviceCredentials = yield* Effect.forEach(credentials, ({ service, apiKey }) => Effect.gen(function* () {
672
38
  return {
673
- write: (event, context2) => tracing.write(event, context2),
674
- getTraceContext: () => context,
675
- traceInvocationStart: () => Effect6.die("Tracing invocation inside another invocation is not supported."),
676
- traceInvocationEnd: () => Effect6.die("Tracing invocation inside another invocation is not supported.")
39
+ service,
40
+ apiKey: Redacted.value(yield* apiKey)
677
41
  };
678
42
  }));
679
- /**
680
- * Create sublayer to trace an invocation.
681
- * @param data
682
- * @returns
683
- */
684
- static layerInvocation = (data) => _TracingService.layerSubframe((context) => ({
685
- ...context,
686
- currentInvocation: data
687
- }));
688
- /**
689
- * Emit the current human-readable execution status.
690
- */
691
- static emitStatus = Effect6.fnUntraced(function* (data) {
692
- const tracing = yield* _TracingService;
693
- tracing.write(Obj5.make(AgentStatus, {
694
- parentMessage: tracing.getTraceContext().parentMessage,
695
- toolCallId: tracing.getTraceContext().toolCallId,
696
- created: (/* @__PURE__ */ new Date()).toISOString(),
697
- ...data
698
- }), tracing.getTraceContext());
699
- });
700
- static emitConverationMessage = Effect6.fnUntraced(function* (data) {
701
- const tracing = yield* _TracingService;
702
- tracing.write(Obj5.make(Message.Message, {
703
- parentMessage: tracing.getTraceContext().parentMessage,
704
- ...data,
705
- properties: {
706
- [MESSAGE_PROPERTY_TOOL_CALL_ID]: tracing.getTraceContext().toolCallId,
707
- ...data.properties
708
- }
709
- }), tracing.getTraceContext());
710
- });
711
- };
712
- var MESSAGE_PROPERTY_TOOL_CALL_ID = "toolCallId";
713
-
714
- // src/services/event-logger.ts
715
- var __dxlog_file = "/__w/dxos/dxos/packages/core/functions/src/services/event-logger.ts";
716
- var ComputeEventPayload = Schema9.Union(Schema9.Struct({
717
- type: Schema9.Literal("begin-compute"),
718
- nodeId: Schema9.String,
719
- /**
720
- * Names of the inputs begin computed.
721
- */
722
- inputs: Schema9.Array(Schema9.String)
723
- }), Schema9.Struct({
724
- type: Schema9.Literal("end-compute"),
725
- nodeId: Schema9.String,
726
- /**
727
- * Names of the outputs computed.
728
- */
729
- outputs: Schema9.Array(Schema9.String)
730
- }), Schema9.Struct({
731
- type: Schema9.Literal("compute-input"),
732
- nodeId: Schema9.String,
733
- property: Schema9.String,
734
- value: Schema9.Any
735
- }), Schema9.Struct({
736
- type: Schema9.Literal("compute-output"),
737
- nodeId: Schema9.String,
738
- property: Schema9.String,
739
- value: Schema9.Any
740
- }), Schema9.Struct({
741
- type: Schema9.Literal("custom"),
742
- nodeId: Schema9.String,
743
- event: Schema9.Any
744
- }));
745
- var ComputeEvent = Schema9.Struct({
746
- payload: ComputeEventPayload
747
- }).pipe(Type6.object({
748
- typename: "dxos.org/type/ComputeEvent",
749
- version: "0.1.0"
43
+ return new ConfiguredCredentialsService(serviceCredentials);
750
44
  }));
751
- var ComputeEventLogger = class _ComputeEventLogger extends Context3.Tag("@dxos/functions/ComputeEventLogger")() {
752
- static noop = {
753
- log: () => {
754
- },
755
- nodeId: void 0
45
+ var credentialsLayerFromDatabase = ({ caching = false } = {}) => Layer.effect(Credential.CredentialsService, Effect.gen(function* () {
46
+ const dbService = yield* Database.Service;
47
+ const cache = /* @__PURE__ */ new Map();
48
+ const queryCredentials = async (query) => {
49
+ const cacheKey = JSON.stringify(query);
50
+ if (caching && cache.has(cacheKey)) {
51
+ return cache.get(cacheKey);
52
+ }
53
+ const accessTokens = await dbService.db.query(Query.type(AccessToken.AccessToken)).run();
54
+ const credentials = accessTokens.filter((accessToken) => accessToken.source === query.service).map((accessToken) => ({
55
+ service: accessToken.source,
56
+ apiKey: accessToken.token
57
+ }));
58
+ if (caching) {
59
+ cache.set(cacheKey, credentials);
60
+ }
61
+ return credentials;
756
62
  };
757
- /**
758
- * Implements ComputeEventLogger using TracingService.
759
- */
760
- static layerFromTracing = Layer3.effect(_ComputeEventLogger, Effect7.gen(function* () {
761
- const tracing = yield* TracingService;
762
- return {
763
- log: (event) => {
764
- tracing.write(Obj6.make(ComputeEvent, {
765
- payload: event
766
- }), tracing.getTraceContext());
767
- },
768
- nodeId: void 0
769
- };
770
- }));
771
- };
772
- var logCustomEvent = (data) => Effect7.gen(function* () {
773
- const logger = yield* ComputeEventLogger;
774
- if (!logger.nodeId) {
775
- throw new Error("logCustomEvent must be called within a node compute function");
776
- }
777
- logger.log({
778
- type: "custom",
779
- nodeId: logger.nodeId,
780
- event: data
781
- });
782
- });
783
- var createDefectLogger = () => Effect7.catchAll((error) => Effect7.gen(function* () {
784
- log2.error("unhandled effect error", {
785
- error
786
- }, {
787
- F: __dxlog_file,
788
- L: 102,
789
- S: this,
790
- C: (f, a) => f(...a)
791
- });
792
- throw error;
793
- }));
794
- var createEventLogger = (level, message = "event") => {
795
- const logFunction = {
796
- [LogLevel.WARN]: log2.warn,
797
- [LogLevel.VERBOSE]: log2.verbose,
798
- [LogLevel.DEBUG]: log2.debug,
799
- [LogLevel.INFO]: log2.info,
800
- [LogLevel.ERROR]: log2.error
801
- }[level];
802
- invariant(logFunction, void 0, {
803
- F: __dxlog_file,
804
- L: 120,
805
- S: void 0,
806
- A: [
807
- "logFunction",
808
- ""
809
- ]
810
- });
811
63
  return {
812
- log: (event) => {
813
- logFunction(message, event);
64
+ getCredential: async (query) => {
65
+ const credentials = await queryCredentials(query);
66
+ if (credentials.length === 0) {
67
+ throw new Error(`Credential not found for service: ${query.service}`);
68
+ }
69
+ return credentials[0];
814
70
  },
815
- nodeId: void 0
71
+ queryCredentials: async (query) => {
72
+ return queryCredentials(query);
73
+ }
816
74
  };
817
- };
75
+ }));
818
76
 
819
77
  // src/services/function-invocation-service.ts
820
- import * as Context4 from "effect/Context";
821
- import * as Effect8 from "effect/Effect";
822
- import * as Layer4 from "effect/Layer";
823
- var FunctionInvocationService = class _FunctionInvocationService extends Context4.Tag("@dxos/functions/FunctionInvocationService")() {
824
- static layerNotAvailable = Layer4.succeed(_FunctionInvocationService, {
825
- invokeFunction: () => Effect8.die("FunctionInvocationService is not avaialble."),
826
- resolveFunction: () => Effect8.die("FunctionInvocationService is not available.")
78
+ import * as Context from "effect/Context";
79
+ import * as Effect2 from "effect/Effect";
80
+ import * as Layer2 from "effect/Layer";
81
+ var FunctionInvocationService = class _FunctionInvocationService extends Context.Tag("@dxos/functions/FunctionInvocationService")() {
82
+ static layerNotAvailable = Layer2.succeed(_FunctionInvocationService, {
83
+ invokeFunction: () => Effect2.die("FunctionInvocationService is not avaialble."),
84
+ resolveFunction: () => Effect2.die("FunctionInvocationService is not available.")
827
85
  });
828
- static invokeFunction = (functionDef, input) => Effect8.serviceFunctionEffect(_FunctionInvocationService, (service) => service.invokeFunction)(functionDef, input);
829
- static resolveFunction = (key) => Effect8.serviceFunctionEffect(_FunctionInvocationService, (service) => service.resolveFunction)(key);
86
+ static invokeFunction = (functionDef, input) => Effect2.serviceFunctionEffect(_FunctionInvocationService, (service) => service.invokeFunction)(functionDef, input);
87
+ static resolveFunction = (key) => Effect2.serviceFunctionEffect(_FunctionInvocationService, (service) => service.resolveFunction)(key);
830
88
  };
831
89
 
832
90
  // src/services/queues.ts
833
- import * as Context5 from "effect/Context";
834
- import * as Effect9 from "effect/Effect";
835
- import * as Layer5 from "effect/Layer";
836
- var QueueService = class _QueueService extends Context5.Tag("@dxos/functions/QueueService")() {
837
- static notAvailable = Layer5.succeed(_QueueService, {
838
- queues: {
839
- get(_dxn) {
840
- throw new Error("Queues not available");
841
- },
842
- create() {
843
- throw new Error("Queues not available");
844
- }
845
- },
846
- queue: void 0
847
- });
848
- static make = (queues, queue) => {
849
- return {
850
- queues,
851
- queue
852
- };
853
- };
854
- static layer = (queues, queue) => Layer5.succeed(_QueueService, _QueueService.make(queues, queue));
855
- /**
856
- * Gets a queue by its DXN.
857
- */
858
- static getQueue = (dxn) => _QueueService.pipe(Effect9.map(({ queues }) => queues.get(dxn)));
859
- /**
860
- * Creates a new queue.
861
- */
862
- static createQueue = (options) => _QueueService.pipe(Effect9.map(({ queues }) => queues.create(options)));
863
- static append = (queue, objects) => Effect9.promise(() => queue.append(objects));
91
+ import { ContextQueueService, QueueService, feedServiceFromQueueServiceLayer } from "@dxos/echo-db";
92
+
93
+ // src/services/tracing.ts
94
+ var MESSAGE_PROPERTY_TOOL_CALL_ID = "toolCallId";
95
+
96
+ // src/types/url.ts
97
+ var FUNCTIONS_META_KEY = "org.dxos.service.function";
98
+ var FUNCTIONS_PRESET_META_KEY = "org.dxos.service.function-preset";
99
+ var getUserFunctionIdInMetadata = (meta) => {
100
+ return meta.keys.find((key) => key.source === FUNCTIONS_META_KEY)?.id;
864
101
  };
865
- var ContextQueueService = class _ContextQueueService extends Context5.Tag("@dxos/functions/ContextQueueService")() {
866
- static layer = (queue) => Layer5.succeed(_ContextQueueService, {
867
- queue
868
- });
102
+ var setUserFunctionIdInMetadata = (meta, functionId) => {
103
+ const key = meta.keys.find((key2) => key2.source === FUNCTIONS_META_KEY);
104
+ if (key) {
105
+ if (key.id !== functionId) {
106
+ throw new Error("Metadata mismatch");
107
+ }
108
+ } else {
109
+ meta.keys.push({
110
+ source: FUNCTIONS_META_KEY,
111
+ id: functionId
112
+ });
113
+ }
869
114
  };
870
115
 
871
116
  // src/protocol/protocol.ts
872
117
  import * as AnthropicClient from "@effect/ai-anthropic/AnthropicClient";
873
- import * as Effect11 from "effect/Effect";
874
- import * as Layer7 from "effect/Layer";
875
- import * as Schema10 from "effect/Schema";
876
- import * as SchemaAST2 from "effect/SchemaAST";
877
- import { AiModelResolver, AiService } from "@dxos/ai";
118
+ import * as Effect4 from "effect/Effect";
119
+ import * as Layer4 from "effect/Layer";
120
+ import * as Option from "effect/Option";
121
+ import * as Schema from "effect/Schema";
122
+ import * as SchemaAST from "effect/SchemaAST";
123
+ import { AiModelResolver, AiService, OpaqueToolkit } from "@dxos/ai";
878
124
  import { AnthropicResolver } from "@dxos/ai/resolvers";
125
+ import { FunctionError, InvalidOperationInputError, InvalidOperationOutputError, Operation, OperationRegistry, Trace } from "@dxos/compute";
879
126
  import { LifecycleState, Resource } from "@dxos/context";
880
- import { Database as Database2, Ref as Ref2, Type as Type7 } from "@dxos/echo";
127
+ import { Database as Database2, Feed, JsonSchema, Ref } from "@dxos/echo";
128
+ import { createFeedServiceLayer, EchoClient } from "@dxos/echo-db";
881
129
  import { refFromEncodedReference } from "@dxos/echo/internal";
882
- import { EchoClient } from "@dxos/echo-db";
883
130
  import { runAndForwardErrors } from "@dxos/effect";
884
- import { assertState, failedInvariant as failedInvariant2, invariant as invariant2 } from "@dxos/invariant";
131
+ import { assertState, failedInvariant, invariant } from "@dxos/invariant";
885
132
  import { PublicKey } from "@dxos/keys";
133
+ import { log as log2 } from "@dxos/log";
134
+ import { ErrorCodec as ErrorCodec2 } from "@dxos/protocols";
886
135
 
887
136
  // src/protocol/functions-ai-http-client.ts
888
137
  import * as Headers from "@effect/platform/Headers";
889
138
  import * as HttpClient2 from "@effect/platform/HttpClient";
890
139
  import * as HttpClientError from "@effect/platform/HttpClientError";
891
140
  import * as HttpClientResponse from "@effect/platform/HttpClientResponse";
892
- import * as Effect10 from "effect/Effect";
141
+ import * as Effect3 from "effect/Effect";
893
142
  import * as FiberRef from "effect/FiberRef";
894
- import * as Layer6 from "effect/Layer";
143
+ import * as Layer3 from "effect/Layer";
895
144
  import * as Stream from "effect/Stream";
896
- import { log as log3 } from "@dxos/log";
145
+ import { FunctionsAiMemoizationMissError, FunctionsAiUpstreamError } from "@dxos/compute";
146
+ import { log } from "@dxos/log";
897
147
  import { ErrorCodec } from "@dxos/protocols";
898
- var __dxlog_file2 = "/__w/dxos/dxos/packages/core/functions/src/protocol/functions-ai-http-client.ts";
148
+ var __dxlog_file = "/__w/dxos/dxos/packages/core/compute/functions/src/protocol/functions-ai-http-client.ts";
899
149
  var requestInitTagKey = "@effect/platform/FetchHttpClient/FetchOptions";
900
150
  var FunctionsAiHttpClient = class _FunctionsAiHttpClient {
901
151
  static make = (service) => HttpClient2.make((request, url, signal, fiber) => {
902
152
  const context = fiber.getFiberRef(FiberRef.currentContext);
903
153
  const options = context.unsafeMap.get(requestInitTagKey) ?? {};
904
154
  const headers = options.headers ? Headers.merge(Headers.fromInput(options.headers), request.headers) : request.headers;
905
- const send = (body) => Effect10.tryPromise({
155
+ const send = (body) => Effect3.tryPromise({
906
156
  try: () => service.fetch(new Request(url, {
907
157
  ...options,
908
158
  method: request.method,
@@ -910,21 +160,21 @@ var FunctionsAiHttpClient = class _FunctionsAiHttpClient {
910
160
  body
911
161
  })),
912
162
  catch: (cause) => {
913
- log3.error("Failed to fetch", {
163
+ log.error("Failed to fetch", {
914
164
  errorSerialized: ErrorCodec.encode(cause)
915
- }, {
916
- F: __dxlog_file2,
917
- L: 43,
918
- S: this,
919
- C: (f, a) => f(...a)
920
- });
165
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 31, S: this });
921
166
  return new HttpClientError.RequestError({
922
167
  request,
923
168
  reason: "Transport",
924
169
  cause
925
170
  });
926
171
  }
927
- }).pipe(Effect10.map((response) => HttpClientResponse.fromWeb(request, response)));
172
+ }).pipe(Effect3.flatMap((response) => (
173
+ // Inspect the body before handing the response to `@effect/ai` so that structured
174
+ // upstream errors surface as typed defects (`FunctionsAiUpstreamError` and friends)
175
+ // rather than as the generic `HttpResponseError` from `@effect/ai/AiError`.
176
+ Effect3.flatMap(Effect3.promise(() => parseUpstreamError(response)), (typedError) => typedError ? Effect3.die(typedError) : Effect3.succeed(HttpClientResponse.fromWeb(request, response)))
177
+ )));
928
178
  switch (request.body._tag) {
929
179
  case "Raw":
930
180
  case "Uint8Array":
@@ -932,14 +182,54 @@ var FunctionsAiHttpClient = class _FunctionsAiHttpClient {
932
182
  case "FormData":
933
183
  return send(request.body.formData);
934
184
  case "Stream":
935
- return Stream.toReadableStreamEffect(request.body.stream).pipe(Effect10.flatMap(send));
185
+ return Stream.toReadableStreamEffect(request.body.stream).pipe(Effect3.flatMap(send));
936
186
  }
937
187
  return send(void 0);
938
188
  });
939
- static layer = (service) => Layer6.succeed(HttpClient2.HttpClient, _FunctionsAiHttpClient.make(service));
189
+ static layer = (service) => Layer3.succeed(HttpClient2.HttpClient, _FunctionsAiHttpClient.make(service));
190
+ };
191
+ var parseUpstreamError = async (response) => {
192
+ if (response.ok) {
193
+ return void 0;
194
+ }
195
+ const contentType = response.headers.get("content-type") ?? "";
196
+ if (!contentType.toLowerCase().includes("application/json")) {
197
+ return void 0;
198
+ }
199
+ let body;
200
+ try {
201
+ body = await response.clone().json();
202
+ } catch {
203
+ return void 0;
204
+ }
205
+ if (!body || body.type !== "error" || typeof body.error !== "object" || body.error === null) {
206
+ return void 0;
207
+ }
208
+ const inner = body.error;
209
+ const message = inner.message ?? `Upstream AI service responded with HTTP ${response.status}`;
210
+ if (inner.type === "memoization_miss" && typeof inner.cacheKey === "string") {
211
+ return new FunctionsAiMemoizationMissError({
212
+ message,
213
+ context: {
214
+ cacheKey: inner.cacheKey,
215
+ status: response.status
216
+ }
217
+ });
218
+ }
219
+ return new FunctionsAiUpstreamError({
220
+ message,
221
+ context: {
222
+ type: inner.type,
223
+ status: response.status,
224
+ ...inner.cacheKey ? {
225
+ cacheKey: inner.cacheKey
226
+ } : {}
227
+ }
228
+ });
940
229
  };
941
230
 
942
231
  // src/protocol/protocol.ts
232
+ var __dxlog_file2 = "/__w/dxos/dxos/packages/core/compute/functions/src/protocol/protocol.ts";
943
233
  function _ts_add_disposable_resource(env, value2, async) {
944
234
  if (value2 !== null && value2 !== void 0) {
945
235
  if (typeof value2 !== "object" && typeof value2 !== "function") throw new TypeError("Object expected.");
@@ -1005,22 +295,22 @@ function _ts_dispose_resources(env) {
1005
295
  return next();
1006
296
  })(env);
1007
297
  }
1008
- var __dxlog_file3 = "/__w/dxos/dxos/packages/core/functions/src/protocol/protocol.ts";
1009
- var wrapFunctionHandler = (func) => {
1010
- if (!FunctionDefinition.isFunction(func)) {
1011
- throw new TypeError("Invalid function definition");
298
+ var wrapFunctionHandler = (func, opts = {}) => {
299
+ if (!Operation.isOperationWithHandler(func)) {
300
+ throw new TypeError("Expected operation with handler");
1012
301
  }
302
+ const serviceTags = func.services.map((service) => service.key);
1013
303
  return {
1014
304
  meta: {
1015
- key: func.key,
1016
- name: func.name,
1017
- description: func.description,
1018
- inputSchema: Type7.toJsonSchema(func.inputSchema),
1019
- outputSchema: func.outputSchema === void 0 ? void 0 : Type7.toJsonSchema(func.outputSchema),
1020
- services: func.services
305
+ key: func.meta.key,
306
+ name: func.meta.name,
307
+ description: func.meta.description,
308
+ inputSchema: JsonSchema.toJsonSchema(func.input),
309
+ outputSchema: func.output === void 0 ? void 0 : JsonSchema.toJsonSchema(func.output),
310
+ services: func.services.map((service) => service.key)
1021
311
  },
1022
312
  handler: async ({ data, context }) => {
1023
- if ((func.services.includes(Database2.Service.key) || func.services.includes(QueueService.key)) && (!context.services.dataService || !context.services.queryService)) {
313
+ if ((serviceTags.includes(Database2.Service.key) || serviceTags.includes(QueueService.key) || serviceTags.includes(Feed.FeedService.key)) && (!context.services.dataService || !context.services.queryService)) {
1024
314
  throw new FunctionError({
1025
315
  message: "Services not provided: dataService, queryService"
1026
316
  });
@@ -1032,40 +322,43 @@ var wrapFunctionHandler = (func) => {
1032
322
  hasError: false
1033
323
  };
1034
324
  try {
1035
- if (!SchemaAST2.isAnyKeyword(func.inputSchema.ast)) {
325
+ if (!SchemaAST.isAnyKeyword(func.input.ast)) {
1036
326
  try {
1037
- Schema10.validateSync(func.inputSchema)(data);
327
+ Schema.validateSync(func.input, {
328
+ onExcessProperty: "error"
329
+ })(data);
1038
330
  } catch (error) {
1039
- throw new FunctionError({
1040
- message: "Invalid input schema",
331
+ throw new InvalidOperationInputError({
332
+ message: `Operation input did not match schema (${func.meta.key}): ${error.message}`,
1041
333
  cause: error
1042
334
  });
1043
335
  }
1044
336
  }
1045
- const funcContext = _ts_add_disposable_resource(env, await new FunctionContext(context).open(), true);
1046
- if (func.types.length > 0) {
1047
- invariant2(funcContext.db, "Database is required for functions with types", {
1048
- F: __dxlog_file3,
1049
- L: 68,
1050
- S: void 0,
1051
- A: [
1052
- "funcContext.db",
1053
- "'Database is required for functions with types'"
1054
- ]
1055
- });
1056
- await funcContext.db.graph.schemaRegistry.register(func.types);
337
+ const funcContext = _ts_add_disposable_resource(env, await new FunctionContext(context, opts).open(), true);
338
+ const types = [
339
+ ...opts.types ?? [],
340
+ ...func.types ?? []
341
+ ];
342
+ if (types.length > 0) {
343
+ invariant(funcContext.db, "Database is required for functions with types", { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 137, S: void 0, A: ["funcContext.db", "'Database is required for functions with types'"] });
344
+ await funcContext.db.graph.schemaRegistry.register(types);
1057
345
  }
1058
- const dataWithDecodedRefs = funcContext.db && !SchemaAST2.isAnyKeyword(func.inputSchema.ast) ? decodeRefsFromSchema(func.inputSchema.ast, data, funcContext.db) : data;
1059
- let result = await func.handler({
1060
- // TODO(dmaretskyi): Fix the types.
1061
- context,
1062
- data: dataWithDecodedRefs
1063
- });
1064
- if (Effect11.isEffect(result)) {
1065
- result = await runAndForwardErrors(result.pipe(Effect11.orDie, Effect11.provide(funcContext.createLayer())));
346
+ const dataWithDecodedRefs = funcContext.db && !SchemaAST.isAnyKeyword(func.input.ast) ? decodeRefsFromSchema(func.input.ast, data, funcContext.db) : data;
347
+ let result = await func.handler(dataWithDecodedRefs);
348
+ if (Effect4.isEffect(result)) {
349
+ result = await runAndForwardErrors(result.pipe(Effect4.orDie, Effect4.provide(funcContext.createLayer())));
1066
350
  }
1067
- if (func.outputSchema && !SchemaAST2.isAnyKeyword(func.outputSchema.ast)) {
1068
- Schema10.validateSync(func.outputSchema)(result);
351
+ if (func.output && !SchemaAST.isAnyKeyword(func.output.ast)) {
352
+ try {
353
+ Schema.validateSync(func.output, {
354
+ onExcessProperty: "error"
355
+ })(result);
356
+ } catch (error) {
357
+ throw new InvalidOperationOutputError({
358
+ message: `Operation output did not match schema (${func.meta.key}): ${error.message}`,
359
+ cause: error
360
+ });
361
+ }
1069
362
  }
1070
363
  return result;
1071
364
  } catch (e) {
@@ -1086,9 +379,11 @@ var FunctionContext = class extends Resource {
1086
379
  client;
1087
380
  db;
1088
381
  queues;
1089
- constructor(context) {
382
+ opts;
383
+ constructor(context, opts) {
1090
384
  super();
1091
385
  this.context = context;
386
+ this.opts = opts;
1092
387
  if (context.services.dataService && context.services.queryService) {
1093
388
  this.client = new EchoClient().connectToService({
1094
389
  dataService: context.services.dataService,
@@ -1100,12 +395,12 @@ var FunctionContext = class extends Resource {
1100
395
  async _open() {
1101
396
  await this.client?.open();
1102
397
  this.db = this.client && this.context.spaceId ? this.client.constructDatabase({
1103
- spaceId: this.context.spaceId ?? failedInvariant2(),
1104
- spaceKey: PublicKey.fromHex(this.context.spaceKey ?? failedInvariant2("spaceKey missing in context")),
398
+ spaceId: this.context.spaceId ?? failedInvariant(),
399
+ spaceKey: PublicKey.fromHex(this.context.spaceKey ?? failedInvariant("spaceKey missing in context")),
1105
400
  reactiveSchemaQuery: false,
1106
401
  preloadSchemaOnOpen: false
1107
402
  }) : void 0;
1108
- await this.db?.setSpaceRoot(this.context.spaceRootUrl ?? failedInvariant2("spaceRootUrl missing in context"));
403
+ await this.db?.setSpaceRoot(this.context.spaceRootUrl ?? failedInvariant("spaceRootUrl missing in context"));
1109
404
  await this.db?.open();
1110
405
  this.queues = this.client && this.context.spaceId ? this.client.constructQueueFactory(this.context.spaceId) : void 0;
1111
406
  }
@@ -1117,29 +412,111 @@ var FunctionContext = class extends Resource {
1117
412
  assertState(this._lifecycleState === LifecycleState.OPEN, "FunctionContext is not open");
1118
413
  const dbLayer = this.db ? Database2.layer(this.db) : Database2.notAvailable;
1119
414
  const queuesLayer = this.queues ? QueueService.layer(this.queues) : QueueService.notAvailable;
1120
- const credentials = dbLayer ? CredentialsService.layerFromDatabase({
415
+ const feedLayer = this.queues ? createFeedServiceLayer(this.queues) : Feed.notAvailable;
416
+ const credentials = dbLayer ? credentialsLayerFromDatabase({
1121
417
  caching: true
1122
- }).pipe(Layer7.provide(dbLayer)) : CredentialsService.configuredLayer([]);
1123
- const functionInvocationService = MockedFunctionInvocationService;
1124
- const tracing = TracingService.layerNoop;
1125
- const aiLayer = this.context.services.functionsAiService ? AiModelResolver.AiModelResolver.buildAiService.pipe(Layer7.provide(AnthropicResolver.make().pipe(Layer7.provide(AnthropicClient.layer({
1126
- // Note: It doesn't matter what is base url here, it will be proxied to ai gateway in edge.
1127
- apiUrl: "http://internal/provider/anthropic"
1128
- }).pipe(Layer7.provide(FunctionsAiHttpClient.layer(this.context.services.functionsAiService))))))) : AiService.notAvailable;
1129
- return Layer7.mergeAll(dbLayer, queuesLayer, credentials, functionInvocationService, aiLayer, tracing);
418
+ }).pipe(Layer4.provide(dbLayer)) : configuredCredentialsLayer([]);
419
+ const aiLayer = this.context.services.functionsAiService ? InternalAiServiceLayer(this.context.services.functionsAiService) : AiService.notAvailable;
420
+ const operationServiceLayer = this.context.services.functionsService ? makeOperationServiceLayer(this.context.services.functionsService) : unavailableOperationServiceLayer;
421
+ const operationRegistryLayer = this.context.services.functionsService ? makeOperationRegistryLayer(this.context.services.functionsService, this.context.spaceId) : emptyOperationRegistryLayer;
422
+ const traceWriterLayer = this.context.services.traceService ? makeTraceWriterLayer(this.context.services.traceService) : Trace.writerLayerNoop;
423
+ log2("Creating function context layer", {
424
+ traceService: !!this.context.services.traceService,
425
+ functionsService: !!this.context.services.functionsService,
426
+ functionsAiService: !!this.context.services.functionsAiService,
427
+ spaceId: this.context.spaceId,
428
+ spaceRootUrl: this.context.spaceRootUrl,
429
+ toolkits: this.opts.toolkits?.length ?? 0,
430
+ types: this.opts.types?.length ?? 0
431
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 220, S: this });
432
+ return Layer4.mergeAll(
433
+ dbLayer,
434
+ queuesLayer,
435
+ feedLayer,
436
+ credentials,
437
+ operationServiceLayer,
438
+ operationRegistryLayer,
439
+ aiLayer,
440
+ OpaqueToolkit.providerLayer(OpaqueToolkit.merge(...this.opts.toolkits ?? [])),
441
+ traceWriterLayer,
442
+ // `FunctionInvocationService` is deprecated; new code should yield `Operation.Service`.
443
+ // The cloudflare wrapper provides only the unavailable layer to satisfy the (still-present)
444
+ // type union — handlers that yield it will die at invocation time.
445
+ FunctionInvocationService.layerNotAvailable
446
+ );
447
+ }
448
+ };
449
+ var makeTraceWriterLayer = (traceService) => Layer4.succeed(Trace.TraceService, {
450
+ write: (eventType, payload) => {
451
+ log2("Writing trace event", {
452
+ eventType: eventType.key
453
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 240, S: void 0 });
454
+ traceService.write([
455
+ {
456
+ key: eventType.key,
457
+ isEphemeral: eventType.isEphemeral,
458
+ data: payload
459
+ }
460
+ ]);
1130
461
  }
462
+ });
463
+ var InternalAiServiceLayer = (functionsAiService) => AiModelResolver.AiModelResolver.buildAiService.pipe(Layer4.provide(AnthropicResolver.make().pipe(Layer4.provide(AnthropicClient.layer({
464
+ // Note: It doesn't matter what is base url here, it will be proxied to ai gateway in edge.
465
+ apiUrl: "http://internal/provider/anthropic"
466
+ }).pipe(Layer4.provide(FunctionsAiHttpClient.layer(functionsAiService)))))));
467
+ var makeOperationServiceLayer = (functionsService) => {
468
+ const invokeRemote = async (op, input, options) => {
469
+ invariant(op.meta.deployedId, `Operation '${op.meta.key}' has no deployedId; cannot invoke remotely.`, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 264, S: void 0, A: ["op.meta.deployedId", "`Operation '${op.meta.key}' has no deployedId; cannot invoke remotely.`"] });
470
+ const result = await functionsService.invoke(op.meta.deployedId, input, {
471
+ spaceId: options?.spaceId
472
+ });
473
+ if (result._kind === "success") {
474
+ return {
475
+ data: result.data
476
+ };
477
+ }
478
+ return {
479
+ error: ErrorCodec2.decode(result.error)
480
+ };
481
+ };
482
+ return Layer4.succeed(Operation.Service, {
483
+ invoke: (op, input, options) => Effect4.tryPromise(() => invokeRemote(op, input, options)).pipe(Effect4.orDie, Effect4.flatMap((outcome) => outcome.error ? Effect4.die(outcome.error) : Effect4.succeed(outcome.data))),
484
+ schedule: (op, input) => Effect4.sync(() => {
485
+ invariant(op.meta.deployedId, `Operation '${op.meta.key}' has no deployedId; cannot schedule remotely.`, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 280, S: void 0, A: ["op.meta.deployedId", "`Operation '${op.meta.key}' has no deployedId; cannot schedule remotely.`"] });
486
+ void functionsService.invoke(op.meta.deployedId, input).catch(() => {
487
+ });
488
+ }),
489
+ invokePromise: (op, input, options) => invokeRemote(op, input, options).catch((error) => ({
490
+ error: error instanceof Error ? error : new Error(String(error))
491
+ }))
492
+ });
1131
493
  };
1132
- var MockedFunctionInvocationService = Layer7.succeed(FunctionInvocationService, {
1133
- invokeFunction: () => Effect11.die("Calling functions from functions is not implemented yet."),
1134
- resolveFunction: () => Effect11.die("Not implemented.")
494
+ var unavailableOperationServiceLayer = Layer4.succeed(Operation.Service, {
495
+ invoke: () => Effect4.die("Operation.Service is not available: missing functionsService in EDGE context."),
496
+ schedule: () => Effect4.die("Operation.Service is not available: missing functionsService in EDGE context."),
497
+ invokePromise: async () => ({
498
+ error: new Error("Operation.Service is not available: missing functionsService in EDGE context.")
499
+ })
500
+ });
501
+ var makeOperationRegistryLayer = (functionsService, spaceId) => Layer4.succeed(OperationRegistry.Service, {
502
+ resolve: (key) => Effect4.gen(function* () {
503
+ const records = yield* Effect4.tryPromise(() => functionsService.query({
504
+ spaceId
505
+ })).pipe(Effect4.orDie);
506
+ const match = records.find((record) => record.key === key);
507
+ return match ? Option.some(Operation.deserialize(match)) : Option.none();
508
+ })
509
+ });
510
+ var emptyOperationRegistryLayer = Layer4.succeed(OperationRegistry.Service, {
511
+ resolve: () => Effect4.succeed(Option.none())
1135
512
  });
1136
513
  var decodeRefsFromSchema = (ast, value2, db) => {
1137
514
  if (value2 == null) {
1138
515
  return value2;
1139
516
  }
1140
- const encoded = SchemaAST2.encodedBoundAST(ast);
1141
- if (Ref2.isRefType(encoded)) {
1142
- if (Ref2.isRef(value2)) {
517
+ const encoded = SchemaAST.encodedBoundAST(ast);
518
+ if (Ref.isRefType(encoded)) {
519
+ if (Ref.isRef(value2)) {
1143
520
  return value2;
1144
521
  }
1145
522
  if (typeof value2 === "object" && value2 !== null && typeof value2["/"] === "string") {
@@ -1160,7 +537,7 @@ var decodeRefsFromSchema = (ast, value2, db) => {
1160
537
  const result = {
1161
538
  ...value2
1162
539
  };
1163
- for (const prop of SchemaAST2.getPropertySignatures(encoded)) {
540
+ for (const prop of SchemaAST.getPropertySignatures(encoded)) {
1164
541
  const key = prop.name.toString();
1165
542
  if (key in result) {
1166
543
  result[key] = decodeRefsFromSchema(prop.type, result[key], db);
@@ -1179,7 +556,7 @@ var decodeRefsFromSchema = (ast, value2, db) => {
1179
556
  return value2;
1180
557
  }
1181
558
  case "Union": {
1182
- const nonUndefined = encoded.types.filter((t) => !SchemaAST2.isUndefinedKeyword(t));
559
+ const nonUndefined = encoded.types.filter((t) => !SchemaAST.isUndefinedKeyword(t));
1183
560
  if (nonUndefined.length === 1) {
1184
561
  return decodeRefsFromSchema(nonUndefined[0], value2, db);
1185
562
  }
@@ -1197,37 +574,19 @@ var decodeRefsFromSchema = (ast, value2, db) => {
1197
574
  }
1198
575
  };
1199
576
  export {
1200
- ComputeEvent,
1201
- ComputeEventLogger,
1202
- ComputeEventPayload,
1203
577
  ConfiguredCredentialsService,
1204
578
  ContextQueueService,
1205
- CredentialsService,
1206
- Example,
1207
579
  FUNCTIONS_META_KEY,
1208
580
  FUNCTIONS_PRESET_META_KEY,
1209
- Function_exports as Function,
1210
- FunctionDefinition,
1211
- FunctionError,
1212
581
  FunctionInvocationService,
1213
- FunctionNotFoundError,
1214
582
  MESSAGE_PROPERTY_TOOL_CALL_ID,
1215
583
  QueueService,
1216
- Script_exports as Script,
1217
- ServiceNotAvailableError,
1218
- TracingService,
1219
- Trigger_exports as Trigger,
1220
- TriggerEvent_exports as TriggerEvent,
1221
- TriggerStateNotFoundError,
1222
- createDefectLogger,
1223
- createEventLogger,
1224
- defineFunction,
1225
- deserializeFunction,
584
+ configuredCredentialsLayer,
585
+ credentialsLayerConfig,
586
+ credentialsLayerFromDatabase,
587
+ feedServiceFromQueueServiceLayer,
1226
588
  getUserFunctionIdInMetadata,
1227
- logCustomEvent,
1228
- serializeFunction,
1229
589
  setUserFunctionIdInMetadata,
1230
- toOperation,
1231
590
  withAuthorization,
1232
591
  wrapFunctionHandler
1233
592
  };