@dxos/functions 0.8.4-main.ef1bc66f44 → 0.8.4-main.effb148878

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