@dxos/assistant 0.8.4-main.9be5663bfe → 0.8.4-main.abd8ff62ef

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 (97) hide show
  1. package/dist/lib/neutral/extraction/index.mjs +4 -21
  2. package/dist/lib/neutral/extraction/index.mjs.map +3 -3
  3. package/dist/lib/neutral/index.mjs +1259 -79
  4. package/dist/lib/neutral/index.mjs.map +4 -4
  5. package/dist/lib/neutral/meta.json +1 -1
  6. package/dist/types/src/conversation/context.d.ts +9 -12
  7. package/dist/types/src/conversation/context.d.ts.map +1 -1
  8. package/dist/types/src/conversation/index.d.ts +1 -1
  9. package/dist/types/src/conversation/index.d.ts.map +1 -1
  10. package/dist/types/src/conversation/session.d.ts +78 -0
  11. package/dist/types/src/conversation/session.d.ts.map +1 -0
  12. package/dist/types/src/diff.d.ts.map +1 -1
  13. package/dist/types/src/errors.d.ts +12 -12
  14. package/dist/types/src/errors.d.ts.map +1 -1
  15. package/dist/types/src/execution-graph.d.ts.map +1 -1
  16. package/dist/types/src/extraction/extraction-ner-function/named-entity-recognition.d.ts.map +1 -1
  17. package/dist/types/src/extraction/extraction.d.ts +461 -455
  18. package/dist/types/src/extraction/extraction.d.ts.map +1 -1
  19. package/dist/types/src/extraction/quotes.d.ts.map +1 -1
  20. package/dist/types/src/functions/services.d.ts +7 -29
  21. package/dist/types/src/functions/services.d.ts.map +1 -1
  22. package/dist/types/src/index.d.ts +0 -1
  23. package/dist/types/src/index.d.ts.map +1 -1
  24. package/dist/types/src/session/artifact-diff.d.ts.map +1 -1
  25. package/dist/types/src/session/error-handling.d.ts.map +1 -1
  26. package/dist/types/src/session/format.d.ts +6 -3
  27. package/dist/types/src/session/format.d.ts.map +1 -1
  28. package/dist/types/src/session/index.d.ts +1 -1
  29. package/dist/types/src/session/{session.d.ts → request.d.ts} +25 -33
  30. package/dist/types/src/session/request.d.ts.map +1 -0
  31. package/dist/types/src/session/toolkit.d.ts +5 -7
  32. package/dist/types/src/session/toolkit.d.ts.map +1 -1
  33. package/dist/types/src/templates/system.d.ts +1 -1
  34. package/dist/types/src/templates/system.d.ts.map +1 -1
  35. package/dist/types/src/tracing.d.ts +64 -95
  36. package/dist/types/src/tracing.d.ts.map +1 -1
  37. package/dist/types/src/types/artifact.d.ts.map +1 -1
  38. package/dist/types/tsconfig.tsbuildinfo +1 -1
  39. package/package.json +21 -38
  40. package/src/conversation/context.ts +1 -1
  41. package/src/conversation/index.ts +1 -1
  42. package/src/conversation/session.ts +334 -0
  43. package/src/execution-graph.ts +15 -5
  44. package/src/extraction/extraction.ts +1 -1
  45. package/src/functions/services.ts +12 -127
  46. package/src/functions.conversations.json +1 -1
  47. package/src/index.ts +0 -1
  48. package/src/session/format.ts +14 -9
  49. package/src/session/index.ts +1 -1
  50. package/src/session/request.conversations.json +1 -0
  51. package/src/session/{session.ts → request.ts} +44 -51
  52. package/src/session/toolkit.ts +18 -15
  53. package/src/templates/instructions/system.tpl +11 -0
  54. package/src/templates/system.ts +1 -1
  55. package/src/tracing.ts +13 -69
  56. package/dist/lib/neutral/chunk-J5LGTIGS.mjs +0 -10
  57. package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +0 -7
  58. package/dist/lib/neutral/chunk-UAWIXKF6.mjs +0 -1875
  59. package/dist/lib/neutral/chunk-UAWIXKF6.mjs.map +0 -7
  60. package/dist/lib/neutral/testing/index.mjs +0 -114
  61. package/dist/lib/neutral/testing/index.mjs.map +0 -7
  62. package/dist/types/src/conversation/conversation.d.ts +0 -68
  63. package/dist/types/src/conversation/conversation.d.ts.map +0 -1
  64. package/dist/types/src/conversation/conversation.test.d.ts +0 -2
  65. package/dist/types/src/conversation/conversation.test.d.ts.map +0 -1
  66. package/dist/types/src/functions.test.d.ts +0 -2
  67. package/dist/types/src/functions.test.d.ts.map +0 -1
  68. package/dist/types/src/service/AgentService.d.ts +0 -61
  69. package/dist/types/src/service/AgentService.d.ts.map +0 -1
  70. package/dist/types/src/service/AgentService.test.d.ts +0 -2
  71. package/dist/types/src/service/AgentService.test.d.ts.map +0 -1
  72. package/dist/types/src/service/agent-process.d.ts +0 -17
  73. package/dist/types/src/service/agent-process.d.ts.map +0 -1
  74. package/dist/types/src/service/index.d.ts +0 -3
  75. package/dist/types/src/service/index.d.ts.map +0 -1
  76. package/dist/types/src/session/format.test.d.ts +0 -2
  77. package/dist/types/src/session/format.test.d.ts.map +0 -1
  78. package/dist/types/src/session/session.d.ts.map +0 -1
  79. package/dist/types/src/session/session.test.d.ts +0 -2
  80. package/dist/types/src/session/session.test.d.ts.map +0 -1
  81. package/dist/types/src/testing/index.d.ts +0 -2
  82. package/dist/types/src/testing/index.d.ts.map +0 -1
  83. package/dist/types/src/testing/layer.d.ts +0 -35
  84. package/dist/types/src/testing/layer.d.ts.map +0 -1
  85. package/src/conversation/conversation.test.ts +0 -58
  86. package/src/conversation/conversation.ts +0 -275
  87. package/src/functions.test.ts +0 -82
  88. package/src/service/AgentService.conversations.json +0 -1
  89. package/src/service/AgentService.test.ts +0 -169
  90. package/src/service/AgentService.ts +0 -165
  91. package/src/service/agent-process.ts +0 -359
  92. package/src/service/index.ts +0 -6
  93. package/src/session/format.test.ts +0 -132
  94. package/src/session/session.conversations.json +0 -1
  95. package/src/session/session.test.ts +0 -190
  96. package/src/testing/index.ts +0 -5
  97. package/src/testing/layer.ts +0 -259
