@dxos/assistant 0.9.1-main.c7dcc2e112 → 0.9.1-staging.ee54ba693a

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 (70) hide show
  1. package/dist/lib/neutral/extraction/index.mjs +1 -1
  2. package/dist/lib/neutral/extraction/index.mjs.map +1 -1
  3. package/dist/lib/neutral/index.mjs +387 -230
  4. package/dist/lib/neutral/index.mjs.map +4 -4
  5. package/dist/lib/neutral/meta.json +1 -1
  6. package/dist/types/src/extraction/extraction-llm-function/proper-noun-extraction.d.ts +1 -202
  7. package/dist/types/src/extraction/extraction-llm-function/proper-noun-extraction.d.ts.map +1 -1
  8. package/dist/types/src/index.d.ts +1 -1
  9. package/dist/types/src/index.d.ts.map +1 -1
  10. package/dist/types/src/request/AiRequest.d.ts +13 -208
  11. package/dist/types/src/request/AiRequest.d.ts.map +1 -1
  12. package/dist/types/src/request/format.d.ts +1 -1
  13. package/dist/types/src/request/format.d.ts.map +1 -1
  14. package/dist/types/src/session/AiContext.d.ts +27 -105
  15. package/dist/types/src/session/AiContext.d.ts.map +1 -1
  16. package/dist/types/src/session/AiSession.d.ts +5 -29
  17. package/dist/types/src/session/AiSession.d.ts.map +1 -1
  18. package/dist/types/src/session/Harness.d.ts +122 -0
  19. package/dist/types/src/session/Harness.d.ts.map +1 -0
  20. package/dist/types/src/session/SessionLink.d.ts +8 -11
  21. package/dist/types/src/session/SessionLink.d.ts.map +1 -1
  22. package/dist/types/src/session/SessionLoader.d.ts +2 -2
  23. package/dist/types/src/session/SessionLoader.d.ts.map +1 -1
  24. package/dist/types/src/session/SkillHooks.d.ts +28 -0
  25. package/dist/types/src/session/SkillHooks.d.ts.map +1 -0
  26. package/dist/types/src/session/harness-control.d.ts +177 -0
  27. package/dist/types/src/session/harness-control.d.ts.map +1 -0
  28. package/dist/types/src/session/index.d.ts +3 -0
  29. package/dist/types/src/session/index.d.ts.map +1 -1
  30. package/dist/types/src/session/toolkit.d.ts +4 -4
  31. package/dist/types/src/session/toolkit.d.ts.map +1 -1
  32. package/dist/types/src/templates/system.d.ts +4 -6
  33. package/dist/types/src/templates/system.d.ts.map +1 -1
  34. package/dist/types/src/tool-runtime/index.d.ts.map +1 -0
  35. package/dist/types/src/tool-runtime/services.d.ts.map +1 -0
  36. package/dist/types/src/util/artifact.d.ts.map +1 -1
  37. package/dist/types/src/util/diff.d.ts +9 -3
  38. package/dist/types/src/util/diff.d.ts.map +1 -1
  39. package/dist/types/src/util/tracing.d.ts +40 -0
  40. package/dist/types/src/util/tracing.d.ts.map +1 -1
  41. package/dist/types/tsconfig.tsbuildinfo +1 -1
  42. package/package.json +28 -25
  43. package/src/extraction/extraction-llm-function/proper-noun-extraction.ts +1 -1
  44. package/src/index.ts +1 -1
  45. package/src/request/AiRequest.ts +35 -14
  46. package/src/request/format.ts +9 -11
  47. package/src/session/AiContext.test.ts +52 -32
  48. package/src/session/AiContext.ts +73 -95
  49. package/src/session/AiSession.test.ts +4 -4
  50. package/src/session/AiSession.ts +43 -83
  51. package/src/session/Harness.ts +241 -0
  52. package/src/session/SessionLink.ts +8 -8
  53. package/src/session/SessionLoader.ts +4 -4
  54. package/src/session/SkillHooks.ts +71 -0
  55. package/src/session/harness-control.ts +30 -0
  56. package/src/session/index.ts +3 -0
  57. package/src/session/toolkit.ts +8 -8
  58. package/src/templates/instructions/format.tpl +3 -3
  59. package/src/templates/instructions/system.tpl +10 -12
  60. package/src/templates/system.ts +6 -2
  61. package/src/util/artifact.ts +9 -2
  62. package/src/util/diff.test.ts +4 -4
  63. package/src/util/diff.ts +15 -8
  64. package/src/util/tracing.ts +1 -1
  65. package/dist/types/src/functions/index.d.ts.map +0 -1
  66. package/dist/types/src/functions/services.d.ts.map +0 -1
  67. /package/dist/types/src/{functions → tool-runtime}/index.d.ts +0 -0
  68. /package/dist/types/src/{functions → tool-runtime}/services.d.ts +0 -0
  69. /package/src/{functions → tool-runtime}/index.ts +0 -0
  70. /package/src/{functions → tool-runtime}/services.ts +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/assistant",
