@dxos/assistant 0.8.4-main.e8ec1fe → 0.8.4-main.ef1bc66f44
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.
- package/dist/lib/neutral/chunk-ZPC54VRM.mjs +596 -0
- package/dist/lib/neutral/chunk-ZPC54VRM.mjs.map +7 -0
- package/dist/lib/{browser → neutral}/extraction/index.mjs +5 -5
- package/dist/lib/neutral/extraction/index.mjs.map +7 -0
- package/dist/lib/{browser → neutral}/index.mjs +320 -681
- package/dist/lib/neutral/index.mjs.map +7 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/lib/neutral/testing/index.mjs +38 -0
- package/dist/lib/neutral/testing/index.mjs.map +7 -0
- package/dist/types/src/conversation/context.d.ts +97 -62
- package/dist/types/src/conversation/context.d.ts.map +1 -1
- package/dist/types/src/conversation/context.test.d.ts +2 -0
- package/dist/types/src/conversation/context.test.d.ts.map +1 -0
- package/dist/types/src/conversation/conversation.d.ts +40 -15
- package/dist/types/src/conversation/conversation.d.ts.map +1 -1
- package/dist/types/src/conversation/conversation.test.d.ts +2 -0
- package/dist/types/src/conversation/conversation.test.d.ts.map +1 -0
- package/dist/types/src/diff.d.ts +3 -1
- package/dist/types/src/diff.d.ts.map +1 -1
- package/dist/types/src/errors.d.ts +12 -16
- package/dist/types/src/errors.d.ts.map +1 -1
- package/dist/types/src/execution-graph.d.ts +2 -2
- package/dist/types/src/execution-graph.d.ts.map +1 -1
- package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts +247 -245
- package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts.map +1 -1
- package/dist/types/src/extraction/extraction.d.ts +342 -308
- package/dist/types/src/extraction/extraction.d.ts.map +1 -1
- package/dist/types/src/extraction/quotes.d.ts +2 -2
- package/dist/types/src/extraction/quotes.d.ts.map +1 -1
- package/dist/types/src/functions/services.d.ts +6 -7
- package/dist/types/src/functions/services.d.ts.map +1 -1
- package/dist/types/src/functions.test.d.ts +2 -0
- package/dist/types/src/functions.test.d.ts.map +1 -0
- package/dist/types/src/session/GenericToolkit.d.ts +23 -0
- package/dist/types/src/session/GenericToolkit.d.ts.map +1 -1
- package/dist/types/src/session/artifact-diff.d.ts +1 -1
- package/dist/types/src/session/artifact-diff.d.ts.map +1 -1
- package/dist/types/src/session/format.d.ts +3 -3
- package/dist/types/src/session/format.d.ts.map +1 -1
- package/dist/types/src/session/index.d.ts +1 -0
- package/dist/types/src/session/index.d.ts.map +1 -1
- package/dist/types/src/session/observer.d.ts +4 -3
- package/dist/types/src/session/observer.d.ts.map +1 -1
- package/dist/types/src/session/session.d.ts +14 -9
- package/dist/types/src/session/session.d.ts.map +1 -1
- package/dist/types/src/session/toolkit.d.ts +5 -6
- package/dist/types/src/session/toolkit.d.ts.map +1 -1
- package/dist/types/src/session/version-pin.d.ts +2 -2
- package/dist/types/src/session/version-pin.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +2 -0
- package/dist/types/src/testing/index.d.ts.map +1 -0
- package/dist/types/src/testing/layer.d.ts +22 -0
- package/dist/types/src/testing/layer.d.ts.map +1 -0
- package/dist/types/src/types/artifact.d.ts +13 -5
- package/dist/types/src/types/artifact.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +40 -33
- package/src/conversation/context.test.ts +46 -0
- package/src/conversation/context.ts +211 -67
- package/src/conversation/conversation.test.ts +65 -0
- package/src/conversation/conversation.ts +123 -48
- package/src/diff.test.ts +35 -4
- package/src/diff.ts +13 -4
- package/src/errors.ts +2 -2
- package/src/execution-graph.test.ts +1 -1
- package/src/execution-graph.ts +4 -4
- package/src/extraction/extraction-ner-function/extraction-ner-function.test.ts +7 -7
- package/src/extraction/extraction-ner-function/extraction-ner-function.ts +1 -1
- package/src/extraction/extraction.ts +4 -4
- package/src/extraction/quotes.ts +4 -5
- package/src/functions/services.ts +55 -30
- package/src/functions.conversations.json +1 -0
- package/src/functions.test.ts +74 -0
- package/src/session/GenericToolkit.ts +30 -0
- package/src/session/artifact-diff.ts +1 -1
- package/src/session/format.test.ts +101 -38
- package/src/session/format.ts +12 -13
- package/src/session/index.ts +1 -0
- package/src/session/observer.ts +3 -1
- package/src/session/session.conversations.json +1 -1
- package/src/session/session.test.ts +26 -13
- package/src/session/session.ts +36 -14
- package/src/session/toolkit.ts +13 -22
- package/src/session/version-pin.ts +4 -3
- package/src/templates/instructions/format.tpl +0 -4
- package/src/testing/index.ts +5 -0
- package/src/testing/layer.ts +84 -0
- package/src/types/artifact.ts +31 -13
- package/dist/lib/browser/extraction/index.mjs.map +0 -7
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +0 -11
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +0 -7
- package/dist/lib/node-esm/extraction/index.mjs +0 -226
- package/dist/lib/node-esm/extraction/index.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -1291
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- /package/dist/lib/{browser → neutral}/chunk-J5LGTIGS.mjs +0 -0
- /package/dist/lib/{browser → neutral}/chunk-J5LGTIGS.mjs.map +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"conversations":[{"parameters":{"model":"@anthropic/claude-opus-4-0","stream":true,"tools":[{"name":"read-name","description":"Reads the name of an organization.","inputSchema":{"type":"object","required":["org"],"properties":{"org":{"type":"string","description":"The ID of the referenced object. Formats accepted:\n- DXN (dxn:echo:@:01KG7R1ZXWFMWQ4DA1Q6TN1DG4). DXNs can be prepended with an @ symbol for compatibility with in-text references.\n- space ID, object ID tuple (spaceID:objectID)\n- Only object ID that is assumed to be in the current space (01KG7R1ZXWFMWQ4DA1Q6TN1DG4)","examples":["dxn:echo:@:01KG7R1ZXWFMWQ4DA1Q6TN1DG4","@dxn:echo:@:01KG7R1ZXWFMWQ4DA1Q6TN1DG4","BM3FSHFOMJCHCG5QW7JTVKGYABD2GAA7G:01KG7R1ZXWFMWQ4DA1Q6TN1DG4","01KG7R1ZXWFMWQ4DA1Q6TN1DG4"]}},"additionalProperties":false}}]},"prompt":{"content":[{"role":"user","content":"What is the name of the organization? 01JGFJJZ00G0WKQSJGMAKCNT89","options":{"anthropic":{"cacheControl":{"ttl":"5m","type":"ephemeral"}}}}]},"response":[{"type":"response-metadata","id":"msg_01FqHQGxFVdQKeMXjodHavsF","modelId":"claude-opus-4-20250514","timestamp":"1970-01-01T00:00:00.000Z","metadata":{}},{"type":"reasoning-start","id":"0","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"The user is asking for the name of","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" an organization an","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"d has provided what","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" appears to be an","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" object","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" ID: 01JGFJ","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"JZ00G0WK","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"QSJGMAKCNT89","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"\n\nI","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" need to use the read-name function","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" to get the name of this organization.","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" According","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" to the function description, I can","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" pass","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" just","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" the object","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" ID if","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" it's assume","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"d to be in the current space.","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"\n\nLet me call","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" the function with this","metadata":{}},{"type":"reasoning-delta","id":"0","delta":" ID.","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"","metadata":{}},{"type":"reasoning-delta","id":"0","delta":"","metadata":{"anthropic":{"type":"thinking","signature":"EokECkYICxgCKkDkOVtqWk3+YJ1nk31yy/hYUygSTbpQxoD7UKl2RqwyS+tJSV2rou35JEFIl30ogJZiohCBXqY0IZ3YO1SwhWq1EgztHHPI5rGjH4gehN8aDBh3BbEfM6OCraoAQiIwDSGtzFCbT7K+yTBtmtri6uuGvPwNGmRshKURPnFRCjdAf0gj1Jwge4pmIYnlGpRGKvACF4kjtsTHsn8f7ktuuzSEpVNaC6d5VYA6/Fm5ZFaiQPn0/F4fQXy1PNEyo4007gP21Ate8+98CCtlfkOnEE53hElq58doXrVOzpL+uH5b6PBPtM9f1+L9cKjhTPV6djIcewwHTTSJDTM6fr9c82f9u5EDvzNe1QODqlqCiVtNsjWCYOWNZUqILdl0TQ43Hzjf2T+WN6ARHfd3mGVsAtg8vcBM8D4mPvThsTnoswYIeB6Y5aDAA+Xu32jGRmJGclevuy25lJFZG8lAhOXJOdiP88zTG5XCN5ED3GLo2rjKBnQzwGpzg1M0ARKkrNzuLbNZ31uk36ayo+1T381Ld0yIQAX/ZUrLNZ8ovJ1sIHW18hmnyec69+4qWuy//NBWlAfyFOQnQfXM1f2XO5AFBrSILGtHxWM1+KINm1Xh68gHZpjjpyM5g8zl61nDLGxNq3OBugM7NSghygmGPmy2DlxU147cVzOHh7ZXh8fFxBfZlW0YAQ=="}}},{"type":"reasoning-end","id":"0","metadata":{}},{"type":"text-start","id":"1","metadata":{}},{"type":"text-delta","id":"1","delta":"I","metadata":{}},{"type":"text-delta","id":"1","delta":"'ll look","metadata":{}},{"type":"text-delta","id":"1","delta":" up the name of that","metadata":{}},{"type":"text-delta","id":"1","delta":" organization for you.","metadata":{}},{"type":"text-end","id":"1","metadata":{}},{"type":"tool-params-start","id":"toolu_01DdHbHNejZJC4CEjngmNLCf","name":"read-name","providerExecuted":false,"metadata":{}},{"type":"tool-params-delta","id":"toolu_01DdHbHNejZJC4CEjngmNLCf","delta":"","metadata":{}},{"type":"tool-params-delta","id":"toolu_01DdHbHNejZJC4CEjngmNLCf","delta":"{\"or","metadata":{}},{"type":"tool-params-delta","id":"toolu_01DdHbHNejZJC4CEjngmNLCf","delta":"g\": \"01JGFJJ","metadata":{}},{"type":"tool-params-delta","id":"toolu_01DdHbHNejZJC4CEjngmNLCf","delta":"Z00G0WKQ","metadata":{}},{"type":"tool-params-delta","id":"toolu_01DdHbHNejZJC4CEjngmNLCf","delta":"SJGM","metadata":{}},{"type":"tool-params-delta","id":"toolu_01DdHbHNejZJC4CEjngmNLCf","delta":"AKCNT89\"}","metadata":{}},{"type":"tool-params-end","id":"toolu_01DdHbHNejZJC4CEjngmNLCf","metadata":{}},{"type":"tool-call","id":"toolu_01DdHbHNejZJC4CEjngmNLCf","name":"read-name","providerExecuted":false,"metadata":{},"params":{"org":"dxn:echo:@:01JGFJJZ00G0WKQSJGMAKCNT89"}},{"type":"finish","reason":"tool-calls","usage":{"inputTokens":729,"outputTokens":187,"totalTokens":916},"metadata":{"anthropic":{"usage":{"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"input_tokens":729,"output_tokens":8,"server_tool_use":null,"service_tier":"standard"}}}}]},{"parameters":{"model":"@anthropic/claude-opus-4-0","stream":true,"tools":[{"name":"read-name","description":"Reads the name of an organization.","inputSchema":{"type":"object","required":["org"],"properties":{"org":{"type":"string","description":"The ID of the referenced object. Formats accepted:\n- DXN (dxn:echo:@:01KG7R1ZXWFMWQ4DA1Q6TN1DG4). DXNs can be prepended with an @ symbol for compatibility with in-text references.\n- space ID, object ID tuple (spaceID:objectID)\n- Only object ID that is assumed to be in the current space (01KG7R1ZXWFMWQ4DA1Q6TN1DG4)","examples":["dxn:echo:@:01KG7R1ZXWFMWQ4DA1Q6TN1DG4","@dxn:echo:@:01KG7R1ZXWFMWQ4DA1Q6TN1DG4","BM3FSHFOMJCHCG5QW7JTVKGYABD2GAA7G:01KG7R1ZXWFMWQ4DA1Q6TN1DG4","01KG7R1ZXWFMWQ4DA1Q6TN1DG4"]}},"additionalProperties":false}}]},"prompt":{"content":[{"role":"user","content":"What is the name of the organization? 01JGFJJZ00G0WKQSJGMAKCNT89","options":{}},{"role":"assistant","content":[{"type":"reasoning","text":"The user is asking for the name of an organization and has provided what appears to be an object ID: 01JGFJJZ00G0WKQSJGMAKCNT89\n\nI need to use the read-name function to get the name of this organization. According to the function description, I can pass just the object ID if it's assumed to be in the current space.\n\nLet me call the function with this ID.","options":{}},{"type":"text","text":"I'll look up the name of that organization for you.","options":{}},{"type":"tool-call","id":"toolu_01DdHbHNejZJC4CEjngmNLCf","name":"read-name","params":{"org":"01JGFJJZ00G0WKQSJGMAKCNT89"},"providerExecuted":false,"options":{}}],"options":{}},{"role":"tool","content":[{"type":"tool-result","id":"toolu_01DdHbHNejZJC4CEjngmNLCf","name":"read-name","isFailure":false,"result":"BlueYard","providerExecuted":false,"options":{}}],"options":{"anthropic":{"cacheControl":{"ttl":"5m","type":"ephemeral"}}}}]},"response":[{"type":"response-metadata","id":"msg_01X5xvtDymPG7tTUMLZz3eAD","modelId":"claude-opus-4-20250514","timestamp":"1970-01-01T00:00:00.000Z","metadata":{}},{"type":"text-start","id":"0","metadata":{}},{"type":"text-delta","id":"0","delta":"The name of the organization with","metadata":{}},{"type":"text-delta","id":"0","delta":" ID 01JGFJJ","metadata":{}},{"type":"text-delta","id":"0","delta":"Z00G0WKQ","metadata":{}},{"type":"text-delta","id":"0","delta":"SJGMAKCNT89 is","metadata":{}},{"type":"text-delta","id":"0","delta":" **BlueYard**.","metadata":{}},{"type":"text-end","id":"0","metadata":{}},{"type":"finish","reason":"stop","usage":{"inputTokens":801,"outputTokens":39,"totalTokens":840},"metadata":{"anthropic":{"usage":{"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"input_tokens":801,"output_tokens":6,"server_tool_use":null,"service_tier":"standard"}}}}]}]}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { describe, it } from '@effect/vitest';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as Schema from 'effect/Schema';
|
|
8
|
+
|
|
9
|
+
import { ConsolePrinter } from '@dxos/ai';
|
|
10
|
+
import { MemoizedAiService } from '@dxos/ai/testing';
|
|
11
|
+
import { AiSession, GenerationObserver, createToolkit } from '@dxos/assistant';
|
|
12
|
+
import { Blueprint } from '@dxos/blueprints';
|
|
13
|
+
import { Database, Obj, Type } from '@dxos/echo';
|
|
14
|
+
import { TestHelpers } from '@dxos/effect/testing';
|
|
15
|
+
import { defineFunction } from '@dxos/functions';
|
|
16
|
+
import { ObjectId } from '@dxos/keys';
|
|
17
|
+
import { Organization } from '@dxos/types';
|
|
18
|
+
|
|
19
|
+
import { AssistantTestLayer } from './testing';
|
|
20
|
+
|
|
21
|
+
ObjectId.dangerouslyDisableRandomness();
|
|
22
|
+
|
|
23
|
+
const readName = defineFunction({
|
|
24
|
+
key: 'dxos.org/function/read-name',
|
|
25
|
+
name: 'Read Name',
|
|
26
|
+
description: 'Reads the name of an organization.',
|
|
27
|
+
inputSchema: Schema.Struct({
|
|
28
|
+
org: Type.Ref(Organization.Organization),
|
|
29
|
+
}),
|
|
30
|
+
outputSchema: Schema.String,
|
|
31
|
+
handler: Effect.fnUntraced(function* ({ data }) {
|
|
32
|
+
const org = yield* Database.load(data.org);
|
|
33
|
+
return org.name ?? '<no org>';
|
|
34
|
+
}),
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const blueprint = Blueprint.make({
|
|
38
|
+
key: 'dxos.org/blueprint/test',
|
|
39
|
+
name: 'Test blueprint',
|
|
40
|
+
tools: Blueprint.toolDefinitions({ functions: [readName] }),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const TestLayer = AssistantTestLayer({
|
|
44
|
+
aiServicePreset: 'edge-remote',
|
|
45
|
+
functions: [readName],
|
|
46
|
+
types: [Organization.Organization],
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('Research', () => {
|
|
50
|
+
it.effect(
|
|
51
|
+
'call a function with a ref input',
|
|
52
|
+
Effect.fnUntraced(
|
|
53
|
+
function* (_) {
|
|
54
|
+
const org = yield* Database.add(
|
|
55
|
+
Obj.make(Organization.Organization, {
|
|
56
|
+
name: 'BlueYard',
|
|
57
|
+
website: 'https://blueyard.com',
|
|
58
|
+
}),
|
|
59
|
+
);
|
|
60
|
+
yield* Database.flush({ indexes: true });
|
|
61
|
+
yield* new AiSession().run({
|
|
62
|
+
prompt: `What is the name of the organization? ${org.id}`,
|
|
63
|
+
toolkit: yield* createToolkit({
|
|
64
|
+
blueprints: [blueprint],
|
|
65
|
+
}),
|
|
66
|
+
observer: GenerationObserver.fromPrinter(new ConsolePrinter()),
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
Effect.provide(TestLayer),
|
|
70
|
+
TestHelpers.provideTestContext,
|
|
71
|
+
),
|
|
72
|
+
MemoizedAiService.isGenerationEnabled() ? 240_000 : 30_000,
|
|
73
|
+
);
|
|
74
|
+
});
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import type * as Tool from '@effect/ai/Tool';
|
|
6
6
|
import * as Toolkit from '@effect/ai/Toolkit';
|
|
7
|
+
import * as Context from 'effect/Context';
|
|
7
8
|
import * as Effect from 'effect/Effect';
|
|
8
9
|
import * as Layer from 'effect/Layer';
|
|
9
10
|
import * as Pipeable from 'effect/Pipeable';
|
|
@@ -83,6 +84,11 @@ export const make = <Tools extends Record<string, Tool.Any>, E, R>(
|
|
|
83
84
|
};
|
|
84
85
|
};
|
|
85
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Empty generic toolkit.
|
|
89
|
+
*/
|
|
90
|
+
export const empty = make(Toolkit.empty, Layer.empty);
|
|
91
|
+
|
|
86
92
|
/**
|
|
87
93
|
* Merges multiple portable toolkits into a single portable toolkit.
|
|
88
94
|
*/
|
|
@@ -113,6 +119,7 @@ export type GenericTools<R = never> = Record<
|
|
|
113
119
|
readonly parameters: AnyStructSchemaNoContext;
|
|
114
120
|
readonly success: Schema.Schema.AnyNoContext;
|
|
115
121
|
readonly failure: typeof Schema.Never;
|
|
122
|
+
readonly failureMode: Tool.FailureMode;
|
|
116
123
|
},
|
|
117
124
|
R
|
|
118
125
|
>
|
|
@@ -128,3 +135,26 @@ export interface AnyStructSchemaNoContext extends Pipeable.Pipeable {
|
|
|
128
135
|
readonly fields: Schema.Struct.Fields;
|
|
129
136
|
readonly annotations: any;
|
|
130
137
|
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Provides a generic toolkit to the agent.
|
|
141
|
+
*/
|
|
142
|
+
export class Provider extends Context.Tag('@dxos/assistant/GenericToolkit.Provider')<
|
|
143
|
+
Provider,
|
|
144
|
+
{
|
|
145
|
+
readonly getToolkit: () => GenericToolkit;
|
|
146
|
+
}
|
|
147
|
+
>() {}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Layer for providing a generic toolkit to the agent.
|
|
151
|
+
*/
|
|
152
|
+
export const providerLayer = (toolkit: GenericToolkit) =>
|
|
153
|
+
Layer.succeed(Provider, {
|
|
154
|
+
getToolkit: () => toolkit,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Layer for providing an empty generic toolkit to the agent.
|
|
159
|
+
*/
|
|
160
|
+
export const providerEmpty = providerLayer(empty);
|
|
@@ -2,60 +2,123 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { describe, expect, it } from '@effect/vitest';
|
|
6
6
|
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as Schema from 'effect/Schema';
|
|
7
8
|
|
|
8
9
|
import { Blueprint, Template } from '@dxos/blueprints';
|
|
9
|
-
import { Obj } from '@dxos/echo';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import { Database, Obj, Query } from '@dxos/echo';
|
|
11
|
+
import { TestHelpers } from '@dxos/effect/testing';
|
|
12
|
+
import { defineFunction } from '@dxos/functions';
|
|
12
13
|
import { Text } from '@dxos/schema';
|
|
13
14
|
import { Organization } from '@dxos/types';
|
|
14
15
|
import { trim } from '@dxos/util';
|
|
15
16
|
|
|
16
17
|
import { createSystemPrompt } from '../templates/system';
|
|
18
|
+
import { AssistantTestLayer } from '../testing';
|
|
17
19
|
|
|
18
20
|
import { formatSystemPrompt } from './format';
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
const organizationListFunction = defineFunction({
|
|
23
|
+
key: 'dxos.org/function/organization-list',
|
|
24
|
+
name: 'Organization List',
|
|
25
|
+
description: 'List organizations',
|
|
26
|
+
inputSchema: Schema.Struct({}),
|
|
27
|
+
outputSchema: Schema.Array(Schema.String),
|
|
28
|
+
handler: Effect.fnUntraced(function* () {
|
|
29
|
+
const organizations = yield* Database.runQuery(Query.type(Organization.Organization));
|
|
30
|
+
return organizations.map((organization) => organization.name);
|
|
31
|
+
}),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const TestLayer = AssistantTestLayer({
|
|
35
|
+
types: [Text.Text, Organization.Organization, Blueprint.Blueprint],
|
|
36
|
+
functions: [organizationListFunction],
|
|
37
|
+
});
|
|
28
38
|
|
|
39
|
+
describe('format', () => {
|
|
29
40
|
it.effect(
|
|
30
41
|
'should format',
|
|
31
|
-
Effect.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
Effect.fnUntraced(
|
|
43
|
+
function* (_) {
|
|
44
|
+
const { db } = yield* Database.Service;
|
|
45
|
+
const object = db.add(
|
|
46
|
+
Obj.make(Organization.Organization, {
|
|
47
|
+
name: 'Test',
|
|
48
|
+
website: 'https://www.test.com',
|
|
49
|
+
}),
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const blueprint = db.add(
|
|
53
|
+
Blueprint.make({
|
|
54
|
+
key: 'example.com/blueprint/test',
|
|
55
|
+
name: 'Test',
|
|
56
|
+
instructions: Template.make({
|
|
57
|
+
source: trim`
|
|
58
|
+
Test
|
|
59
|
+
This is the test blueprint.
|
|
60
|
+
`,
|
|
61
|
+
}),
|
|
62
|
+
}),
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const output = yield* formatSystemPrompt({
|
|
66
|
+
system: createSystemPrompt({}),
|
|
67
|
+
blueprints: [blueprint],
|
|
68
|
+
objects: [object],
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
console.log(output);
|
|
72
|
+
},
|
|
73
|
+
Effect.provide(TestLayer),
|
|
74
|
+
TestHelpers.provideTestContext,
|
|
75
|
+
),
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
it.effect(
|
|
79
|
+
'should format with function input',
|
|
80
|
+
Effect.fnUntraced(
|
|
81
|
+
function* (_) {
|
|
82
|
+
const { db } = yield* Database.Service;
|
|
83
|
+
const object = db.add(
|
|
84
|
+
Obj.make(Organization.Organization, {
|
|
85
|
+
name: 'Test Org',
|
|
86
|
+
website: 'https://www.test.com',
|
|
87
|
+
}),
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const blueprint = db.add(
|
|
91
|
+
Blueprint.make({
|
|
92
|
+
key: 'example.com/blueprint/test',
|
|
93
|
+
name: 'Test',
|
|
94
|
+
instructions: Template.make({
|
|
95
|
+
source: trim`
|
|
96
|
+
Organization List:
|
|
97
|
+
{{#each organizations}}
|
|
98
|
+
- {{this}}
|
|
99
|
+
{{/each}}
|
|
100
|
+
`,
|
|
101
|
+
inputs: [
|
|
102
|
+
{
|
|
103
|
+
name: 'organizations',
|
|
104
|
+
kind: 'function',
|
|
105
|
+
function: organizationListFunction.key,
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
}),
|
|
48
109
|
}),
|
|
49
|
-
|
|
50
|
-
);
|
|
110
|
+
);
|
|
51
111
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
112
|
+
const output = yield* formatSystemPrompt({
|
|
113
|
+
system: createSystemPrompt({}),
|
|
114
|
+
blueprints: [blueprint],
|
|
115
|
+
objects: [object],
|
|
116
|
+
});
|
|
57
117
|
|
|
58
|
-
|
|
59
|
-
|
|
118
|
+
expect(output).to.include('Test Org');
|
|
119
|
+
},
|
|
120
|
+
Effect.provide(TestLayer),
|
|
121
|
+
TestHelpers.provideTestContext,
|
|
122
|
+
),
|
|
60
123
|
);
|
|
61
124
|
});
|
package/src/session/format.ts
CHANGED
|
@@ -2,15 +2,14 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import * as Array from 'effect/Array';
|
|
6
5
|
import * as Effect from 'effect/Effect';
|
|
7
6
|
import * as Function from 'effect/Function';
|
|
8
7
|
import * as Option from 'effect/Option';
|
|
9
8
|
|
|
10
9
|
import { Template } from '@dxos/blueprints';
|
|
11
10
|
import { Obj } from '@dxos/echo';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
11
|
+
import { ObjectVersion } from '@dxos/echo-db';
|
|
12
|
+
import { type ObjectId } from '@dxos/keys';
|
|
14
13
|
import { log } from '@dxos/log';
|
|
15
14
|
import { type ContentBlock, Message } from '@dxos/types';
|
|
16
15
|
import { trim } from '@dxos/util';
|
|
@@ -18,7 +17,7 @@ import { trim } from '@dxos/util';
|
|
|
18
17
|
import { AiAssistantError } from '../errors';
|
|
19
18
|
|
|
20
19
|
import { ArtifactDiffResolver } from './artifact-diff';
|
|
21
|
-
import { type AiSessionRunError, type
|
|
20
|
+
import { type AiSessionRunError, type AiSessionRunProps } from './session';
|
|
22
21
|
|
|
23
22
|
/**
|
|
24
23
|
* Formats the system prompt.
|
|
@@ -28,20 +27,20 @@ export const formatSystemPrompt = ({
|
|
|
28
27
|
system,
|
|
29
28
|
blueprints = [],
|
|
30
29
|
objects = [],
|
|
31
|
-
}: Pick<
|
|
30
|
+
}: Pick<AiSessionRunProps<any>, 'system' | 'blueprints' | 'objects'>) =>
|
|
32
31
|
Effect.gen(function* () {
|
|
33
32
|
const blueprintDefs = yield* Function.pipe(
|
|
34
33
|
blueprints,
|
|
35
34
|
Effect.forEach((blueprint) => Effect.succeed(blueprint.instructions)),
|
|
36
|
-
Effect.flatMap(
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
(template) => trim`
|
|
35
|
+
Effect.flatMap(
|
|
36
|
+
Effect.forEach((template) =>
|
|
37
|
+
Effect.gen(function* () {
|
|
38
|
+
return trim`
|
|
41
39
|
<blueprint>
|
|
42
|
-
${Template.
|
|
40
|
+
${yield* Template.processTemplate(template)}
|
|
43
41
|
</blueprint>
|
|
44
|
-
|
|
42
|
+
`;
|
|
43
|
+
}),
|
|
45
44
|
),
|
|
46
45
|
),
|
|
47
46
|
Effect.map((blueprints) =>
|
|
@@ -76,7 +75,7 @@ export const formatSystemPrompt = ({
|
|
|
76
75
|
export const formatUserPrompt = ({
|
|
77
76
|
prompt,
|
|
78
77
|
history = [],
|
|
79
|
-
}: Pick<
|
|
78
|
+
}: Pick<AiSessionRunProps<any>, 'prompt' | 'history'>): Effect.Effect<Message.Message, AiSessionRunError> =>
|
|
80
79
|
Effect.gen(function* () {
|
|
81
80
|
const blocks: ContentBlock.Any[] = [];
|
|
82
81
|
|
package/src/session/index.ts
CHANGED
package/src/session/observer.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import type * as Tool from '@effect/ai/Tool';
|
|
5
6
|
import * as Effect from 'effect/Effect';
|
|
6
7
|
import * as Function from 'effect/Function';
|
|
7
8
|
|
|
@@ -11,7 +12,8 @@ import { type Message } from '@dxos/types';
|
|
|
11
12
|
/**
|
|
12
13
|
* Live observer of the generation process.
|
|
13
14
|
*/
|
|
14
|
-
export interface GenerationObserver extends
|
|
15
|
+
export interface GenerationObserver<Tools extends Record<string, Tool.Any> = any>
|
|
16
|
+
extends AiParser.ParseResponseCallbacks<Tools> {
|
|
15
17
|
/**
|
|
16
18
|
* Complete messages fired during the session, both from the model and from the user.
|
|
17
19
|
* This message will contain all message blocks emitted through the `onBlock` callback.
|