@dxos/assistant 0.8.4-main.fd6878d → 0.8.4-staging.60fe92afc8

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 (183) hide show
  1. package/LICENSE +102 -5
  2. package/README.md +2 -1
  3. package/dist/lib/neutral/chunk-J5LGTIGS.mjs +10 -0
  4. package/dist/lib/neutral/extraction/index.mjs +208 -0
  5. package/dist/lib/neutral/extraction/index.mjs.map +7 -0
  6. package/dist/lib/neutral/index.mjs +1886 -0
  7. package/dist/lib/neutral/index.mjs.map +7 -0
  8. package/dist/lib/neutral/meta.json +1 -0
  9. package/dist/types/src/extraction/extraction-ner-function/index.d.ts +0 -1
  10. package/dist/types/src/extraction/extraction-ner-function/index.d.ts.map +1 -1
  11. package/dist/types/src/extraction/extraction-ner-function/named-entity-recognition.d.ts.map +1 -1
  12. package/dist/types/src/extraction/extraction.d.ts +1650 -281
  13. package/dist/types/src/extraction/extraction.d.ts.map +1 -1
  14. package/dist/types/src/extraction/index.d.ts +0 -1
  15. package/dist/types/src/extraction/index.d.ts.map +1 -1
  16. package/dist/types/src/extraction/quotes.d.ts +3 -3
  17. package/dist/types/src/extraction/quotes.d.ts.map +1 -1
  18. package/dist/types/src/functions/services.d.ts +16 -5
  19. package/dist/types/src/functions/services.d.ts.map +1 -1
  20. package/dist/types/src/index.d.ts +2 -3
  21. package/dist/types/src/index.d.ts.map +1 -1
  22. package/dist/types/src/request/AiRequest.d.ts +308 -0
  23. package/dist/types/src/request/AiRequest.d.ts.map +1 -0
  24. package/dist/types/src/{session → request}/artifact-diff.d.ts +5 -5
  25. package/dist/types/src/request/artifact-diff.d.ts.map +1 -0
  26. package/dist/types/src/request/format.d.ts +15 -0
  27. package/dist/types/src/request/format.d.ts.map +1 -0
  28. package/dist/types/src/request/index.d.ts +4 -0
  29. package/dist/types/src/request/index.d.ts.map +1 -0
  30. package/dist/types/src/request/observer.d.ts +23 -0
  31. package/dist/types/src/request/observer.d.ts.map +1 -0
  32. package/dist/types/src/{session → request}/version-pin.d.ts +6 -6
  33. package/dist/types/src/request/version-pin.d.ts.map +1 -0
  34. package/dist/types/src/session/AiContext.d.ts +178 -0
  35. package/dist/types/src/session/AiContext.d.ts.map +1 -0
  36. package/dist/types/src/session/AiContext.test.d.ts +2 -0
  37. package/dist/types/src/session/AiContext.test.d.ts.map +1 -0
  38. package/dist/types/src/session/AiSession.d.ts +79 -0
  39. package/dist/types/src/session/AiSession.d.ts.map +1 -0
  40. package/dist/types/src/session/AiSession.test.d.ts +2 -0
  41. package/dist/types/src/session/AiSession.test.d.ts.map +1 -0
  42. package/dist/types/src/session/SessionLink.d.ts +17 -0
  43. package/dist/types/src/session/SessionLink.d.ts.map +1 -0
  44. package/dist/types/src/session/SessionLoader.d.ts +15 -0
  45. package/dist/types/src/session/SessionLoader.d.ts.map +1 -0
  46. package/dist/types/src/session/SessionLoader.test.d.ts +2 -0
  47. package/dist/types/src/session/SessionLoader.test.d.ts.map +1 -0
  48. package/dist/types/src/session/index.d.ts +5 -3
  49. package/dist/types/src/session/index.d.ts.map +1 -1
  50. package/dist/types/src/session/toolkit.d.ts +16 -0
  51. package/dist/types/src/session/toolkit.d.ts.map +1 -0
  52. package/dist/types/src/templates/system.d.ts +19 -14
  53. package/dist/types/src/templates/system.d.ts.map +1 -1
  54. package/dist/types/src/util/artifact.d.ts +18 -0
  55. package/dist/types/src/util/artifact.d.ts.map +1 -0
  56. package/dist/types/src/util/diff.d.ts +17 -0
  57. package/dist/types/src/util/diff.d.ts.map +1 -0
  58. package/dist/types/src/util/diff.test.d.ts +2 -0
  59. package/dist/types/src/util/diff.test.d.ts.map +1 -0
  60. package/dist/types/src/util/error-handling.d.ts +4 -0
  61. package/dist/types/src/util/error-handling.d.ts.map +1 -0
  62. package/dist/types/src/util/errors.d.ts +67 -0
  63. package/dist/types/src/util/errors.d.ts.map +1 -0
  64. package/dist/types/src/util/execution-graph.d.ts +85 -0
  65. package/dist/types/src/util/execution-graph.d.ts.map +1 -0
  66. package/dist/types/src/util/execution-graph.test.d.ts +2 -0
  67. package/dist/types/src/util/execution-graph.test.d.ts.map +1 -0
  68. package/dist/types/src/util/index.d.ts +7 -0
  69. package/dist/types/src/util/index.d.ts.map +1 -0
  70. package/dist/types/src/util/tracing.d.ts +296 -0
  71. package/dist/types/src/util/tracing.d.ts.map +1 -0
  72. package/dist/types/tsconfig.tsbuildinfo +1 -1
  73. package/package.json +37 -47
  74. package/src/extraction/extraction-ner-function/index.ts +0 -1
  75. package/src/extraction/extraction-ner-function/named-entity-recognition.test.ts +12 -6
  76. package/src/extraction/extraction-ner-function/named-entity-recognition.ts +2 -0
  77. package/src/extraction/extraction.ts +49 -19
  78. package/src/extraction/index.ts +0 -1
  79. package/src/extraction/quotes.test.ts +2 -2
  80. package/src/extraction/quotes.ts +7 -9
  81. package/src/functions/services.ts +180 -66
  82. package/src/index.ts +2 -3
  83. package/src/request/AiRequest.ts +387 -0
  84. package/src/{session → request}/artifact-diff.ts +10 -6
  85. package/src/{session → request}/format.ts +45 -37
  86. package/src/request/index.ts +8 -0
  87. package/src/request/observer.ts +62 -0
  88. package/src/{session → request}/version-pin.ts +8 -8
  89. package/src/session/AiContext.test.ts +49 -0
  90. package/src/session/AiContext.ts +420 -0
  91. package/src/session/AiSession.test.ts +111 -0
  92. package/src/session/AiSession.ts +328 -0
  93. package/src/session/SessionLink.ts +23 -0
  94. package/src/session/SessionLoader.test.ts +115 -0
  95. package/src/session/SessionLoader.ts +55 -0
  96. package/src/session/index.ts +6 -3
  97. package/src/session/toolkit.ts +47 -0
  98. package/src/templates/{format.tpl → instructions/format.tpl} +6 -4
  99. package/src/templates/instructions/system.tpl +96 -0
  100. package/src/templates/system.ts +26 -16
  101. package/src/util/artifact.ts +96 -0
  102. package/src/util/diff.test.ts +74 -0
  103. package/src/util/diff.ts +93 -0
  104. package/src/util/error-handling.ts +42 -0
  105. package/src/util/errors.ts +15 -0
  106. package/src/util/execution-graph.test.ts +740 -0
  107. package/src/util/execution-graph.ts +520 -0
  108. package/src/util/index.ts +10 -0
  109. package/src/util/tracing.ts +60 -0
  110. package/dist/lib/browser/chunk-6WRGDEMH.mjs +0 -89
  111. package/dist/lib/browser/chunk-6WRGDEMH.mjs.map +0 -7
  112. package/dist/lib/browser/chunk-NZGGCEF3.mjs +0 -341
  113. package/dist/lib/browser/chunk-NZGGCEF3.mjs.map +0 -7
  114. package/dist/lib/browser/extraction/index.mjs +0 -269
  115. package/dist/lib/browser/extraction/index.mjs.map +0 -7
  116. package/dist/lib/browser/index.mjs +0 -354
  117. package/dist/lib/browser/index.mjs.map +0 -7
  118. package/dist/lib/browser/meta.json +0 -1
  119. package/dist/lib/browser/named-entity-recognition-O46UTCLR.mjs +0 -13
  120. package/dist/lib/node-esm/chunk-3UU5V4FS.mjs +0 -91
  121. package/dist/lib/node-esm/chunk-3UU5V4FS.mjs.map +0 -7
  122. package/dist/lib/node-esm/chunk-XOOPGSGW.mjs +0 -343
  123. package/dist/lib/node-esm/chunk-XOOPGSGW.mjs.map +0 -7
  124. package/dist/lib/node-esm/extraction/index.mjs +0 -270
  125. package/dist/lib/node-esm/extraction/index.mjs.map +0 -7
  126. package/dist/lib/node-esm/index.mjs +0 -355
  127. package/dist/lib/node-esm/index.mjs.map +0 -7
  128. package/dist/lib/node-esm/meta.json +0 -1
  129. package/dist/lib/node-esm/named-entity-recognition-W4VMRCH6.mjs +0 -14
  130. package/dist/lib/node-esm/named-entity-recognition-W4VMRCH6.mjs.map +0 -7
  131. package/dist/types/src/conversation/context.d.ts +0 -90
  132. package/dist/types/src/conversation/context.d.ts.map +0 -1
  133. package/dist/types/src/conversation/conversation.d.ts +0 -50
  134. package/dist/types/src/conversation/conversation.d.ts.map +0 -1
  135. package/dist/types/src/conversation/index.d.ts +0 -3
  136. package/dist/types/src/conversation/index.d.ts.map +0 -1
  137. package/dist/types/src/errors.d.ts +0 -39
  138. package/dist/types/src/errors.d.ts.map +0 -1
  139. package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.d.ts +0 -4
  140. package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.d.ts.map +0 -1
  141. package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.test.d.ts +0 -2
  142. package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.test.d.ts.map +0 -1
  143. package/dist/types/src/extraction/extraction-llm-function/index.d.ts +0 -2
  144. package/dist/types/src/extraction/extraction-llm-function/index.d.ts.map +0 -1
  145. package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts +0 -306
  146. package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts.map +0 -1
  147. package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.test.d.ts +0 -2
  148. package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.test.d.ts.map +0 -1
  149. package/dist/types/src/session/artifact-diff.d.ts.map +0 -1
  150. package/dist/types/src/session/format.d.ts +0 -168
  151. package/dist/types/src/session/format.d.ts.map +0 -1
  152. package/dist/types/src/session/format.test.d.ts +0 -2
  153. package/dist/types/src/session/format.test.d.ts.map +0 -1
  154. package/dist/types/src/session/session.d.ts +0 -167
  155. package/dist/types/src/session/session.d.ts.map +0 -1
  156. package/dist/types/src/session/session.test.d.ts +0 -2
  157. package/dist/types/src/session/session.test.d.ts.map +0 -1
  158. package/dist/types/src/session/version-pin.d.ts.map +0 -1
  159. package/dist/types/src/session/version-pin.test.d.ts +0 -2
  160. package/dist/types/src/session/version-pin.test.d.ts.map +0 -1
  161. package/dist/types/src/summarization/summarization.test.d.ts +0 -2
  162. package/dist/types/src/summarization/summarization.test.d.ts.map +0 -1
  163. package/dist/types/src/types.d.ts +0 -16
  164. package/dist/types/src/types.d.ts.map +0 -1
  165. package/src/conversation/context.ts +0 -133
  166. package/src/conversation/conversation.ts +0 -125
  167. package/src/conversation/index.ts +0 -6
  168. package/src/errors.ts +0 -10
  169. package/src/extraction/extraction-llm-function/extraction-llm-function.test.ts +0 -84
  170. package/src/extraction/extraction-llm-function/extraction-llm-function.ts +0 -71
  171. package/src/extraction/extraction-llm-function/index.ts +0 -5
  172. package/src/extraction/extraction-ner-function/extraction-ner-function.test.ts +0 -116
  173. package/src/extraction/extraction-ner-function/extraction-ner-function.ts +0 -57
  174. package/src/session/__snapshots__/session.test.ts.snap +0 -32
  175. package/src/session/format.test.ts +0 -60
  176. package/src/session/session.test.ts +0 -305
  177. package/src/session/session.ts +0 -279
  178. package/src/session/version-pin.test.ts +0 -7
  179. package/src/summarization/summarization.test.ts +0 -197
  180. package/src/templates/system.tpl +0 -47
  181. package/src/types.ts +0 -52
  182. /package/dist/lib/{browser/named-entity-recognition-O46UTCLR.mjs.map → neutral/chunk-J5LGTIGS.mjs.map} +0 -0
  183. /package/src/extraction/extraction-llm-function/{instructions.tpl → transcription-instructions.tpl} +0 -0