3
- "version": "0.9.1-main.c7dcc2e112",
3
+ "version": "0.9.1-staging.ee54ba693a",
4
4
  "description": "Natural language interface to DXOS",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -30,41 +30,44 @@
30
30
  "src"
31
31
  ],
32
32
  "dependencies": {
33
- "@automerge/automerge": "3.3.0-fragments.1",
33
+ "@automerge/automerge": "3.3.0-fragments.2",
34
34
  "@effect-atom/atom": "^0.5.3",
35
35
  "@effect-atom/atom-react": "^0.5.0",
36
36
  "@effect/ai": "0.36.0",
37
37
  "@effect/experimental": "0.60.0",
38
- "@effect/platform": "0.96.1",
38
+ "@effect/platform": "0.96.2",
39
+ "@effect/rpc": "0.75.1",
39
40
  "@xenova/transformers": "^2.17.2",
40
41
  "lodash.defaultsdeep": "^4.6.1",
41
- "@dxos/ai": "0.9.1-main.c7dcc2e112",
42
- "@dxos/async": "0.9.1-main.c7dcc2e112",
43
- "@dxos/compute": "0.9.1-main.c7dcc2e112",
44
- "@dxos/context": "0.9.1-main.c7dcc2e112",
45
- "@dxos/debug": "0.9.1-main.c7dcc2e112",
46
- "@dxos/echo": "0.9.1-main.c7dcc2e112",
47
- "@dxos/echo-client": "0.9.1-main.c7dcc2e112",
48
- "@dxos/errors": "0.9.1-main.c7dcc2e112",
49
- "@dxos/echo-protocol": "0.9.1-main.c7dcc2e112",
50
- "@dxos/graph": "0.9.1-main.c7dcc2e112",
51
- "@dxos/keys": "0.9.1-main.c7dcc2e112",
52
- "@dxos/functions": "0.9.1-main.c7dcc2e112",
53
- "@dxos/log": "0.9.1-main.c7dcc2e112",
54
- "@dxos/mcp-client": "0.9.1-main.c7dcc2e112",
55
- "@dxos/invariant": "0.9.1-main.c7dcc2e112",
56
- "@dxos/node-std": "0.9.1-main.c7dcc2e112",
57
- "@dxos/effect": "0.9.1-main.c7dcc2e112",
58
- "@dxos/types": "0.9.1-main.c7dcc2e112",
59
- "@dxos/schema": "0.9.1-main.c7dcc2e112",
60
- "@dxos/util": "0.9.1-main.c7dcc2e112"
42
+ "@dxos/ai": "0.9.1-staging.ee54ba693a",
43
+ "@dxos/async": "0.9.1-staging.ee54ba693a",
44
+ "@dxos/compute": "0.9.1-staging.ee54ba693a",
45
+ "@dxos/compute-runtime": "0.9.1-staging.ee54ba693a",
46
+ "@dxos/debug": "0.9.1-staging.ee54ba693a",
47
+ "@dxos/context": "0.9.1-staging.ee54ba693a",
48
+ "@dxos/echo-client": "0.9.1-staging.ee54ba693a",
49
+ "@dxos/echo-doc": "0.9.1-staging.ee54ba693a",
50
+ "@dxos/effect": "0.9.1-staging.ee54ba693a",
51
+ "@dxos/echo": "0.9.1-staging.ee54ba693a",
52
+ "@dxos/echo-protocol": "0.9.1-staging.ee54ba693a",
53
+ "@dxos/errors": "0.9.1-staging.ee54ba693a",
54
+ "@dxos/functions": "0.9.1-staging.ee54ba693a",
55
+ "@dxos/graph": "0.9.1-staging.ee54ba693a",
56
+ "@dxos/keys": "0.9.1-staging.ee54ba693a",
57
+ "@dxos/log": "0.9.1-staging.ee54ba693a",
58
+ "@dxos/invariant": "0.9.1-staging.ee54ba693a",
59
+ "@dxos/mcp-client": "0.9.1-staging.ee54ba693a",
60
+ "@dxos/node-std": "0.9.1-staging.ee54ba693a",
61
+ "@dxos/schema": "0.9.1-staging.ee54ba693a",
62
+ "@dxos/types": "0.9.1-staging.ee54ba693a",
63
+ "@dxos/util": "0.9.1-staging.ee54ba693a"
61
64
  },
