@dxos/assistant 0.8.3 → 0.8.4-main.28f8d3d

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 (152) hide show
  1. package/dist/lib/browser/chunk-6WRGDEMH.mjs +89 -0
  2. package/dist/lib/browser/chunk-6WRGDEMH.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-NZGGCEF3.mjs +341 -0
  4. package/dist/lib/browser/chunk-NZGGCEF3.mjs.map +7 -0
  5. package/dist/lib/browser/extraction/index.mjs +269 -0
  6. package/dist/lib/browser/extraction/index.mjs.map +7 -0
  7. package/dist/lib/browser/index.mjs +306 -2110
  8. package/dist/lib/browser/index.mjs.map +4 -4
  9. package/dist/lib/browser/meta.json +1 -1
  10. package/dist/lib/browser/named-entity-recognition-O46UTCLR.mjs +13 -0
  11. package/dist/lib/browser/named-entity-recognition-O46UTCLR.mjs.map +7 -0
  12. package/dist/lib/node-esm/chunk-3UU5V4FS.mjs +91 -0
  13. package/dist/lib/node-esm/chunk-3UU5V4FS.mjs.map +7 -0
  14. package/dist/lib/node-esm/chunk-XOOPGSGW.mjs +343 -0
  15. package/dist/lib/node-esm/chunk-XOOPGSGW.mjs.map +7 -0
  16. package/dist/lib/node-esm/extraction/index.mjs +270 -0
  17. package/dist/lib/node-esm/extraction/index.mjs.map +7 -0
  18. package/dist/lib/node-esm/index.mjs +305 -2110
  19. package/dist/lib/node-esm/index.mjs.map +4 -4
  20. package/dist/lib/node-esm/meta.json +1 -1
  21. package/dist/lib/node-esm/named-entity-recognition-W4VMRCH6.mjs +14 -0
  22. package/dist/lib/node-esm/named-entity-recognition-W4VMRCH6.mjs.map +7 -0
  23. package/dist/types/src/conversation/context.d.ts +90 -0
  24. package/dist/types/src/conversation/context.d.ts.map +1 -0
  25. package/dist/types/src/conversation/conversation.d.ts +50 -0
  26. package/dist/types/src/conversation/conversation.d.ts.map +1 -0
  27. package/dist/types/src/conversation/index.d.ts +3 -0
  28. package/dist/types/src/conversation/index.d.ts.map +1 -0
  29. package/dist/types/src/errors.d.ts +39 -0
  30. package/dist/types/src/errors.d.ts.map +1 -0
  31. package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.d.ts.map +1 -1
  32. package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts +151 -53
  33. package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts.map +1 -1
  34. package/dist/types/src/extraction/extraction-ner-function/named-entity-recognition.d.ts +1 -1
  35. package/dist/types/src/extraction/extraction-ner-function/named-entity-recognition.d.ts.map +1 -1
  36. package/dist/types/src/extraction/extraction.d.ts +106 -44
  37. package/dist/types/src/extraction/extraction.d.ts.map +1 -1
  38. package/dist/types/src/functions/index.d.ts +2 -0
  39. package/dist/types/src/functions/index.d.ts.map +1 -0
  40. package/dist/types/src/functions/services.d.ts +7 -0
  41. package/dist/types/src/functions/services.d.ts.map +1 -0
  42. package/dist/types/src/index.d.ts +4 -3
  43. package/dist/types/src/index.d.ts.map +1 -1
  44. package/dist/types/src/session/artifact-diff.d.ts +27 -0
  45. package/dist/types/src/session/artifact-diff.d.ts.map +1 -0
  46. package/dist/types/src/session/format.d.ts +168 -0
  47. package/dist/types/src/session/format.d.ts.map +1 -0
  48. package/dist/types/src/session/format.test.d.ts +2 -0
  49. package/dist/types/src/session/format.test.d.ts.map +1 -0
  50. package/dist/types/src/session/index.d.ts +1 -0
  51. package/dist/types/src/session/index.d.ts.map +1 -1
  52. package/dist/types/src/session/session.d.ts +125 -219
  53. package/dist/types/src/session/session.d.ts.map +1 -1
  54. package/dist/types/src/session/version-pin.d.ts +4 -4
  55. package/dist/types/src/session/version-pin.d.ts.map +1 -1
  56. package/dist/types/src/templates/index.d.ts +2 -0
  57. package/dist/types/src/templates/index.d.ts.map +1 -0
  58. package/dist/types/src/templates/system.d.ts +22 -0
  59. package/dist/types/src/templates/system.d.ts.map +1 -0
  60. package/dist/types/src/types.d.ts +13 -0
  61. package/dist/types/src/types.d.ts.map +1 -1
  62. package/dist/types/tsconfig.tsbuildinfo +1 -1
  63. package/package.json +46 -31
  64. package/src/conversation/context.ts +133 -0
  65. package/src/conversation/conversation.ts +125 -0
  66. package/src/conversation/index.ts +6 -0
  67. package/src/errors.ts +10 -0
  68. package/src/extraction/extraction-llm-function/extraction-llm-function.test.ts +7 -18
  69. package/src/extraction/extraction-llm-function/extraction-llm-function.ts +23 -17
  70. package/src/extraction/extraction-ner-function/extraction-ner-function.test.ts +4 -3
  71. package/src/extraction/extraction-ner-function/extraction-ner-function.ts +7 -4
  72. package/src/extraction/extraction-ner-function/named-entity-recognition.test.ts +2 -2
  73. package/src/extraction/extraction-ner-function/named-entity-recognition.ts +1 -1
  74. package/src/extraction/quotes.test.ts +1 -1
  75. package/src/extraction/quotes.ts +1 -1
  76. package/src/functions/index.ts +5 -0
  77. package/src/functions/services.ts +114 -0
  78. package/src/index.ts +4 -3
  79. package/src/session/__snapshots__/session.test.ts.snap +32 -0
  80. package/src/session/artifact-diff.ts +37 -0
  81. package/src/session/format.test.ts +60 -0
  82. package/src/session/format.ts +139 -0
  83. package/src/session/index.ts +1 -0
  84. package/src/session/session.test.ts +95 -19
  85. package/src/session/session.ts +224 -494
  86. package/src/session/version-pin.test.ts +2 -21
  87. package/src/session/version-pin.ts +9 -9
  88. package/src/summarization/summarization.test.ts +82 -106
  89. package/src/templates/format.tpl +55 -0
  90. package/src/templates/index.ts +5 -0
  91. package/src/templates/system.tpl +47 -0
  92. package/src/templates/system.ts +32 -0
  93. package/src/types.ts +45 -1
  94. package/src/typings.d.ts +5 -0
  95. package/dist/lib/node/index.cjs +0 -2178
  96. package/dist/lib/node/index.cjs.map +0 -7
  97. package/dist/lib/node/meta.json +0 -1
  98. package/dist/types/bin/chat.d.ts +0 -2
  99. package/dist/types/bin/chat.d.ts.map +0 -1
  100. package/dist/types/src/blueprint/ai.test.d.ts +0 -2
  101. package/dist/types/src/blueprint/ai.test.d.ts.map +0 -1
  102. package/dist/types/src/blueprint/blueprint.d.ts +0 -55
  103. package/dist/types/src/blueprint/blueprint.d.ts.map +0 -1
  104. package/dist/types/src/blueprint/blueprint.test.d.ts +0 -2
  105. package/dist/types/src/blueprint/blueprint.test.d.ts.map +0 -1
  106. package/dist/types/src/blueprint/index.d.ts +0 -4
  107. package/dist/types/src/blueprint/index.d.ts.map +0 -1
  108. package/dist/types/src/blueprint/logger.d.ts +0 -25
  109. package/dist/types/src/blueprint/logger.d.ts.map +0 -1
  110. package/dist/types/src/blueprint/machine.d.ts +0 -143
  111. package/dist/types/src/blueprint/machine.d.ts.map +0 -1
  112. package/dist/types/src/blueprint/test-data.d.ts +0 -3
  113. package/dist/types/src/blueprint/test-data.d.ts.map +0 -1
  114. package/dist/types/src/research/exa.d.ts +0 -7
  115. package/dist/types/src/research/exa.d.ts.map +0 -1
  116. package/dist/types/src/research/graph.d.ts +0 -41
  117. package/dist/types/src/research/graph.d.ts.map +0 -1
  118. package/dist/types/src/research/graph.test.d.ts +0 -2
  119. package/dist/types/src/research/graph.test.d.ts.map +0 -1
  120. package/dist/types/src/research/index.d.ts +0 -4
  121. package/dist/types/src/research/index.d.ts.map +0 -1
  122. package/dist/types/src/research/research.d.ts +0 -10
  123. package/dist/types/src/research/research.d.ts.map +0 -1
  124. package/dist/types/src/research/research.test.d.ts +0 -2
  125. package/dist/types/src/research/research.test.d.ts.map +0 -1
  126. package/dist/types/src/testing/exa-search-1748337321991.d.ts +0 -38
  127. package/dist/types/src/testing/exa-search-1748337321991.d.ts.map +0 -1
  128. package/dist/types/src/testing/exa-search-1748337331526.d.ts +0 -37
  129. package/dist/types/src/testing/exa-search-1748337331526.d.ts.map +0 -1
  130. package/dist/types/src/testing/exa-search-1748337344119.d.ts +0 -58
  131. package/dist/types/src/testing/exa-search-1748337344119.d.ts.map +0 -1
  132. package/dist/types/src/testing/index.d.ts +0 -3
  133. package/dist/types/src/testing/index.d.ts.map +0 -1
  134. package/src/blueprint/ai.test.ts +0 -156
  135. package/src/blueprint/blueprint.test.ts +0 -151
  136. package/src/blueprint/blueprint.ts +0 -75
  137. package/src/blueprint/index.ts +0 -7
  138. package/src/blueprint/logger.ts +0 -155
  139. package/src/blueprint/machine.ts +0 -251
  140. package/src/blueprint/test-data.ts +0 -55
  141. package/src/research/exa.ts +0 -100
  142. package/src/research/graph.test.ts +0 -15
  143. package/src/research/graph.ts +0 -337
  144. package/src/research/index.ts +0 -7
  145. package/src/research/instructions-research.tpl +0 -97
  146. package/src/research/research.test.ts +0 -190
  147. package/src/research/research.ts +0 -89
  148. package/src/testing/exa-search-1748337321991.ts +0 -131
  149. package/src/testing/exa-search-1748337331526.ts +0 -144
  150. package/src/testing/exa-search-1748337344119.ts +0 -133
  151. package/src/testing/index.ts +0 -11
  152. package/src/typedefs.d.ts +0 -8