@@ -1,359 +0,0 @@
1
- //
2
- // Copyright 2026 DXOS.org
3
- //
4
-
5
- import * as Tool from '@effect/ai/Tool';
6
- import * as Toolkit from '@effect/ai/Toolkit';
7
- import * as Cause from 'effect/Cause';
8
- import * as Duration from 'effect/Duration';
9
- import * as Effect from 'effect/Effect';
10
- import * as Exit from 'effect/Exit';
11
- import * as Layer from 'effect/Layer';
12
- import * as Match from 'effect/Match';
13
- import * as Option from 'effect/Option';
14
- import * as Schema from 'effect/Schema';
15
-
16
- import { AiService, GenericToolkit, type ModelName } from '@dxos/ai';
17
- import { Database, DXN, Feed, Obj } from '@dxos/echo';
18
- import { acquireReleaseResource } from '@dxos/effect';
19
- import { TracingService } from '@dxos/functions';
20
- import { Process, ProcessManager, StorageService } from '@dxos/functions-runtime';
21
- import { log } from '@dxos/log';
22
- import { Operation, OperationRegistry } from '@dxos/operation';
23
- import { trim } from '@dxos/util';
24
-
25
- import { AiConversation } from '../conversation';
26
- import {
27
- functionInvocationServiceFromOperations,
28
- getOperationFromTool,
29
- makeToolExecutionService,
30
- makeToolResolverFromOperations,
31
- } from '../functions';
32
-
33
- interface AgentProcessOptions {
34
- systemPrompt?: string;
35
- model?: ModelName;
36
- }
37
-
38
- export const AGENT_PROCESS_KEY = 'org.dxos.testing.process.agent';
39
-
40
- /**
41
- * Hosts a persistent, suspendible AiAgent that can process a number of prompts.
42
- * The process target is a queue DXN string.
43
- */
44
- export const AgentProcess = (options: AgentProcessOptions) =>
45
- Process.make(
46
- {
47
- key: AGENT_PROCESS_KEY,
48
- input: Schema.String,
49
- output: Schema.Void,
50
- services: [
51
- Database.Service,
52
- GenericToolkit.GenericToolkitProvider,
53
- Operation.Service,
54
- OperationRegistry.Service,
55
- StorageService.StorageService,
56
- Feed.FeedService,
57
- ProcessManager.ProcessOperationInvoker.Service,
58
- AiService.AiService,
59
- // @deprecated Required by AiSessionRunRequirements for backward compat with tool handlers.
60
- TracingService,
61
- ],
62
- },
63
- (ctx) =>
64
- Effect.gen(function* () {
65
- const feedDxn = ctx.params.target;
66
- if (feedDxn == null) {
67
- return yield* Effect.die(new Error('Agent executable requires spawn options.target set to a queue DXN.'));
68
- }
69
- const feed = yield* Database.resolve(DXN.parse(feedDxn), Feed.Feed).pipe(Effect.orDie);
70
- const runtime = yield* Effect.runtime<Feed.FeedService>();
71
- const conversation = yield* acquireReleaseResource(() => new AiConversation({ feed, runtime }));
72
- let inputQueue: AgentEvent[] = [...(yield* AgentEventsKey.get)];
73
- const storageService = yield* StorageService.StorageService;
74
- const toolCallManager = new ToolCallManager(storageService);
75
- yield* toolCallManager.load();
76
-
77
- return {
78
- onInput: Effect.fnUntraced(function* (prompt: string) {
79
- log('agent onInput received', { promptLength: prompt.length, backlog: inputQueue.length });
80
- inputQueue.push({ _tag: 'prompt', content: prompt });
81
- log('agent onInput persisting queue', { depth: inputQueue.length });
82
- yield* AgentEventsKey.set(inputQueue);
83
- log('agent onInput persisted', { depth: inputQueue.length });
84
- ctx.setAlarm();
85
- log('agent onInput alarm scheduled');
86
- }),
87
- onAlarm: Effect.fnUntraced(
88
- function* () {
89
- log('agent onAlarm fired', { pending: inputQueue.length });
90
- const item = inputQueue.shift();
91
- if (!item) {
92
- log('agent onAlarm empty queue', {});
93
- return;
94
- }
95
-
96
- if (item._tag === 'tool_result' && toolCallManager.isReported(item.pid)) {
97
- log.info('skip tool result that was reported synchronously', { pid: item.pid });
98
- // Ignore tool results that were reported synchronously.
99
- return;
100
- }
101
-
102
- log('agent onAlarm handling', { tag: item._tag });
103
-
104
- const prompt = Match.value(item).pipe(
105
- Match.tag('prompt', (item) => item.content),
106
- Match.tag('tool_result', (item) =>
107
- item.isError
108
- ? toolErrorResponse(item.pid, item.result as string)
109
- : toolResultResponse(item.pid, item.result),
110
- ),
111
- Match.exhaustive,
112
- );
113
-
114
- log('begin request', { prompt });
115
- yield* conversation.createRequest({
116
- prompt,
117
- // TODO(dmaretskyi): Polling currently broken, agent relies on completion notifications being delivered.
118
- // toolkit: AsynchronousExectionToolkit,
119
- system: options.systemPrompt,
120
- });
121
- log('end request');
122
- yield* AgentEventsKey.set(inputQueue);
123
- if (inputQueue.length > 0) {
124
- ctx.setAlarm();
125
- }
126
- },
127
- Effect.orDie,
128
- Effect.provide(
129
- Layer.mergeAll(
130
- makeToolResolverFromOperations(),
131
- ToolExecutionService({
132
- toolCallManager,
133
- feed,
134
- }),
135
- functionInvocationServiceFromOperations,
136
- AsynchronousExectionToolkitLayer,
137
- AiService.model(options.model ?? '@anthropic/claude-opus-4-6'),
138
- ).pipe(Layer.orDie),
139
- ),
140
- ),
141
- onChildEvent: Effect.fnUntraced(function* (event) {
142
- log.info('childEvent', { event });
143
- if (event._tag === 'exited') {
144
- if (!toolCallManager.isToolCall(event.pid)) {
145
- log.verbose('childEvent ignored non-tool call', { pid: event.pid });
146
- return;
147
- }
148
-
149
- const operationInvoker = yield* ProcessManager.ProcessOperationInvoker.Service;
150
- const fiber = yield* operationInvoker.attachFiber(event.pid).pipe(Effect.orDie);
151
- const result = yield* fiber.await.pipe(Effect.orDie).pipe(
152
- Effect.map(
153
- Exit.match({
154
- onSuccess: (value): AgentEvent => ({
155
- _tag: 'tool_result',
156
- pid: event.pid,
157
- result: value,
158
- isError: false,
159
- }),
160
- onFailure: (cause): AgentEvent => ({
161
- _tag: 'tool_result',
162
- pid: event.pid,
163
- result: Cause.pretty(cause),
164
- isError: true,
165
- }),
166
- }),
167
- ),
168
- );
169
- inputQueue.push(result);
170
- log('agent onChildEvent persisted tool result', { depth: inputQueue.length, childPid: event.pid });
171
- yield* AgentEventsKey.set(inputQueue);
172
- ctx.setAlarm();
173
- log('agent onChildEvent alarm scheduled', { depth: inputQueue.length });
174
- }
175
- }),
176
- };
177
- }),
178
- );
179
-
180
- interface ToolExecutionServiceOptions {
181
- /**
182
- * Threshold after which the tool execution is placed in the background.
183
- */
184
- // TODO(dmaretskyi): Tool annotation to never run in background.
185
- backgroundThreshold?: Duration.Duration;
186
-
187
- toolCallManager: ToolCallManager;
188
- feed: Feed.Feed;
189
- }
190
-
191
- const AgentEvent = Schema.Union(
192
- Schema.TaggedStruct('prompt', {
193
- content: Schema.String,
194
- }),
195
- Schema.TaggedStruct('tool_result', {
196
- pid: Process.ID,
197
- result: Schema.Unknown,
198
- isError: Schema.Boolean,
199
- }),
200
- );
201
- type AgentEvent = Schema.Schema.Type<typeof AgentEvent>;
202
-
203
- const AgentEventsKey = StorageService.key(
204
- Schema.parseJson(Schema.Array(AgentEvent).pipe(Schema.mutable)),
205
- 'inputQueue',
206
- ).pipe(StorageService.withDefault(() => []));
207
-
208
- const ToolCallState = Schema.Struct({
209
- activeCalls: Schema.Array(
210
- Schema.Struct({
211
- pid: Process.ID,
212
- // Whether the result was reported to the agent.
213
- reported: Schema.Boolean,
214
- }).pipe(Schema.mutable),
215
- ).pipe(Schema.mutable),
216
- });
217
- interface ToolCallState extends Schema.Schema.Type<typeof ToolCallState> {}
218
-
219
- // Id's of processes who's results were already submitted to the agent.
220
- const ToolCallStateKey = StorageService.key(Schema.parseJson(ToolCallState.pipe(Schema.mutable)), 'toolCallState').pipe(
221
- StorageService.withDefault(() => ({ activeCalls: [] })),
222
- );
223
-
224
- class ToolCallManager {
225
- #storageService: StorageService.Service;
226
- #state: ToolCallState = { activeCalls: [] };
227
-
228
- constructor(storageService: StorageService.Service) {
229
- this.#storageService = storageService;
230
- }
231
-
232
- load() {
233
- return Effect.gen(this, function* () {
234
- this.#state = yield* ToolCallStateKey.get;
235
- }).pipe(Effect.provideService(StorageService.StorageService, this.#storageService));
236
- }
237
-
238
- beginCall(pid: Process.ID) {
239
- return Effect.gen(this, function* () {
240
- this.#state.activeCalls.push({ pid, reported: false });
241
- yield* ToolCallStateKey.set(this.#state);
242
- }).pipe(Effect.provideService(StorageService.StorageService, this.#storageService));
243
- }
244
-
245
- markAsReported(pid: Process.ID) {
246
- return Effect.gen(this, function* () {
247
- const call = this.#state.activeCalls.find((call) => call.pid === pid);
248
- if (!call) {
249
- return;
250
- }
251
- call.reported = true;
252
- yield* ToolCallStateKey.set(this.#state);
253
- }).pipe(Effect.provideService(StorageService.StorageService, this.#storageService));
254
- }
255
-
256
- isToolCall(pid: Process.ID): boolean {
257
- return this.#state.activeCalls.some((call) => call.pid === pid);
258
- }
259
-
260
- isReported(pid: Process.ID) {
261
- return this.#state.activeCalls.some((call) => call.pid === pid && call.reported);
262
- }
263
- }
264
-
265
- const ToolExecutionService = ({
266
- backgroundThreshold = Duration.seconds(1),
267
- toolCallManager,
268
- feed,
269
- }: ToolExecutionServiceOptions) =>
270
- Layer.unwrapEffect(
271
- Effect.gen(function* () {
272
- const operationInvoker = yield* ProcessManager.ProcessOperationInvoker.Service;
273
- return makeToolExecutionService({
274
- invoke: (tool, input) =>
275
- Effect.gen(function* () {
276
- const operationDef = getOperationFromTool(tool).pipe(Option.getOrThrow);
277
- log('invoking operation', { operationDef, input });
278
- const fiber = yield* operationInvoker.invokeFiber(operationDef, input, {
279
- environment: {
280
- conversation: Obj.getDXN(feed).toString(),
281
- },
282
- });
283
- toolCallManager.beginCall(fiber.pid);
284
- log('invoked operation', { operationDef, input, fiber });
285
-
286
- const result = yield* fiber.await.pipe(
287
- Effect.tap(() => toolCallManager.markAsReported(fiber.pid)),
288
- Effect.timeout(backgroundThreshold),
289
- Effect.catchTag('TimeoutException', () => Effect.succeed(toolIsRunningInBackgroundResponse(fiber.pid))),
290
- );
291
- log('result', { result });
292
- return result;
293
- }),
294
- });
295
- }),
296
- );
297
-
298
- class AsynchronousExectionToolkit extends Toolkit.make(
299
- Tool.make('poll-tools', {
300
- description: trim`
301
- Poll tool calls running in the background.
302
- Set wait to true to wait for the tool call to complete before returning.
303
- Only set wait to true if you dont have other tasks to perform in parallel.
304
- Set an appropriate timeout to avoid waiting forever.
305
- You will also be notified about the job completion separatelly, so you do not always need to inspect the job if you dont need the result right now.
306
- `,
307
- parameters: {
308
- ids: Schema.Array(Schema.String).annotations({
309
- description: 'The IDs of the jobs to inspect.',
310
- }),
311
- wait: Schema.optional(Schema.Boolean).annotations({
312
- description: 'Whether to wait for the job to complete before returning.',
313
- default: false,
314
- }),
315
- timeout: Schema.optional(Schema.Number).annotations({
316
- description:
317
- 'Maximum time to wait for the job to complete. If the job does not complete within the timeout, the current state is returned.',
318
- default: 10_000,
319
- }),
320
- },
321
- }),
322
- ) {}
323
-
324
- // TODO(dmaretskyi): Currently broken: polling a completed process returns interruped error.
325
- const AsynchronousExectionToolkitLayer = AsynchronousExectionToolkit.toLayer(
326
- Effect.gen(function* () {
327
- const invoker = yield* ProcessManager.ProcessOperationInvoker.Service;
328
- return {
329
- 'poll-tools': ({ ids, wait, timeout = 10_000 }) =>
330
- Effect.gen(function* () {
331
- return yield* Effect.forEach(ids, (pid) =>
332
- invoker.attachFiber<unknown>(Process.ID.make(pid)).pipe(
333
- Effect.flatMap((_) => _.await),
334
- Effect.timeout(Duration.millis(timeout)),
335
- Effect.flatMap(
336
- Exit.match({
337
- onSuccess: (value) => Effect.succeed(toolResultResponse(pid, value)),
338
- onFailure: (cause) => Effect.succeed(toolErrorResponse(pid, Cause.pretty(cause))),
339
- }),
340
- ),
341
- Effect.catchTag('ProcessNotFoundError', () => Effect.succeed(`Process not found: ${pid}`)),
342
- Effect.catchTag('TimeoutException', () => Effect.succeed(`Process still running: ${pid}`)),
343
- ),
344
- );
345
- }),
346
- };
347
- }),
348
- );
349
-
350
- /**
351
- * Instructs model that the tool is running in the background.
352
- */
353
- const toolIsRunningInBackgroundResponse = (pid: Process.ID) =>
354
- `Tool is running in the background id=${pid}; wait for the completion notification to get the result.`;
355
- // `Tool is running in the background id=${pid}; use ${AsynchronousExectionToolkit.tools['poll-tools'].name} to get the result.`;
356
-
357
- const toolResultResponse = (pid: string, value: unknown) => `<result pid=${pid}>${JSON.stringify(value)}</result>`;
358
-
359
- const toolErrorResponse = (pid: string, cause: string) => `<error pid=${pid}>${cause}</error>`;
@@ -1,6 +0,0 @@
1
- //
2
- // Copyright 2026 DXOS.org
3
- //
4
-
5
- export * as AgentService from './AgentService';
6
- export { AGENT_PROCESS_KEY } from './agent-process';
@@ -1,132 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import { describe, expect, it } from '@effect/vitest';
6
- import * as Effect from 'effect/Effect';
7
- import * as Schema from 'effect/Schema';
8
-
9
- import { Blueprint, Template } from '@dxos/blueprints';
10
- import { Database, Obj, Query } from '@dxos/echo';
11
- import { TestHelpers } from '@dxos/effect/testing';
12
- import { Operation, OperationHandlerSet } from '@dxos/operation';
13
- import { Text } from '@dxos/schema';
14
- import { Organization } from '@dxos/types';
15
- import { trim } from '@dxos/util';
16
-
17
- import { createSystemPrompt } from '../templates/system';
18
- import { AssistantTestLayer } from '../testing';
19
- import { formatSystemPrompt } from './format';
20
-
21
- const OrganizationList = Operation.make({
22
- meta: {
23
- key: 'org.dxos.function.organization-list',
24
- name: 'Organization List',
25
- description: 'List organizations',
26
- },
27
- input: Schema.Struct({}),
28
- output: Schema.Array(Schema.String),
29
- services: [Database.Service],
30
- });
31
-
32
- const Handlers = OperationHandlerSet.make(
33
- Operation.withHandler(
34
- OrganizationList,
35
- Effect.fnUntraced(function* () {
36
- const organizations = yield* Database.runQuery(Query.type(Organization.Organization));
37
- return organizations.map((organization) => organization.name ?? '<no org>');
38
- }),
39
- ),
40
- );
41
-
42
- const TestLayer = AssistantTestLayer({
43
- types: [Text.Text, Organization.Organization, Blueprint.Blueprint],
44
- operationHandlers: Handlers,
45
- });
46
-
47
- describe('format', () => {
48
- it.effect(
49
- 'should format',
50
- Effect.fnUntraced(
51
- function* (_) {
52
- const { db } = yield* Database.Service;
53
- const object = db.add(
54
- Obj.make(Organization.Organization, {
55
- name: 'Test',
56
- website: 'https://www.test.com',
57
- }),
58
- );
59
-
60
- const blueprint = db.add(
61
- Blueprint.make({
62
- key: 'example.com/blueprint/test',
63
- name: 'Test',
64
- instructions: Template.make({
65
- source: trim`
66
- Test
67
- This is the test blueprint.
68
- `,
69
- }),
70
- }),
71
- );
72
-
73
- const output = yield* formatSystemPrompt({
74
- system: createSystemPrompt({}),
75
- blueprints: [blueprint],
76
- objects: [object],
77
- });
78
-
79
- console.log(output);
80
- },
81
- Effect.provide(TestLayer),
82
- TestHelpers.provideTestContext,
83
- ),
84
- );
85
-
86
- it.effect(
87
- 'should format with function input',
88
- Effect.fnUntraced(
89
- function* (_) {
90
- const { db } = yield* Database.Service;
91
- const object = db.add(
92
- Obj.make(Organization.Organization, {
93
- name: 'Test Org',
94
- website: 'https://www.test.com',
95
- }),
96
- );
97
-
98
- const blueprint = db.add(
99
- Blueprint.make({
100
- key: 'example.com/blueprint/test',
101
- name: 'Test',
102
- instructions: Template.make({
103
- source: trim`
104
- Organization List:
105
- {{#each organizations}}
106
- - {{this}}
107
- {{/each}}
108
- `,
109
- inputs: [
110
- {
111
- name: 'organizations',
112
- kind: 'function',
113
- function: OrganizationList.meta.key,
114
- },
115
- ],
116
- }),
117
- }),
118
- );
119
-
120
- const output = yield* formatSystemPrompt({
121
- system: createSystemPrompt({}),
122
- blueprints: [blueprint],
123
- objects: [object],
124
- });
125
-
126
- expect(output).to.include('Test Org');
127
- },
128
- Effect.provide(TestLayer),
129
- TestHelpers.provideTestContext,
130
- ),
131
- );
132
- });