62
65
  "devDependencies": {
63
66
  "@types/lodash.defaultsdeep": "^4.6.6",
64
- "effect": "3.21.3"
67
+ "effect": "3.21.4"
65
68
  },
66
69
  "peerDependencies": {
67
- "effect": "3.21.3"
70
+ "effect": "3.21.4"
68
71
  },
69
72
  "publishConfig": {
70
73
  "access": "public"
@@ -12,7 +12,7 @@ import { Message } from '@dxos/types';
12
12
 
13
13
  import { findReferences, insertReferences } from '../quotes';
14
14
 
15
- const EXTRACTION_MODEL = 'ai.claude.model.claude-haiku-4-5';
15
+ const EXTRACTION_MODEL = 'com.anthropic.model.claude-haiku-4-5.default';
16
16
 
17
17
  /**
18
18
  * Proper nouns extracted from transcript text.
package/src/index.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- export * from './functions';
5
+ export * from './tool-runtime';
6
6
  export * from './request';
7
7
  export * from './session';
8
8
  export * from './templates';
@@ -19,19 +19,19 @@ import {
19
19
  AiPreprocessor,
20
20
  AiSummarizer,
21
21
  type AiToolNotFoundError,
22
- callTool,
23
22
  type OpaqueToolkit,
24
23
  type PromptPreprocessingError,
25
24
  type ToolExecutionService,
26
25
  type ToolResolverService,
26
+ callTool,
27
27
  withoutToolCallParising,
28
28
  } from '@dxos/ai';
29
- import { type Blueprint, Trace, Operation } from '@dxos/compute';
29
+ import { Operation, type Skill, Trace } from '@dxos/compute';
30
30
  import { Database, Obj, Registry } from '@dxos/echo';
31
31
  import { log } from '@dxos/log';
32
32
  import { ContentBlock, Message } from '@dxos/types';
33
33
 
34
- import { getOperationFromTool } from '../functions/services';
34
+ import { getOperationFromTool } from '../tool-runtime/services';
35
35
  import { type AiAssistantError, CompleteBlock, PartialBlock } from '../util';
36
36
  import { formatSystemPrompt, formatUserPrompt } from './format';
37
37
  import { GenerationObserver } from './observer';
@@ -75,7 +75,7 @@ export type RunProps<R = never> = {
75
75
  system?: string;
76
76
  history?: Message.Message[];
77
77
  objects?: Obj.Unknown[];
78
- blueprints?: readonly Blueprint.Blueprint[];
78
+ skills?: readonly Skill.Skill[];
79
79
  toolkit?: OpaqueToolkit.OpaqueToolkit<R>;
80
80
  };
81
81
 
@@ -84,7 +84,7 @@ export type BeginProps = {
84
84
  system?: string;
85
85
  history?: Message.Message[];
86
86
  objects?: Obj.Unknown[];
87
- blueprints?: readonly Blueprint.Blueprint[];
87
+ skills?: readonly Skill.Skill[];
88
88
  };
89
89
 
90
90
  export type TurnProps<R = never> = {
@@ -95,6 +95,12 @@ export type TurnProps<R = never> = {
95
95
  export type TurnResult = {
96
96
  messages: Message.Message[];
97
97
  done: boolean;
98
+ /**
99
+ * Provider finish reason for this turn. `pause` means the provider paused a server-tool turn
100
+ * mid-execution (e.g. Anthropic `pause_turn`) and the turn must be resumed by issuing another
101
+ * request without mutating the trailing assistant content.
102
+ */
103
+ finishReason?: ContentBlock.FinishReason;
98
104
  };