@@ -1,156 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import { AiChat, AiInput, AiLanguageModel, AiTool, AiToolkit } from '@effect/ai';
6
- import { AnthropicClient, AnthropicLanguageModel } from '@effect/ai-anthropic';
7
- import { OpenAiClient, OpenAiLanguageModel } from '@effect/ai-openai';
8
- import { NodeHttpClient } from '@effect/platform-node';
9
- import { Config, Console, Effect, Layer, pipe, Schedule, Schema } from 'effect';
10
- import { describe, it } from 'vitest';
11
-
12
- import { log } from '@dxos/log';
13
-
14
- // https://effect.website/docs/ai/tool-use/#5-bring-it-all-together
15
- // https://github.com/Effect-TS/effect/blob/main/packages/ai/ai/CHANGELOG.md
16
- // https://discord.com/channels/795981131316985866/1338871274398679130
17
-
18
- /**
19
- * Rationale:
20
- * - Separation of concerns: config, execution pipline, error handling/retry, tool dispatch, async.
21
- * - Uncouple tool definitions from tool implementation (late binding, composition).
22
- * - Affinity with effect schema.
23
- * - Leverage existing effect based conductor pipline.
24
- * - Simple API for plugins/artifacts.
25
- * - Ecosystem and design partner.
26
- */
27
- describe.runIf(!process.env.CI)('AiLanguageModel', () => {
28
- it.runIf(process.env.OPENAI_API_KEY)('Debug: Verify API configuration', async ({ expect }) => {
29
- const program = Effect.gen(function* () {
30
- yield* Console.log('Testing API connectivity...');
31
- const response = yield* AiLanguageModel.generateText({ prompt: 'Hello, respond with "API is working"' });
32
- yield* Console.log('API Response received:', response.text);
33
- return response.text;
34
- }).pipe(
35
- Effect.provide(OpenAiLanguageModel.model('gpt-4o')),
36
- Effect.timeout('10 seconds'),
37
- Effect.retry({ times: 1 }),
38
- );
39
-
40
- const result = await program.pipe(
41
- Effect.provide([
42
- OpenAiClient.layerConfig({
43
- apiKey: Config.redacted('OPENAI_API_KEY'),
44
- }).pipe(Layer.provide(NodeHttpClient.layerUndici)),
45
- ]),
46
- Effect.runPromise,
47
- );
48
-
49
- expect(result).to.contain('working');
50
- });
51
-
52
- // Tool definitions.
53
- class Toolkit extends AiToolkit.make(
54
- AiTool.make('Calculator', {
55
- description: 'Test tool',
56
- parameters: {
57
- input: Schema.String.annotations({
58
- description: 'The calculation to perform.',
59
- }),
60
- },
61
- success: Schema.Struct({
62
- result: Schema.Number,
63
- }),
64
- failure: Schema.Never,
65
- }),
66
- ) {}
67
-
68
- // Tool handlers.
69
- const ToolkitLayer = Toolkit.toLayer({
70
- Calculator: ({ input }) =>
71
- Effect.gen(function* () {
72
- const result = (() => {
73
- // Only allow basic arithmetic operations for safety.
74
- const sanitizedInput = input.replace(/[^0-9+\-*/().\s]/g, '');
75
- // eslint-disable-next-line no-new-func
76
- return Function(`"use strict"; return (${sanitizedInput})`)();
77
- })();
78
-
79
- yield* Console.log(`Executing calculation: ${input} = ${result}`);
80
- return { result };
81
- }),
82
- });
83
-
84
- // Providers.
85
- const OpenAiLayer = OpenAiClient.layerConfig({
86
- apiKey: Config.redacted('OPENAI_API_KEY'),
87
- }).pipe(Layer.provide(NodeHttpClient.layerUndici));
88
-
89
- const AnthropicLayer = AnthropicClient.layerConfig({
90
- apiKey: Config.redacted('ANTHROPIC_API_KEY'),
91
- }).pipe(Layer.provide(NodeHttpClient.layerUndici));
92
-
93
- it.runIf(process.env.OPENAI_API_KEY)('should make a tool call', async ({ expect }) => {
94
- const createProgram = (prompt: string) =>
95
- AiLanguageModel.generateText({
96
- toolkit: Toolkit,
97
- prompt,
98
- }).pipe(
99
- Effect.tap((response) => Console.log(response)),
100
- Effect.provide(OpenAiLanguageModel.model('gpt-4o')),
101
- Effect.retry(pipe(Schedule.exponential('1 second'), Schedule.intersect(Schedule.recurs(2)))),
102
- Effect.timeout('30 seconds'),
103
- );
104
-
105
- const program = createProgram('What is six times seven? Use appropriate tools and just answer with the number.');
106
- const result = await program.pipe(Effect.provide([ToolkitLayer, OpenAiLayer]), Effect.runPromise);
107
- expect(result).toBeDefined();
108
- });
109
-
110
- // TODO(burdon): Is this the effectful way to do this?
111
- const createChat = (prompt: string) =>
112
- Effect.gen(function* () {
113
- const chat = yield* AiChat.empty;
114
- const toolkit = yield* Toolkit;
115
-
116
- // Initial request.
117
- let response = yield* chat.generateText({ toolkit, prompt });
118
-
119
- // Agentic loop.
120
- while (response.results.size > 0) {
121
- response = yield* chat.generateText({ toolkit, prompt: AiInput.empty });
122
- }
123
-
124
- // Done.
125
- return response.text;
126
- });
127
-
128
- it.runIf(process.env.OPENAI_API_KEY)('should process an agentic loop using OpenAI', async ({ expect }) => {
129
- const chat = createChat('What is six times seven?');
130
- const result = await chat.pipe(
131
- Effect.provide(OpenAiLanguageModel.model('gpt-4o')),
132
- Effect.provide(OpenAiLayer),
133
- Effect.provide(ToolkitLayer),
134
- Effect.runPromise,
135
- );
136
-
137
- log.info('result', { result });
138
- expect(result).toContain('42');
139
- });
140
-
141
- // TODO(burdon): Fix Anthropic.
142
- it.runIf(process.env.ANTHROPIC_API_KEY).skip('should process an agentic loop using Anthropic', async ({ expect }) => {
143
- const chat = createChat('What is six times seven?');
144
- const result = await chat.pipe(
145
- Effect.provide(AnthropicLanguageModel.model('claude-3-5-sonnet-latest')),
146
- Effect.provide(AnthropicLayer),
147
- Effect.provide(ToolkitLayer),
148
- Effect.runPromise,
149
- );
150
-
151
- log.info('result', { result });
152
- expect(result).toContain('42');
153
- });
154
-
155
- // TODO(burdon): Implement MCP server for ECHO on CF.
156
- });
@@ -1,151 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import { Schema } from 'effect';
6
- import { describe, test } from 'vitest';
7
-
8
- import { EdgeAiServiceClient, ToolRegistry, ToolResult, createTool } from '@dxos/ai';
9
- import { AI_SERVICE_ENDPOINT, EXA_API_KEY } from '@dxos/ai/testing';
10
- import { ArtifactId } from '@dxos/artifact';
11
- import { Obj } from '@dxos/echo';
12
- import { EchoTestBuilder } from '@dxos/echo-db/testing';
13
- import { DataType, DataTypes } from '@dxos/schema';
14
-
15
- import { BlueprintBuilder } from './blueprint';
16
- import { setConsolePrinter } from './logger';
17
- import { BlueprintMachine } from './machine';
18
- import { TEST_EMAILS } from './test-data';
19
- import { createGraphWriterTool, createLocalSearchTool } from '../research';
20
- import { createExaTool } from '../research/exa';
21
-
22
- // TODO(burdon): Conslidate with existing artifact definition and create JSON DSL.
23
-
24
- // TODO(burdon): Don't run on CI.
25
- describe.skip('Blueprint', () => {
26
- const aiClient = new EdgeAiServiceClient({
27
- endpoint: AI_SERVICE_ENDPOINT.REMOTE,
28
- defaultGenerationOptions: {
29
- // model: '@anthropic/claude-sonnet-4-20250514',
30
- model: '@anthropic/claude-3-5-sonnet-20241022',
31
- },
32
- });
33
-
34
- test('follows a simple blueprint', { timeout: 60_000 }, async () => {
35
- const blueprint = BlueprintBuilder.create()
36
- .step('Generate an idea for a new product. Do not use any external tools for this.')
37
- .step('Write a short description of the product.')
38
- .step('Run a market research to see if the product is viable. Do not use any external tools for this.')
39
- .step('Write a pitch deck for the product')
40
- .build();
41
-
42
- const tools = new ToolRegistry([]);
43
- const machine = new BlueprintMachine(tools, blueprint);
44
- setConsolePrinter(machine, true);
45
- await machine.runToCompletion({ aiClient });
46
- });
47
-
48
- test('email bot', { timeout: 60_000 }, async () => {
49
- const replyTool = createTool('email', {
50
- name: 'reply',
51
- description: 'Reply to the email',
52
- schema: Schema.Struct({
53
- toEmail: ArtifactId,
54
- subject: Schema.String.annotations({
55
- description: 'The subject of the reply',
56
- }),
57
- body: Schema.String.annotations({
58
- description: 'The body of the reply',
59
- }),
60
- }),
61
- execute: async (params) => {
62
- console.log('reply', params);
63
- return ToolResult.Success('Sent!');
64
- },
65
- });
66
-
67
- const labelTool = createTool('email', {
68
- name: 'label',
69
- description: 'Apply a label to the email',
70
- schema: Schema.Struct({
71
- toEmail: ArtifactId,
72
- label: Schema.String.annotations({
73
- description: 'The label to apply to the email',
74
- }),
75
- }),
76
- execute: async (params) => {
77
- return ToolResult.Success('Labeled!');
78
- },
79
- });
80
-
81
- const blueprint = BlueprintBuilder.create()
82
- .step(
83
- 'Determine if the email is introduction, question, or spam. Bail if email does not fit into one of these categories.',
84
- )
85
- .step('If the email is spam, label it as spam and do not respond.', {
86
- tools: [labelTool.id],
87
- })
88
- .step(
89
- 'If the email is an introduction, respond with a short introduction of yourself and ask for more information.',
90
- {
91
- tools: [replyTool.id],
92
- },
93
- )
94
- .step('If the email is a question, respond with a short answer and ask for more information.', {
95
- tools: [replyTool.id],
96
- })
97
- .build();
98
-
99
- const tools = new ToolRegistry([replyTool, labelTool]);
100
- const machine = new BlueprintMachine(tools, blueprint);
101
- setConsolePrinter(machine);
102
- await machine.runToCompletion({ aiClient, input: TEST_EMAILS[0] });
103
- });
104
-
105
- test.only('research', { timeout: 120_000 }, async () => {
106
- const builder = await new EchoTestBuilder().open();
107
- const { db } = await builder.createDatabase({ indexing: { vector: true }, types: DataTypes });
108
-
109
- const [org1] = [
110
- db.add(
111
- Obj.make(DataType.Organization, {
112
- name: 'Exa',
113
- website: 'https://exa.ai',
114
- description: 'An AI-powered search engine company building search infrastructure for AI agents',
115
- }),
116
- ),
117
- db.add(
118
- Obj.make(DataType.Organization, {
119
- name: 'Cresta',
120
- website: 'https://cresta.ai',
121
- description: 'A company that builds AI agents',
122
- }),
123
- ),
124
- ];
125
-
126
- await db.flush({ indexes: true });
127
-
128
- const [exa, localSearch, graphWriter] = [
129
- createExaTool({ apiKey: EXA_API_KEY }),
130
- createLocalSearchTool(db),
131
- createGraphWriterTool({ db, schema: DataTypes }),
132
- ];
133
-
134
- const blueprint = BlueprintBuilder.create()
135
- .step('Research founders of the organization. Do deep research.', {
136
- tools: [exa.id],
137
- })
138
- .step('Based on your research select matching entires that are already in the graph', {
139
- tools: [localSearch.id],
140
- })
141
- .step('Add researched data to the graph', {
142
- tools: [localSearch.id, graphWriter.id],
143
- })
144
- .build();
145
-
146
- const tools = new ToolRegistry([exa, localSearch, graphWriter]);
147
- const machine = new BlueprintMachine(tools, blueprint);
148
- setConsolePrinter(machine, true);
149
- await machine.runToCompletion({ aiClient, input: org1 });
150
- });
151
- });
@@ -1,75 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import { Schema } from 'effect';
6
-
7
- import { Key, Obj, Type } from '@dxos/echo';
8
-
9
- export const BlueprintStep = Schema.Struct({
10
- id: Key.ObjectId,
11
- instructions: Schema.String,
12
- tools: Schema.optional(Schema.Array(Schema.String)),
13
- });
14
- export interface BlueprintStep extends Schema.Schema.Type<typeof BlueprintStep> {}
15
-
16
- export const BlueprintDefinition = Schema.Struct({
17
- steps: Schema.Array(BlueprintStep.pipe(Schema.omit('id'))),
18
- });
19
- export interface BlueprintDefinition extends Schema.Schema.Type<typeof BlueprintDefinition> {}
20
-
21
- export const Blueprint = Schema.Struct({
22
- name: Schema.optional(Schema.String),
23
- steps: Schema.Array(BlueprintStep),
24
- }).pipe(
25
- Type.Obj({
26
- typename: 'dxos.org/type/Blueprint',
27
- version: '0.1.0',
28
- }),
29
- );
30
- export interface Blueprint extends Schema.Schema.Type<typeof Blueprint> {}
31
-
32
- /**
33
- * Blueprint builder API.
34
- */
35
- export namespace BlueprintBuilder {
36
- export const create = () => new Builder();
37
-
38
- class Builder {
39
- private readonly _steps: BlueprintStep[] = [];
40
-
41
- step(instructions: string, options?: { tools?: string[] }): Builder {
42
- this._steps.push({
43
- id: Key.ObjectId.random(),
44
- instructions,
45
- tools: options?.tools ?? [],
46
- });
47
-
48
- return this;
49
- }
50
-
51
- build(): Blueprint {
52
- return Obj.make(Blueprint, { steps: this._steps });
53
- }
54
- }
55
- }
56
-
57
- /**
58
- * Blueprint parser API.
59
- */
60
- export namespace BlueprintParser {
61
- export const create = () => new Parser();
62
-
63
- class Parser {
64
- parse({ steps }: BlueprintDefinition): Blueprint {
65
- const builder = BlueprintBuilder.create();
66
- for (const step of steps) {
67
- builder.step(step.instructions, {
68
- tools: (step.tools ?? []) as string[],
69
- });
70
- }
71
-
72
- return builder.build();
73
- }
74
- }
75
- }
@@ -1,7 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- export * from './blueprint';
6
- export * from './machine';
7
- export * from './logger';
@@ -1,155 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import { type ReadonlySignal, signal } from '@preact/signals-core';
6
- import chalk from 'chalk';
7
-
8
- import { ConsolePrinter } from '@dxos/ai';
9
- import { type CleanupFn, combine } from '@dxos/async';
10
- import { log } from '@dxos/log';
11
-
12
- import { type Blueprint } from './blueprint';
13
- import {
14
- type BlueprintEvent,
15
- type BlueprintLogger,
16
- type BlueprintMachine,
17
- type BlueprintMachineState,
18
- } from './machine';
19
-
20
- /* eslint-disable no-console */
21
-
22
- // Force chalk colors on for tests.
23
- chalk.level = 2;
24
-
25
- // TODO(burdon): Factor out.
26
- type ConsoleLogSignature = (message: string, arg?: any) => void;
27
-
28
- interface Logger {
29
- log: ConsoleLogSignature;
30
- }
31
-
32
- const DEFAULT_LOGGER: Logger = { log: log.info };
33
-
34
- /**
35
- * Reactive bufferedlogger.
36
- */
37
- export class BufferedLogger implements Logger {
38
- private _messages = signal<string[]>([]);
39
-
40
- get messages(): ReadonlySignal<string[]> {
41
- return this._messages;
42
- }
43
-
44
- clear() {
45
- this._messages.value = [];
46
- }
47
-
48
- log(message: string) {
49
- this._messages.value = [...this._messages.value, message];
50
- }
51
- }
52
-
53
- // TODO(burdon): Reconcile with ConsolePrinter.
54
- export class BlueprintLoggerAdapter implements BlueprintLogger {
55
- constructor(private readonly logger: Logger = DEFAULT_LOGGER) {}
56
-
57
- log(event: BlueprintEvent) {
58
- switch (event.type) {
59
- case 'begin':
60
- this.logger.log('begin', { invocationId: event.invocationId });
61
- break;
62
- case 'end':
63
- this.logger.log('end', { invocationId: event.invocationId });
64
- break;
65
- case 'step-start':
66
- this.logger.log('step-start', { invocationId: event.invocationId, step: event.step });
67
- break;
68
- case 'step-complete':
69
- this.logger.log('step-complete', { invocationId: event.invocationId, step: event.step });
70
- break;
71
- case 'message':
72
- this.logger.log('message', { invocationId: event.invocationId, message: event.message });
73
- break;
74
- case 'block':
75
- this.logger.log('block', { invocationId: event.invocationId, block: event.block });
76
- break;
77
- }
78
- }
79
- }
80
-
81
- export const setLogger = (machine: BlueprintMachine, logger: BufferedLogger): CleanupFn => {
82
- return combine(
83
- machine.begin.on(() => {
84
- logger.log('Starting...');
85
- }),
86
- machine.stepStart.on((step) => {
87
- const index = machine.blueprint.steps.indexOf(step);
88
- logger.log(`Step ${index + 1} of ${machine.blueprint.steps.length}`);
89
- logger.log(`Instructions: ${step.instructions}`);
90
- }),
91
- machine.stepComplete.on((step) => {
92
- const trace = machine.state.trace.find((t) => t.stepId === step.id);
93
- logger.log(`Complete: ${trace?.comment}`);
94
- }),
95
- machine.end.on(() => {
96
- logger.log('OK');
97
- }),
98
- );
99
- };
100
-
101
- export const setConsolePrinter = (machine: BlueprintMachine, verbose = false): CleanupFn => {
102
- const printer = new ConsolePrinter();
103
- return combine(
104
- machine.begin.on(() => printTrace(machine.blueprint, machine.state)),
105
- machine.stepStart.on((step) =>
106
- console.log(
107
- `\n${chalk.magenta(`${chalk.bold(`STEP ${machine.blueprint.steps.indexOf(step) + 1} of ${machine.blueprint.steps.length}:`)} ${step.instructions}`)}\n`,
108
- ),
109
- ),
110
- machine.stepComplete.on(() => printTrace(machine.blueprint, machine.state)),
111
- machine.end.on(() => console.log('DONE')),
112
- verbose
113
- ? [
114
- machine.message.on((msg) => printer.printMessage(msg)),
115
- machine.block.on((block) => printer.printContentBlock(block)),
116
- ]
117
- : [],
118
- );
119
- };
120
-
121
- const BREAK_LINE = `\n${'_'.repeat(80)}\n`;
122
-
123
- const printTrace = (blueprint: Blueprint, state: BlueprintMachineState) => {
124
- console.group(chalk.bold('\nBlueprint'));
125
- blueprint.steps.forEach((step) => {
126
- const traceStep = state.trace.find((t) => t.stepId === step.id);
127
-
128
- let color = chalk.gray; // Not executed.
129
- let bullet = '○';
130
- if (traceStep) {
131
- switch (traceStep.status) {
132
- case 'done':
133
- color = chalk.green;
134
- bullet = '✓';
135
- break;
136
- case 'skipped':
137
- color = chalk.blue;
138
- bullet = '↓';
139
- break;
140
- case 'bailed':
141
- color = chalk.red;
142
- bullet = '✗';
143
- break;
144
- }
145
- }
146
-
147
- console.log(color(`\n${bullet} ${step.instructions}`));
148
- if (traceStep?.comment) {
149
- console.log(chalk.white(` ↳ ${traceStep.comment}`));
150
- }
151
- });
152
-
153
- console.groupEnd();
154
- console.log(BREAK_LINE);
155
- };