@@ -0,0 +1,520 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { AgentStatus } from '@dxos/ai';
6
+ import { type Entity, Obj, type Ref } from '@dxos/echo';
7
+ import { MESSAGE_PROPERTY_TOOL_CALL_ID } from '@dxos/functions';
8
+ import { EID, type EntityId } from '@dxos/keys';
9
+ import { LogLevel } from '@dxos/log';
10
+ import { ContentBlock, Message } from '@dxos/types';
11
+ import { isNonNullable } from '@dxos/util';
12
+
13
+ const SKIP_BLOCKS: ContentBlock.Any['_tag'][] = ['text'];
14
+
15
+ /**
16
+ * Mercurial-style Commit.
17
+ */
18
+ // TODO(wittjosiah): Reconcile with @dxos/react-ui-components.
19
+ export type Commit = {
20
+ id: string;
21
+ parents: string[];
22
+ branch: string;
23
+ icon?: string;
24
+ level?: LogLevel;
25
+ message: string;
26
+ timestamp?: Date;
27
+ tags?: string[];
28
+ };
29
+
30
+ // TODO(burdon): Add colors?
31
+ enum IconType {
32
+ // General status.
33
+ SUCCESS = 'ph--check-circle--regular',
34
+ WARNING = 'ph--warning-circle--regular',
35
+ ERROR = 'ph--x-circle--regular',
36
+ FLAG = 'ph--flag--regular',
37
+ ROCKET = 'ph--rocket--regular',
38
+ TIMER = 'ph--timer--regular',
39
+
40
+ // Interactions.
41
+ USER = 'ph--user--regular',
42
+ USER_INTERACTION = 'ph--user-sound--regular',
43
+ AGENT = 'ph--drone--regular',
44
+ THINKING = 'ph--brain--regular',
45
+ LINK = 'ph--link--regular',
46
+ TOOL = 'ph--wrench--regular',
47
+ }
48
+
49
+ /**
50
+ * Models the execution graph based on a stream of events.
51
+ */
52
+ export class ExecutionGraph {
53
+ // TODO(dmaretskyi): Evolve the internal state to support chats, functions, circuit workflows, etc.
54
+ private _commits: Commit[] = [];
55
+ private _branchNames = new Set<string>();
56
+ private _lastBlockId: string | undefined;
57
+
58
+ // Tool call tracking.
59
+ private _toolCallCommitIds = new Map<string, string>(); // toolCallId -> commitId
60
+ private _lastCommitByBranch = new Map<string, string>(); // branch -> last commitId
61
+ private _pendingToolResults = new Map<string, string>(); // toolCallId -> toolResultCommitId
62
+
63
+ constructor(private readonly _skipBlocks: ContentBlock.Any['_tag'][] = SKIP_BLOCKS) {}
64
+
65
+ /**
66
+ * Adds events to the graph.
67
+ */
68
+ addEvents(events: Entity.Unknown[]) {
69
+ const sortedEvents = this.sortObjectsByCreated(events);
70
+ for (const event of sortedEvents) {
71
+ if (Obj.instanceOf(Message.Message, event)) {
72
+ this._processMessage(event);
73
+ } else if (Obj.instanceOf(AgentStatus, event)) {
74
+ this._processAgentStatus(event);
75
+ }
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Processes a message event and creates commits for its blocks.
81
+ */
82
+ private _processMessage(message: Message.Message) {
83
+ const messageCommits = messageToCommits(
84
+ message,
85
+ this._lastBlockId,
86
+ this._toolCallCommitIds,
87
+ this._lastCommitByBranch,
88
+ this._skipBlocks,
89
+ );
90
+ this._commits.push(...messageCommits);
91
+
92
+ // Track branches.
93
+ messageCommits.forEach((commit) => this._branchNames.add(commit.branch));
94
+
95
+ // Track tool calls and update pending tool results.
96
+ this._trackToolCalls(messageCommits);
97
+
98
+ // Update last block ID for sequential chaining.
99
+ if (messageCommits.length > 0) {
100
+ this._lastBlockId = messageCommits[messageCommits.length - 1].id;
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Processes an AgentStatus event.
106
+ */
107
+ private _processAgentStatus(event: AgentStatus) {
108
+ const branch = this._getToolCallBranch(event.parentMessage, event.toolCallId);
109
+ this._branchNames.add(branch);
110
+
111
+ const agentStatusCommit: Commit = {
112
+ id: event.id,
113
+ branch,
114
+ message: event.message,
115
+ icon: IconType.FLAG,
116
+ parents: this._getAgentStatusParents(event),
117
+ timestamp: new Date(event.created),
118
+ };
119
+
120
+ this._commits.push(agentStatusCommit);
121
+
122
+ // Update last block ID for sequential chaining.
123
+ this._lastBlockId = event.id;
124
+
125
+ // Update pending tool results to point to this AgentStatus.
126
+ if (event.toolCallId) {
127
+ this._lastCommitByBranch.set(branch, event.id);
128
+ this._updatePendingToolResults(event.toolCallId, event.id);
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Stable sort: objects with 'created' field are sorted by it, others remain in place.
134
+ */
135
+ private sortObjectsByCreated(objects: any[]) {
136
+ const sortedObjects = objects.slice();
137
+ // Find indices of objects with 'created'
138
+ const createdObjects: { idx: number; obj: any }[] = [];
139
+ sortedObjects.forEach((obj, idx) => {
140
+ if (obj && typeof obj.created === 'string') {
141
+ createdObjects.push({ idx, obj });
142
+ }
143
+ });
144
+ // Sort only the objects with 'created' by their date, stable
145
+ createdObjects.sort((a, b) => {
146
+ const aDate = new Date(a.obj.created).getTime();
147
+ const bDate = new Date(b.obj.created).getTime();
148
+ return aDate - bDate;
149
+ });
150
+ // Place sorted createdObjects back into their original positions
151
+ let createdIdx = 0;
152
+ return sortedObjects.map((obj, _idx) => {
153
+ if (obj && typeof obj.created === 'string') {
154
+ return createdObjects[createdIdx++].obj;
155
+ }
156
+ return obj;
157
+ });
158
+ }
159
+
160
+ /**
161
+ * Returns the current state of the graph.
162
+ */
163
+ getGraph(lastRequest = false): { branches: string[]; commits: Commit[] } {
164
+ const idx = lastRequest ? this._commits.findLastIndex((c) => c.tags?.includes('user')) : -1;
165
+ const commits = idx === -1 ? this._commits : this._commits.slice(idx);
166
+
167
+ return {
168
+ branches: Array.from(this._branchNames),
169
+ commits,
170
+ };
171
+ }
172
+
173
+ /**
174
+ * Tracks tool calls and handles pending tool result updates.
175
+ */
176
+ private _trackToolCalls(commits: Commit[]) {
177
+ commits.forEach((commit) => {
178
+ if (this._isToolCallCommit(commit)) {
179
+ const toolCallId = this._extractToolCallId(commit.id);
180
+ if (toolCallId) {
181
+ this._toolCallCommitIds.set(toolCallId, commit.id);
182
+ }
183
+ }
184
+
185
+ if (this._isToolResultCommit(commit)) {
186
+ const toolCallId = this._extractToolCallId(commit.id);
187
+ if (toolCallId) {
188
+ this._pendingToolResults.set(toolCallId, commit.id);
189
+ this._handleLateToolResultUpdate(toolCallId, commit.id);
190
+ }
191
+ }
192
+
193
+ this._lastCommitByBranch.set(commit.branch, commit.id);
194
+ });
195
+ }
196
+
197
+ /**
198
+ * Updates pending tool results to point to an AgentStatus event.
199
+ */
200
+ private _updatePendingToolResults(toolCallId: string, agentStatusId: string) {
201
+ const toolResultId = this._pendingToolResults.get(toolCallId);
202
+ if (!toolResultId) {
203
+ return;
204
+ }
205
+
206
+ const toolResultCommit = this._commits.find((c) => c.id === toolResultId);
207
+ if (!toolResultCommit) {
208
+ return;
209
+ }
210
+
211
+ const toolCallCommitId = this._toolCallCommitIds.get(toolCallId);
212
+ if (!toolCallCommitId) {
213
+ return;
214
+ }
215
+
216
+ // Replace tool call commit with AgentStatus commit.
217
+ const toolCallIndex = toolResultCommit.parents.indexOf(toolCallCommitId);
218
+ if (toolCallIndex !== -1) {
219
+ toolResultCommit.parents[toolCallIndex] = agentStatusId;
220
+ }
221
+
222
+ this._pendingToolResults.delete(toolCallId);
223
+ }
224
+
225
+ /**
226
+ * Handles late updates when AgentStatus is processed before tool result.
227
+ */
228
+ private _handleLateToolResultUpdate(toolCallId: string, toolResultId: string) {
229
+ const toolCallCommitId = this._toolCallCommitIds.get(toolCallId);
230
+ if (!toolCallCommitId) {
231
+ return;
232
+ }
233
+
234
+ const messageId = toolCallCommitId.split('_toolCall_')[0];
235
+ const toolCallBranch = `${messageId}_${toolCallId}`;
236
+ const agentStatusCommitId = this._lastCommitByBranch.get(toolCallBranch);
237
+
238
+ if (agentStatusCommitId && agentStatusCommitId !== toolCallCommitId) {
239
+ const toolResultCommit = this._commits.find((c) => c.id === toolResultId);
240
+ if (toolResultCommit) {
241
+ const toolCallIndex = toolResultCommit.parents.indexOf(toolCallCommitId);
242
+ if (toolCallIndex !== -1) {
243
+ toolResultCommit.parents[toolCallIndex] = agentStatusCommitId;
244
+ }
245
+ }
246
+ this._pendingToolResults.delete(toolCallId);
247
+ }
248
+ }
249
+
250
+ /**
251
+ * Gets the branch name for a tool call.
252
+ */
253
+ private _getToolCallBranch(parentMessage?: EntityId, toolCallId?: string): string {
254
+ if (toolCallId) {
255
+ return toolCallId;
256
+ }
257
+ return parentMessage || 'main';
258
+ }
259
+
260
+ /**
261
+ * Gets the parents for an AgentStatus commit.
262
+ */
263
+ private _getAgentStatusParents(event: AgentStatus): string[] {
264
+ if (event.parentMessage && event.toolCallId) {
265
+ return [getToolCallId(event.parentMessage, event.toolCallId)];
266
+ }
267
+ return [];
268
+ }
269
+
270
+ /**
271
+ * Checks if a commit is a tool call commit.
272
+ */
273
+ private _isToolCallCommit(commit: Commit): boolean {
274
+ return commit.message.includes('Calling tool');
275
+ }
276
+
277
+ /**
278
+ * Checks if a commit is a tool result commit.
279
+ */
280
+ private _isToolResultCommit(commit: Commit): boolean {
281
+ return commit.message.includes('Tool call succeeded') || commit.message.includes('Tool error:');
282
+ }
283
+
284
+ /**
285
+ * Extracts tool call ID from a commit ID.
286
+ */
287
+ private _extractToolCallId(commitId: string): string | undefined {
288
+ const toolCallMatch = commitId.match(/_toolCall_(.+)$/);
289
+ const toolResultMatch = commitId.match(/_toolResult_(.+)$/);
290
+ return toolCallMatch?.[1] || toolResultMatch?.[1];
291
+ }
292
+ }
293
+
294
+ /**
295
+ * Creates commits for all blocks in a message.
296
+ */
297
+ // TODO(burdon): Pass in AiToolProvider.
298
+ const messageToCommits = (
299
+ message: Message.Message,
300
+ lastBlockId?: string,
301
+ toolCallIds?: Map<string, string>,
302
+ lastCommitByBranch?: Map<string, string>,
303
+ skipBlocks?: ContentBlock.Any['_tag'][],
304
+ ): Commit[] => {
305
+ let previousBlockId: string | undefined = lastBlockId;
306
+
307
+ return message.blocks
308
+ .map((block, idx) => {
309
+ const branch = getMessageBranch(message);
310
+ const parents = getBlockParents(block, previousBlockId, message, toolCallIds, lastCommitByBranch);
311
+ if (skipBlocks?.includes(block._tag)) {
312
+ return null;
313
+ }
314
+
315
+ const commit = createBlockCommit(block, message, branch, parents, idx);
316
+ if (commit) {
317
+ previousBlockId = commit.id;
318
+ }
319
+
320
+ return commit;
321
+ })
322
+ .filter(isNonNullable);
323
+ };
324
+
325
+ /**
326
+ * Determines the parent commits for a block based on its type and context.
327
+ */
328
+ const getBlockParents = (
329
+ block: ContentBlock.Any,
330
+ previousBlockId: string | undefined,
331
+ message: Message.Message,
332
+ toolCallIds?: Map<string, string>,
333
+ lastCommitByBranch?: Map<string, string>,
334
+ ): string[] => {
335
+ const parents: string[] = [];
336
+
337
+ if (block._tag === 'toolResult') {
338
+ // Tool results have two parents: previous block and last block from tool call branch.
339
+ if (previousBlockId) {
340
+ parents.push(previousBlockId);
341
+ }
342
+
343
+ const toolCallCommitId = toolCallIds?.get(block.toolCallId);
344
+ if (toolCallCommitId) {
345
+ const toolCallBranch = getToolCallBranchFromCommitId(toolCallCommitId, block.toolCallId);
346
+ const lastBlockFromToolCallBranch = lastCommitByBranch?.get(toolCallBranch);
347
+
348
+ if (lastBlockFromToolCallBranch) {
349
+ parents.push(lastBlockFromToolCallBranch);
350
+ } else {
351
+ // Fallback to tool call commit if no AgentStatus exists yet.
352
+ parents.push(toolCallCommitId);
353
+ }
354
+ }
355
+ } else {
356
+ // For other blocks, use previous block as parent (or tool call parent for first block).
357
+ if (previousBlockId) {
358
+ parents.push(previousBlockId);
359
+ } else {
360
+ const toolCallParent = getParentId(message);
361
+ if (toolCallParent) {
362
+ parents.push(toolCallParent);
363
+ }
364
+ }
365
+ }
366
+
367
+ return parents;
368
+ };
369
+
370
+ /**
371
+ * Creates a commit for a specific block.
372
+ */
373
+ const createBlockCommit = (
374
+ block: ContentBlock.Any,
375
+ message: Message.Message,
376
+ branch: string,
377
+ parents: string[],
378
+ idx: number,
379
+ ): Commit | null => {
380
+ const timestamp = new Date(message.created);
381
+ switch (block._tag) {
382
+ case 'text':
383
+ if (!block.text.trim().length) {
384
+ return null;
385
+ }
386
+ return {
387
+ id: getGenericBlockId(message.id, idx),
388
+ branch,
389
+ parents,
390
+ timestamp,
391
+ ...(message.sender.role === 'user'
392
+ ? {
393
+ icon: IconType.USER,
394
+ tags: ['user'],
395
+ message: 'Processing request...',
396
+ }
397
+ : {
398
+ icon: IconType.AGENT,
399
+ message: `Response (${block.text.split(' ').length} words)`,
400
+ }),
401
+ } satisfies Commit;
402
+
403
+ case 'toolCall':
404
+ return {
405
+ id: getToolCallId(message.id, block.toolCallId),
406
+ branch,
407
+ parents,
408
+ timestamp,
409
+ icon: IconType.TOOL,
410
+ level: LogLevel.INFO,
411
+ message: `Calling tool (${block.name})`,
412
+ } satisfies Commit;
413
+
414
+ case 'toolResult':
415
+ return {
416
+ id: getToolResultId(message.id, block.toolCallId),
417
+ branch,
418
+ parents,
419
+ timestamp,
420
+ icon: block.error ? IconType.ERROR : IconType.SUCCESS,
421
+ level: block.error ? LogLevel.ERROR : LogLevel.INFO,
422
+ message: block.error ? 'Tool error: ' + block.error : 'Tool call succeeded',
423
+ } satisfies Commit;
424
+
425
+ case 'stats':
426
+ return {
427
+ id: getGenericBlockId(message.id, idx),
428
+ branch,
429
+ parents,
430
+ timestamp,
431
+ icon: IconType.ROCKET,
432
+ level: LogLevel.INFO,
433
+ message: ContentBlock.createStatsMessage(block),
434
+ } satisfies Commit;
435
+
436
+ case 'status':
437
+ return {
438
+ id: getGenericBlockId(message.id, idx),
439
+ branch,
440
+ parents,
441
+ timestamp,
442
+ message: block.statusText,
443
+ level: LogLevel.INFO,
444
+ icon: IconType.FLAG,
445
+ } satisfies Commit;
446
+
447
+ case 'reasoning':
448
+ return {
449
+ id: getGenericBlockId(message.id, idx),
450
+ branch,
451
+ parents,
452
+ timestamp,
453
+ message: block.reasoningText ?? 'Thinking...',
454
+ icon: IconType.THINKING,
455
+ } satisfies Commit;
456
+
457
+ case 'reference':
458
+ return {
459
+ id: getGenericBlockId(message.id, idx),
460
+ branch,
461
+ parents,
462
+ timestamp,
463
+ icon: IconType.LINK,
464
+ message: stringifyRef(block.reference),
465
+ } satisfies Commit;
466
+
467
+ default:
468
+ return null;
469
+ }
470
+ };
471
+
472
+ /**
473
+ * Gets the tool call branch name from a tool call commit ID.
474
+ */
475
+ const getToolCallBranchFromCommitId = (toolCallCommitId: string, toolCallId: string): string => {
476
+ const messageId = toolCallCommitId.split('_toolCall_')[0];
477
+ return `${messageId}_${toolCallId}`;
478
+ };
479
+
480
+ const getToolCallId = (messageId: EntityId, toolCallId: string) => `${messageId}_toolCall_${toolCallId}`;
481
+ const getToolResultId = (messageId: EntityId, toolCallId: string) => `${messageId}_toolResult_${toolCallId}`;
482
+ const getGenericBlockId = (messageId: EntityId, idx: number) => `${messageId}_block_${idx}`;
483
+
484
+ const getBranchName = (options: { parentMessage?: EntityId; toolCallId?: string }) => {
485
+ if (options.toolCallId) {
486
+ return options.toolCallId;
487
+ } else if (options.parentMessage) {
488
+ return options.parentMessage;
489
+ } else {
490
+ return 'main';
491
+ }
492
+ };
493
+
494
+ const getMessageBranch = (message: Message.Message) => {
495
+ return getBranchName({
496
+ parentMessage: message.parentMessage,
497
+ toolCallId: message.properties?.[MESSAGE_PROPERTY_TOOL_CALL_ID],
498
+ });
499
+ };
500
+
501
+ const getParentId = (message: Message.Message) => {
502
+ if (message.parentMessage && message.properties?.[MESSAGE_PROPERTY_TOOL_CALL_ID]) {
503
+ return getToolCallId(message.parentMessage, message.properties[MESSAGE_PROPERTY_TOOL_CALL_ID]);
504
+ } else {
505
+ return undefined;
506
+ }
507
+ };
508
+
509
+ const stringifyRef = (ref: Ref.Unknown) => {
510
+ if (ref.target) {
511
+ return stringifyObject(ref.target);
512
+ }
513
+
514
+ const echoUri = EID.tryParse(ref.uri);
515
+ return (echoUri ? EID.getEntityId(echoUri) : undefined) ?? '';
516
+ };
517
+
518
+ const stringifyObject = (obj: Obj.Unknown) => {
519
+ return Obj.getLabel(obj) ?? Obj.getTypename(obj) ?? obj.id;
520
+ };
@@ -0,0 +1,10 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './artifact';
6
+ export * from './diff';
7
+ export * from './error-handling';
8
+ export * from './errors';
9
+ export * from './execution-graph';
10
+ export * from './tracing';
@@ -0,0 +1,60 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Schema from 'effect/Schema';
6
+
7
+ import { Trace } from '@dxos/compute';
8
+ import { Obj } from '@dxos/echo';
9
+ import { ContentBlock, Actor } from '@dxos/types';
10
+
11
+ /**
12
+ * Partial content block emitted.
13
+ */
14
+ export const PartialBlock = Trace.EventType('assistant.partialBlock', {
15
+ schema: Schema.Struct({
16
+ messageId: Obj.ID,
17
+ role: Actor.Role,
18
+ block: ContentBlock.Any,
19
+ }),
20
+ isEphemeral: true,
21
+ });
22
+
23
+ /**
24
+ * Complete content block emitted.
25
+ */
26
+ export const CompleteBlock = Trace.EventType('assistant.completeBlock', {
27
+ schema: Schema.Struct({
28
+ messageId: Obj.ID,
29
+ role: Actor.Role,
30
+ block: ContentBlock.Any,
31
+ }),
32
+ isEphemeral: false,
33
+ });
34
+
35
+ export const AgentRequestBegin = Trace.EventType('assistant.agentRequestBegin', {
36
+ schema: Schema.Struct({}),
37
+ isEphemeral: false,
38
+ });
39
+
40
+ export const AgentRequestEnd = Trace.EventType('assistant.agentRequestEnd', {
41
+ schema: Schema.Struct({
42
+ status: Schema.Literal('success', 'error', 'interrupted'),
43
+ error: Schema.optional(Schema.String),
44
+ }),
45
+ isEphemeral: false,
46
+ });
47
+
48
+ /**
49
+ * Emitted when an MCP server connection fails for a request turn.
50
+ * Ephemeral so that misconfigured/unreachable servers don't pollute the durable feed,
51
+ * but can still be surfaced to the user via the live ephemeral event stream.
52
+ */
53
+ export const McpServerError = Trace.EventType('assistant.mcpServerError', {
54
+ schema: Schema.Struct({
55
+ url: Schema.String,
56
+ protocol: Schema.Literal('sse', 'http'),
57
+ message: Schema.String,
58
+ }),
59
+ isEphemeral: true,
60
+ });
@@ -1,89 +0,0 @@
1
- // src/extraction/extraction-ner-function/named-entity-recognition.ts
2
- import { pipeline } from "@xenova/transformers";
3
- import { log } from "@dxos/log";
4
- var __dxlog_file = "/__w/dxos/dxos/packages/core/assistant/src/extraction/extraction-ner-function/named-entity-recognition.ts";
5
- var _ner;
6
- var getNer = () => {
7
- if (!_ner) {
8
- _ner = pipeline("ner", "Xenova/bert-base-NER").then((ner) => {
9
- log.info("NER model is ready", void 0, {
10
- F: __dxlog_file,
11
- L: 23,
12
- S: void 0,
13
- C: (f, a) => f(...a)
14
- });
15
- return ner;
16
- });
17
- }
18
- return _ner;
19
- };
20
- var extractFullEntities = async (text) => {
21
- const ner = await getNer();
22
- const entities = await ner(text);
23
- const tokenGroups = createTokenGroups(entities);
24
- const combinedEntities = tokenGroups.map(combineNerTokens);
25
- return combinedEntities;
26
- };
27
- var createTokenGroups = (tokens) => {
28
- const tokenGroups = [];
29
- const canBeCombined = (prevToken, currentToken) => {
30
- const [currentState, currentEntity] = currentToken.entity.split("-");
31
- const [prevState, prevEntity] = prevToken.entity.split("-");
32
- if (prevEntity !== currentEntity) {
33
- return false;
34
- }
35
- if (prevState === "O") {
36
- return false;
37
- }
38
- if (currentState === "I") {
39
- return true;
40
- }
41
- if ((prevState === "B" || prevState === "I") && currentState === "B") {
42
- return currentToken.word.startsWith("#");
43
- }
44
- return false;
45
- };
46
- for (const token of tokens) {
47
- if (tokenGroups.length === 0) {
48
- tokenGroups.push([
49
- token
50
- ]);
51
- continue;
52
- }
53
- const lastTokenGroup = tokenGroups.at(-1);
54
- if (canBeCombined(lastTokenGroup.at(-1), token)) {
55
- lastTokenGroup.push(token);
56
- continue;
57
- }
58
- tokenGroups.push([
59
- token
60
- ]);
61
- }
62
- return tokenGroups;
63
- };
64
- var combineNerTokens = (group) => {
65
- const combinedToken = {
66
- entity: group.at(0).entity.split("-")[1],
67
- score: group.reduce((acc, token) => acc + token.score, 0) / group.length,
68
- index: group.at(0).index,
69
- word: group.at(0).word,
70
- start: group.at(0).start,
71
- end: group.at(-1).end
72
- };
73
- for (const token of group.slice(1)) {
74
- if (token.word.startsWith("#")) {
75
- combinedToken.word += token.word.replace(/^#+/, "");
76
- } else {
77
- combinedToken.word += " " + token.word;
78
- }
79
- }
80
- return combinedToken;
81
- };
82
-
83
- export {
84
- getNer,
85
- extractFullEntities,
86
- createTokenGroups,
87
- combineNerTokens
88
- };
89
- //# sourceMappingURL=chunk-6WRGDEMH.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/extraction/extraction-ner-function/named-entity-recognition.ts"],
4
- "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport {\n type TokenClassificationOutput,\n type TokenClassificationPipelineType,\n type TokenClassificationSingle,\n pipeline,\n} from '@xenova/transformers';\n\nimport { log } from '@dxos/log';\n\nlet _ner: Promise<TokenClassificationPipelineType>;\n/**\n * Named Entity Recognition pipeline.\n * Initializes the pipeline on first call.\n * @returns The singleton promise that resolves to a token classification pipeline.\n */\nexport const getNer = () => {\n if (!_ner) {\n _ner = pipeline('ner', 'Xenova/bert-base-NER').then((ner) => {\n log.info('NER model is ready');\n return ner;\n });\n }\n return _ner;\n};\n\n/**\n * Extracts entities from text using the named entity recognition pipeline and does simple grouping of tokens.\n */\nexport const extractFullEntities = async (text: string): Promise<TokenClassificationSingle[]> => {\n const ner = await getNer();\n const entities = (await ner(text)) as TokenClassificationOutput;\n const tokenGroups = createTokenGroups(entities);\n const combinedEntities = tokenGroups.map(combineNerTokens);\n return combinedEntities;\n};\n\nexport const createTokenGroups = (tokens: TokenClassificationSingle[]): TokenClassificationSingle[][] => {\n const tokenGroups: TokenClassificationSingle[][] = [];\n\n const canBeCombined = (prevToken: TokenClassificationSingle, currentToken: TokenClassificationSingle) => {\n const [currentState, currentEntity] = currentToken.entity.split('-'); // B, I, O\n const [prevState, prevEntity] = prevToken.entity.split('-'); // B, I, O\n if (prevEntity !== currentEntity) {\n return false;\n }\n if (prevState === 'O') {\n return false;\n }\n if (currentState === 'I') {\n return true;\n }\n if ((prevState === 'B' || prevState === 'I') && currentState === 'B') {\n return currentToken.word.startsWith('#');\n }\n return false;\n };\n\n for (const token of tokens) {\n if (tokenGroups.length === 0) {\n tokenGroups.push([token]);\n continue;\n }\n const lastTokenGroup = tokenGroups.at(-1)!;\n if (canBeCombined(lastTokenGroup.at(-1)!, token)) {\n lastTokenGroup.push(token);\n continue;\n }\n tokenGroups.push([token]);\n }\n\n return tokenGroups;\n};\n\nexport const combineNerTokens = (group: TokenClassificationSingle[]): TokenClassificationSingle => {\n const combinedToken: TokenClassificationSingle = {\n entity: group.at(0)!.entity.split('-')[1],\n score: group.reduce((acc, token) => acc + token.score, 0) / group.length,\n index: group.at(0)!.index,\n word: group.at(0)!.word,\n start: group.at(0)!.start,\n end: group.at(-1)!.end,\n };\n\n for (const token of group.slice(1)) {\n if (token.word.startsWith('#')) {\n combinedToken.word += token.word.replace(/^#+/, '');\n } else {\n combinedToken.word += ' ' + token.word;\n }\n }\n\n return combinedToken;\n};\n"],
5
- "mappings": ";AAIA,SAIEA,gBACK;AAEP,SAASC,WAAW;;AAEpB,IAAIC;AAMG,IAAMC,SAAS,MAAA;AACpB,MAAI,CAACD,MAAM;AACTA,WAAOF,SAAS,OAAO,sBAAA,EAAwBI,KAAK,CAACC,QAAAA;AACnDJ,UAAIK,KAAK,sBAAA,QAAA;;;;;;AACT,aAAOD;IACT,CAAA;EACF;AACA,SAAOH;AACT;AAKO,IAAMK,sBAAsB,OAAOC,SAAAA;AACxC,QAAMH,MAAM,MAAMF,OAAAA;AAClB,QAAMM,WAAY,MAAMJ,IAAIG,IAAAA;AAC5B,QAAME,cAAcC,kBAAkBF,QAAAA;AACtC,QAAMG,mBAAmBF,YAAYG,IAAIC,gBAAAA;AACzC,SAAOF;AACT;AAEO,IAAMD,oBAAoB,CAACI,WAAAA;AAChC,QAAML,cAA6C,CAAA;AAEnD,QAAMM,gBAAgB,CAACC,WAAsCC,iBAAAA;AAC3D,UAAM,CAACC,cAAcC,aAAAA,IAAiBF,aAAaG,OAAOC,MAAM,GAAA;AAChE,UAAM,CAACC,WAAWC,UAAAA,IAAcP,UAAUI,OAAOC,MAAM,GAAA;AACvD,QAAIE,eAAeJ,eAAe;AAChC,aAAO;IACT;AACA,QAAIG,cAAc,KAAK;AACrB,aAAO;IACT;AACA,QAAIJ,iBAAiB,KAAK;AACxB,aAAO;IACT;AACA,SAAKI,cAAc,OAAOA,cAAc,QAAQJ,iBAAiB,KAAK;AACpE,aAAOD,aAAaO,KAAKC,WAAW,GAAA;IACtC;AACA,WAAO;EACT;AAEA,aAAWC,SAASZ,QAAQ;AAC1B,QAAIL,YAAYkB,WAAW,GAAG;AAC5BlB,kBAAYmB,KAAK;QAACF;OAAM;AACxB;IACF;AACA,UAAMG,iBAAiBpB,YAAYqB,GAAG,EAAC;AACvC,QAAIf,cAAcc,eAAeC,GAAG,EAAC,GAAKJ,KAAAA,GAAQ;AAChDG,qBAAeD,KAAKF,KAAAA;AACpB;IACF;AACAjB,gBAAYmB,KAAK;MAACF;KAAM;EAC1B;AAEA,SAAOjB;AACT;AAEO,IAAMI,mBAAmB,CAACkB,UAAAA;AAC/B,QAAMC,gBAA2C;IAC/CZ,QAAQW,MAAMD,GAAG,CAAA,EAAIV,OAAOC,MAAM,GAAA,EAAK,CAAA;IACvCY,OAAOF,MAAMG,OAAO,CAACC,KAAKT,UAAUS,MAAMT,MAAMO,OAAO,CAAA,IAAKF,MAAMJ;IAClES,OAAOL,MAAMD,GAAG,CAAA,EAAIM;IACpBZ,MAAMO,MAAMD,GAAG,CAAA,EAAIN;IACnBa,OAAON,MAAMD,GAAG,CAAA,EAAIO;IACpBC,KAAKP,MAAMD,GAAG,EAAC,EAAIQ;EACrB;AAEA,aAAWZ,SAASK,MAAMQ,MAAM,CAAA,GAAI;AAClC,QAAIb,MAAMF,KAAKC,WAAW,GAAA,GAAM;AAC9BO,oBAAcR,QAAQE,MAAMF,KAAKgB,QAAQ,OAAO,EAAA;IAClD,OAAO;AACLR,oBAAcR,QAAQ,MAAME,MAAMF;IACpC;EACF;AAEA,SAAOQ;AACT;",
6
- "names": ["pipeline", "log", "_ner", "getNer", "then", "ner", "info", "extractFullEntities", "text", "entities", "tokenGroups", "createTokenGroups", "combinedEntities", "map", "combineNerTokens", "tokens", "canBeCombined", "prevToken", "currentToken", "currentState", "currentEntity", "entity", "split", "prevState", "prevEntity", "word", "startsWith", "token", "length", "push", "lastTokenGroup", "at", "group", "combinedToken", "score", "reduce", "acc", "index", "start", "end", "slice", "replace"]
7
- }