99
105
 
100
106
  /**
@@ -183,7 +189,7 @@ export class Request {
183
189
  prompt,
184
190
  system,
185
191
  history = [],
186
- blueprints = [],
192
+ skills = [],
187
193
  objects = [],
188
194
  }: BeginProps): Effect.Effect<void, RunError, RunRequirements> =>
189
195
  Effect.gen(this, function* () {
@@ -191,7 +197,7 @@ export class Request {
191
197
  this._history = [...history];
192
198
  this._pending = [];
193
199
 
194
- const systemPrompt = yield* formatSystemPrompt({ system, blueprints, objects }).pipe(Effect.orDie);
200
+ const systemPrompt = yield* formatSystemPrompt({ system, skills, objects }).pipe(Effect.orDie);
195
201
 
196
202
  if (this._options.summarizationThreshold !== undefined) {
197
203
  const tokenCount = yield* AiPreprocessor.estimateTokens(
@@ -210,7 +216,7 @@ export class Request {
210
216
 
211
217
  /**
212
218
  * Execute a single turn: one LLM generation followed by tool execution.
213
- * The toolkit and system prompt can be updated between turns to reflect context changes (e.g. dynamically enabled blueprints).
219
+ * The toolkit and system prompt can be updated between turns to reflect context changes (e.g. dynamically enabled skills).
214
220
  */
215
221
  runAgentTurn = <const R = never>({
216
222
  system,
@@ -232,6 +238,7 @@ export class Request {
232
238
 
233
239
  const observer = this._observer;
234
240
  let currentMessageId: Obj.ID | null = null;
241
+ let finishReason: ContentBlock.FinishReason | undefined;
235
242
 
236
243
  const messages = yield* LanguageModel.streamText({
237
244
  prompt,
@@ -250,6 +257,9 @@ export class Request {
250
257
  Stream.mapEffect(
251
258
  (block) =>
252
259
  Effect.gen(this, function* () {
260
+ if (block._tag === 'stats' && block.finishReason !== undefined) {
261
+ finishReason = block.finishReason;
262
+ }
253
263
  if (block.pending) {
254
264
  currentMessageId ??= Obj.ID.random();
255
265
  log('emit ephemeral message', { id: currentMessageId, type: block._tag });
@@ -281,16 +291,23 @@ export class Request {
281
291
  );
282
292
  log('messages', { messages });
283
293
 
294
+ // A paused server-tool turn (e.g. Anthropic `pause_turn`) is not complete: the provider
295
+ // expects the assistant content to be resent so it can finish executing the server tool.
296
+ // No local tool execution is needed — just another request.
297
+ if (finishReason === 'pause') {
298
+ return { messages, done: false, finishReason };
299
+ }
300
+
284
301
  const toolCalls = this.getToolCalls();
285
302
 
286
303
  if (toolCalls.length === 0) {
287
304
  this._ended = Date.now();
288
- return { messages, done: true };
305
+ return { messages, done: true, finishReason };
289
306
  } else if (!toolkit) {
290
307
  throw new Error('No toolkit provided');
291
308
  }
292
309
 
293
- return { messages, done: false };
310
+ return { messages, done: false, finishReason };
294
311
  }).pipe(Effect.withSpan('AiRequest.runAgentTurn'));
295
312
 
296
313
  runTools = <const R = never>({
@@ -327,19 +344,23 @@ export class Request {
327
344
  system: systemTemplate,
328
345
  history = [],
329
346
  objects = [],
330
- blueprints = [],
347
+ skills = [],
331
348
  toolkit,
332
349
  }: RunProps<R>): Effect.Effect<Message.Message[], RunError, RunRequirements | R> =>
333
350
  Effect.gen(this, function* () {
334
- yield* this.begin({ prompt, system: systemTemplate, history, objects, blueprints });
351
+ yield* this.begin({ prompt, system: systemTemplate, history, objects, skills });
335
352
 
336
- const system = yield* formatSystemPrompt({ system: systemTemplate, blueprints, objects }).pipe(Effect.orDie);
353
+ const system = yield* formatSystemPrompt({ system: systemTemplate, skills, objects }).pipe(Effect.orDie);
337
354
 
338
355
  do {
339
- const { done } = yield* this.runAgentTurn({ system, toolkit });
356
+ const { done, finishReason } = yield* this.runAgentTurn({ system, toolkit });
340
357
  if (done) {
341
358
  break;
342
359
  }
360
+ // A paused server-tool turn resumes with another request and no local tool execution.
361
+ if (finishReason === 'pause') {
362
+ continue;
363
+ }
343
364
  yield* this.runTools({ toolkit });
344
365
  } while (true);
345
366
 
@@ -25,31 +25,29 @@ import { ArtifactDiffResolver } from './artifact-diff';
25
25
  // TODO(burdon): Move to AiPreprocessor.
26
26
  export const formatSystemPrompt = ({
27
27
  system,
28
- blueprints = [],
28
+ skills = [],
29
29
  objects = [],
30
- }: Pick<AiRequest.RunProps, 'system' | 'blueprints' | 'objects'>): Effect.Effect<
30
+ }: Pick<AiRequest.RunProps, 'system' | 'skills' | 'objects'>): Effect.Effect<
31
31
  string,
32
32
  FunctionNotFoundError | EntityNotFoundError,
33
33
  Database.Service | Registry.Service | Operation.Service
34
34
  > =>
35
35
  Effect.gen(function* () {
36
- const blueprintDefs = yield* Function.pipe(
37
- blueprints,
38
- Effect.forEach((blueprint) => Effect.succeed(blueprint.instructions)),
36
+ const skillDefs = yield* Function.pipe(
37
+ skills,
38
+ Effect.forEach((skill) => Effect.succeed(skill.instructions)),
39
39
  Effect.flatMap(
40
40
  Effect.forEach((template) =>
41
41
  Effect.gen(function* () {
42
42
  return trim`
43
- <blueprint>
43
+ <skill>
44
44
  ${yield* Template.processTemplate(template)}
45
- </blueprint>
45
+ </skill>
46
46
  `;
47
47
  }),
48
48
  ),
49
49
  ),
50
- Effect.map((blueprints) =>
51
- blueprints.length > 0 ? ['## Blueprints Definitions', ...blueprints].join('\n\n') : undefined,
52
- ),
50
+ Effect.map((skills) => (skills.length > 0 ? ['## Skills Definitions', ...skills].join('\n\n') : undefined)),
53
51
  );
54
52
 
55
53
  const objectDefs = yield* Function.pipe(
@@ -66,7 +64,7 @@ export const formatSystemPrompt = ({
66
64
  );
67
65
 
68
66
  return yield* Function.pipe(
69
- Effect.succeed([system, blueprintDefs, objectDefs].filter((def): def is string => def !== undefined)),
67
+ Effect.succeed([system, skillDefs, objectDefs].filter((def): def is string => def !== undefined)),
70
68
  Effect.map((parts) => parts.join('\n\n')),
71
69
  );
72
70
  }).pipe(Effect.withSpan('formatSystemPrompt'));
@@ -2,48 +2,68 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import * as Context from 'effect/Context';
6
5
  import * as Effect from 'effect/Effect';
7
- import * as Layer from 'effect/Layer';
8
- import * as Runtime from 'effect/Runtime';
9
6
  import * as Schema from 'effect/Schema';
10
- import { describe, it } from 'vitest';
7
+ import { describe, test } from 'vitest';
11
8
 
12
- import { DXN, Feed, Obj, Ref, Type } from '@dxos/echo';
9
+ import { Database, DXN, Feed, Obj, Ref, Type } from '@dxos/echo';
10
+ import { TestDatabaseLayer } from '@dxos/echo-client/testing';
13
11
 
14
12
  import * as AiContext from './AiContext';
15
13
 
16
- const createMockFeedRuntime = (): Runtime.Runtime<Feed.FeedService> => {
17
- const mockFeedService: Context.Tag.Service<Feed.FeedService> = {
18
- append: async () => {},
19
- remove: async () => {},
20
- query: () =>
21
- ({
22
- subscribe: () => () => {},
23
- results: [],
24
- run: async () => [],
25
- }) as any,
26
- sync: async () => {},
27
- getSyncState: async () => ({ blocksToPull: 0, blocksToPush: 0, totalBlocks: 0 }),
28
- };
29
- const layer = Layer.succeed(Feed.FeedService, mockFeedService);
30
- return Effect.runSync(Effect.runtime<Feed.FeedService>().pipe(Effect.provide(layer)));
31
- };
14
+ const TypeA = Type.makeObject(DXN.make('org.dxos.type.a', '0.1.0'))(Schema.Struct({}));
15
+ const TypeB = Type.makeObject(DXN.make('org.dxos.type.b', '0.1.0'))(Schema.Struct({}));
32
16
 
33
17
  describe('AiContext.Binder', () => {
34
- it('should handle bind with Ref', async () => {
35
- const feed = Feed.make();
36
- const runtime = createMockFeedRuntime();
37
- const binder = new AiContext.Binder({ feed, runtime });
18
+ const TestLayer = TestDatabaseLayer({ types: [Feed.Feed, TypeA, TypeB] });
38
19
 
39
- const TestSchema = Schema.Struct({}).pipe(Type.makeObject(DXN.make('org.dxos.type.example', '0.1.0')));
20
+ test('reopened binder resolves all distinct bound objects', async ({ expect }) => {
21
+ await Effect.gen(function* () {
22
+ const feed = yield* Database.add(Feed.make());
23
+ const runtime = yield* Effect.runtime<Database.Service>();
40
24
 
41
- const obj = Obj.make(TestSchema, {});
42
- const ref = Ref.make(obj);
25
+ const a = yield* Database.add(Obj.make(TypeA, {}));
26
+ const b = yield* Database.add(Obj.make(TypeB, {}));
43
27
 
44
- await binder.bind({
45
- blueprints: [],
46
- objects: [ref],
47
- });
28
+ // Bind two distinct objects across two separate bindings (as the chat + companion do).
29
+ const writer = new AiContext.Binder({ feed, runtime });
30
+ yield* Effect.promise(() => writer.open());
31
+ yield* Effect.promise(() => writer.bind({ objects: [Ref.make(a)] }));
32
+ yield* Effect.promise(() => writer.bind({ objects: [Ref.make(b)] }));
33
+ yield* Effect.promise(() => writer.close());
34
+
35
+ // Reopen over the same feed (the path ContextModule takes): bindings are re-read via _reduce.
36
+ const reader = new AiContext.Binder({ feed, runtime });
37
+ yield* Effect.promise(() => reader.open());
38
+ const objects = reader.getObjects();
39
+ yield* Effect.promise(() => reader.close());
40
+
41
+ expect(objects.map((obj) => Obj.getURI(obj)).sort()).toEqual([Obj.getURI(a), Obj.getURI(b)].sort());
42
+ })
43
+ .pipe(Effect.provide(TestLayer))
44
+ .pipe(Effect.runPromise);
45
+ });
46
+
47
+ test('should handle bind with Ref', async () => {
48
+ await Effect.gen(function* () {
49
+ const feed = yield* Database.add(Feed.make());
50
+ const runtime = yield* Effect.runtime<Database.Service>();
51
+
52
+ const TestSchema = Type.makeObject(DXN.make('org.dxos.type.example', '0.1.0'))(Schema.Struct({}));
53
+
54
+ const obj = Obj.make(TestSchema, {});
55
+ const ref = Ref.make(obj);
56
+
57
+ const binder = new AiContext.Binder({ feed, runtime });
58
+
59
+ yield* Effect.promise(() =>
60
+ binder.bind({
61
+ skills: [],
62
+ objects: [ref],
63
+ }),
64
+ );
65
+ })
66
+ .pipe(Effect.provide(TestLayer))
67
+ .pipe(Effect.runPromise);
48
68
  });
49
69
  });