@dxos/assistant 0.8.2-staging.7ac8446 → 0.8.2
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/browser/index.mjs +1830 -228
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +1825 -229
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +1831 -228
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/{src/bin → bin}/chat.d.ts.map +1 -1
- package/dist/types/src/blueprint/blueprint.d.ts +79 -0
- package/dist/types/src/blueprint/blueprint.d.ts.map +1 -0
- package/dist/types/src/blueprint/blueprint.test.d.ts +2 -0
- package/dist/types/src/blueprint/blueprint.test.d.ts.map +1 -0
- package/dist/types/src/blueprint/index.d.ts +4 -0
- package/dist/types/src/blueprint/index.d.ts.map +1 -0
- package/dist/types/src/blueprint/logger.d.ts +3 -0
- package/dist/types/src/blueprint/logger.d.ts.map +1 -0
- package/dist/types/src/blueprint/machine.d.ts +113 -0
- package/dist/types/src/blueprint/machine.d.ts.map +1 -0
- package/dist/types/src/blueprint/test-data.d.ts +3 -0
- package/dist/types/src/blueprint/test-data.d.ts.map +1 -0
- package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.d.ts +4 -0
- package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.d.ts.map +1 -0
- package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.test.d.ts +2 -0
- package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.test.d.ts.map +1 -0
- package/dist/types/src/extraction/extraction-llm-function/index.d.ts +2 -0
- package/dist/types/src/extraction/extraction-llm-function/index.d.ts.map +1 -0
- package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts +210 -0
- package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts.map +1 -0
- package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.test.d.ts +2 -0
- package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.test.d.ts.map +1 -0
- package/dist/types/src/extraction/extraction-ner-function/index.d.ts +3 -0
- package/dist/types/src/extraction/extraction-ner-function/index.d.ts.map +1 -0
- package/dist/types/src/extraction/extraction-ner-function/named-entity-recognition.d.ts +14 -0
- package/dist/types/src/extraction/extraction-ner-function/named-entity-recognition.d.ts.map +1 -0
- package/dist/types/src/extraction/extraction-ner-function/named-entity-recognition.test.d.ts +2 -0
- package/dist/types/src/extraction/extraction-ner-function/named-entity-recognition.test.d.ts.map +1 -0
- package/dist/types/src/extraction/extraction.d.ts +242 -0
- package/dist/types/src/extraction/extraction.d.ts.map +1 -0
- package/dist/types/src/extraction/index.d.ts +5 -0
- package/dist/types/src/extraction/index.d.ts.map +1 -0
- package/dist/types/src/extraction/quotes.d.ts +15 -0
- package/dist/types/src/extraction/quotes.d.ts.map +1 -0
- package/dist/types/src/extraction/quotes.test.d.ts +2 -0
- package/dist/types/src/extraction/quotes.test.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +4 -3
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/research/exa.d.ts +7 -0
- package/dist/types/src/research/exa.d.ts.map +1 -0
- package/dist/types/src/research/graph.d.ts +39 -0
- package/dist/types/src/research/graph.d.ts.map +1 -0
- package/dist/types/src/research/graph.test.d.ts +2 -0
- package/dist/types/src/research/graph.test.d.ts.map +1 -0
- package/dist/types/src/research/index.d.ts +4 -0
- package/dist/types/src/research/index.d.ts.map +1 -0
- package/dist/types/src/research/research.d.ts +10 -0
- package/dist/types/src/research/research.d.ts.map +1 -0
- package/dist/types/src/research/research.test.d.ts +2 -0
- package/dist/types/src/research/research.test.d.ts.map +1 -0
- 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/session.d.ts +80 -35
- package/dist/types/src/session/session.d.ts.map +1 -1
- package/dist/types/src/session/version-pin.d.ts +21 -0
- package/dist/types/src/session/version-pin.d.ts.map +1 -0
- package/dist/types/src/session/version-pin.test.d.ts +2 -0
- package/dist/types/src/session/version-pin.test.d.ts.map +1 -0
- package/dist/types/src/summarization/summarization.test.d.ts +2 -0
- package/dist/types/src/summarization/summarization.test.d.ts.map +1 -0
- package/dist/types/src/testing/exa-search-1748337321991.d.ts +38 -0
- package/dist/types/src/testing/exa-search-1748337321991.d.ts.map +1 -0
- package/dist/types/src/testing/exa-search-1748337331526.d.ts +37 -0
- package/dist/types/src/testing/exa-search-1748337331526.d.ts.map +1 -0
- package/dist/types/src/testing/exa-search-1748337344119.d.ts +58 -0
- package/dist/types/src/testing/exa-search-1748337344119.d.ts.map +1 -0
- package/dist/types/src/testing/index.d.ts +2 -6
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +3 -0
- package/dist/types/src/types.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +25 -35
- package/src/blueprint/blueprint.test.ts +142 -0
- package/src/blueprint/blueprint.ts +95 -0
- package/src/blueprint/index.ts +7 -0
- package/src/blueprint/logger.ts +66 -0
- package/src/blueprint/machine.ts +208 -0
- package/src/blueprint/test-data.ts +55 -0
- package/src/extraction/extraction-llm-function/extraction-llm-function.test.ts +95 -0
- package/src/extraction/extraction-llm-function/extraction-llm-function.ts +64 -0
- package/src/extraction/extraction-llm-function/index.ts +5 -0
- package/src/extraction/extraction-llm-function/instructions.tpl +28 -0
- package/src/extraction/extraction-ner-function/extraction-ner-function.test.ts +115 -0
- package/src/extraction/extraction-ner-function/extraction-ner-function.ts +54 -0
- package/src/extraction/extraction-ner-function/index.ts +6 -0
- package/src/extraction/extraction-ner-function/named-entity-recognition.test.ts +94 -0
- package/src/extraction/extraction-ner-function/named-entity-recognition.ts +97 -0
- package/src/extraction/extraction.ts +75 -0
- package/src/extraction/index.ts +8 -0
- package/src/extraction/quotes.test.ts +27 -0
- package/src/extraction/quotes.ts +57 -0
- package/src/index.ts +4 -3
- package/src/research/exa.ts +100 -0
- package/src/research/graph.test.ts +15 -0
- package/src/research/graph.ts +291 -0
- package/src/research/index.ts +7 -0
- package/src/research/instructions-research.tpl +97 -0
- package/src/research/research.test.ts +189 -0
- package/src/research/research.ts +89 -0
- package/src/session/index.ts +1 -0
- package/src/session/session.test.ts +39 -67
- package/src/session/session.ts +328 -155
- package/src/session/version-pin.test.ts +26 -0
- package/src/session/version-pin.ts +48 -0
- package/src/summarization/summarization.test.ts +216 -0
- package/src/testing/exa-search-1748337321991.ts +131 -0
- package/src/testing/exa-search-1748337331526.ts +144 -0
- package/src/testing/exa-search-1748337344119.ts +133 -0
- package/src/testing/index.ts +8 -7
- package/src/typedefs.d.ts +8 -0
- package/src/types.ts +8 -0
- package/src/typings.d.ts +8 -0
- package/dist/lib/browser/chunk-PND5VR6D.mjs +0 -2315
- package/dist/lib/browser/chunk-PND5VR6D.mjs.map +0 -7
- package/dist/lib/browser/testing/index.mjs +0 -621
- package/dist/lib/browser/testing/index.mjs.map +0 -7
- package/dist/lib/node/chunk-IBOBRBDF.cjs +0 -2326
- package/dist/lib/node/chunk-IBOBRBDF.cjs.map +0 -7
- package/dist/lib/node/testing/index.cjs +0 -637
- package/dist/lib/node/testing/index.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-DCQJOLSR.mjs +0 -2317
- package/dist/lib/node-esm/chunk-DCQJOLSR.mjs.map +0 -7
- package/dist/lib/node-esm/testing/index.mjs +0 -622
- package/dist/lib/node-esm/testing/index.mjs.map +0 -7
- package/dist/types/src/ai-service/client.test.d.ts +0 -2
- package/dist/types/src/ai-service/client.test.d.ts.map +0 -1
- package/dist/types/src/ai-service/defs.d.ts +0 -9
- package/dist/types/src/ai-service/defs.d.ts.map +0 -1
- package/dist/types/src/ai-service/edge-client.d.ts +0 -19
- package/dist/types/src/ai-service/edge-client.d.ts.map +0 -1
- package/dist/types/src/ai-service/index.d.ts +0 -10
- package/dist/types/src/ai-service/index.d.ts.map +0 -1
- package/dist/types/src/ai-service/message-collector.d.ts +0 -88
- package/dist/types/src/ai-service/message-collector.d.ts.map +0 -1
- package/dist/types/src/ai-service/ollama-client.d.ts +0 -39
- package/dist/types/src/ai-service/ollama-client.d.ts.map +0 -1
- package/dist/types/src/ai-service/parser.d.ts +0 -138
- package/dist/types/src/ai-service/parser.d.ts.map +0 -1
- package/dist/types/src/ai-service/service.d.ts +0 -9
- package/dist/types/src/ai-service/service.d.ts.map +0 -1
- package/dist/types/src/ai-service/stream.d.ts +0 -40
- package/dist/types/src/ai-service/stream.d.ts.map +0 -1
- package/dist/types/src/ai-service/stream.test.d.ts +0 -2
- package/dist/types/src/ai-service/stream.test.d.ts.map +0 -1
- package/dist/types/src/ai-service/testing/index.d.ts +0 -3
- package/dist/types/src/ai-service/testing/index.d.ts.map +0 -1
- package/dist/types/src/ai-service/testing/mock.d.ts +0 -7
- package/dist/types/src/ai-service/testing/mock.d.ts.map +0 -1
- package/dist/types/src/ai-service/testing/test-stream.d.ts +0 -7
- package/dist/types/src/ai-service/testing/test-stream.d.ts.map +0 -1
- package/dist/types/src/ai-service/transform.d.ts +0 -27
- package/dist/types/src/ai-service/transform.d.ts.map +0 -1
- package/dist/types/src/ai-service/types.d.ts +0 -167
- package/dist/types/src/ai-service/types.d.ts.map +0 -1
- package/dist/types/src/ai-service/util/index.d.ts +0 -2
- package/dist/types/src/ai-service/util/index.d.ts.map +0 -1
- package/dist/types/src/ai-service/util/sse.d.ts +0 -39
- package/dist/types/src/ai-service/util/sse.d.ts.map +0 -1
- package/dist/types/src/conversation/conversation.d.ts +0 -80
- package/dist/types/src/conversation/conversation.d.ts.map +0 -1
- package/dist/types/src/conversation/conversation.test.d.ts +0 -2
- package/dist/types/src/conversation/conversation.test.d.ts.map +0 -1
- package/dist/types/src/conversation/index.d.ts +0 -2
- package/dist/types/src/conversation/index.d.ts.map +0 -1
- package/dist/types/src/conversation/types.d.ts +0 -79
- package/dist/types/src/conversation/types.d.ts.map +0 -1
- package/dist/types/src/cypher/ast.d.ts +0 -56
- package/dist/types/src/cypher/ast.d.ts.map +0 -1
- package/dist/types/src/cypher/combinators.d.ts +0 -14
- package/dist/types/src/cypher/combinators.d.ts.map +0 -1
- package/dist/types/src/cypher/combinators.test.d.ts +0 -2
- package/dist/types/src/cypher/combinators.test.d.ts.map +0 -1
- package/dist/types/src/cypher/echo-data-source.d.ts +0 -16
- package/dist/types/src/cypher/echo-data-source.d.ts.map +0 -1
- package/dist/types/src/cypher/execution-plan.d.ts +0 -49
- package/dist/types/src/cypher/execution-plan.d.ts.map +0 -1
- package/dist/types/src/cypher/execution-plan.test.d.ts +0 -2
- package/dist/types/src/cypher/execution-plan.test.d.ts.map +0 -1
- package/dist/types/src/cypher/index.d.ts +0 -5
- package/dist/types/src/cypher/index.d.ts.map +0 -1
- package/dist/types/src/cypher/parjs.d.ts +0 -4
- package/dist/types/src/cypher/parjs.d.ts.map +0 -1
- package/dist/types/src/cypher/parser.d.ts +0 -6
- package/dist/types/src/cypher/parser.d.ts.map +0 -1
- package/dist/types/src/cypher/query-executor.d.ts +0 -26
- package/dist/types/src/cypher/query-executor.d.ts.map +0 -1
- package/dist/types/src/cypher/query-executor.test.d.ts +0 -2
- package/dist/types/src/cypher/query-executor.test.d.ts.map +0 -1
- package/dist/types/src/cypher/schema.d.ts +0 -12
- package/dist/types/src/cypher/schema.d.ts.map +0 -1
- package/dist/types/src/cypher/schema.test.d.ts +0 -2
- package/dist/types/src/cypher/schema.test.d.ts.map +0 -1
- package/dist/types/src/testing/artifacts.test.d.ts +0 -1
- package/dist/types/src/testing/artifacts.test.d.ts.map +0 -1
- package/dist/types/src/testing/data.d.ts +0 -2
- package/dist/types/src/testing/data.d.ts.map +0 -1
- package/dist/types/src/testing/defs.d.ts +0 -5
- package/dist/types/src/testing/defs.d.ts.map +0 -1
- package/dist/types/src/testing/logger.d.ts +0 -12
- package/dist/types/src/testing/logger.d.ts.map +0 -1
- package/dist/types/src/testing/object-extraction.test.d.ts +0 -1
- package/dist/types/src/testing/object-extraction.test.d.ts.map +0 -1
- package/dist/types/src/testing/ollama.d.ts +0 -6
- package/dist/types/src/testing/ollama.d.ts.map +0 -1
- package/dist/types/src/testing/query-promts.d.ts +0 -5
- package/dist/types/src/testing/query-promts.d.ts.map +0 -1
- package/dist/types/src/testing/query.test.d.ts +0 -2
- package/dist/types/src/testing/query.test.d.ts.map +0 -1
- package/dist/types/src/testing/test-data.d.ts +0 -29
- package/dist/types/src/testing/test-data.d.ts.map +0 -1
- package/dist/types/src/testing/test-schema.d.ts +0 -50
- package/dist/types/src/testing/test-schema.d.ts.map +0 -1
- package/dist/types/src/util/index.d.ts +0 -2
- package/dist/types/src/util/index.d.ts.map +0 -1
- package/dist/types/src/util/trim.d.ts +0 -5
- package/dist/types/src/util/trim.d.ts.map +0 -1
- package/src/ai-service/client.test.ts +0 -265
- package/src/ai-service/defs.ts +0 -39
- package/src/ai-service/edge-client.ts +0 -67
- package/src/ai-service/index.ts +0 -13
- package/src/ai-service/message-collector.ts +0 -84
- package/src/ai-service/ollama-client.ts +0 -499
- package/src/ai-service/parser.ts +0 -358
- package/src/ai-service/service.ts +0 -15
- package/src/ai-service/stream.test.ts +0 -125
- package/src/ai-service/stream.ts +0 -118
- package/src/ai-service/testing/index.ts +0 -6
- package/src/ai-service/testing/mock.ts +0 -22
- package/src/ai-service/testing/test-stream.ts +0 -93
- package/src/ai-service/transform.ts +0 -121
- package/src/ai-service/types.ts +0 -103
- package/src/ai-service/util/index.ts +0 -5
- package/src/ai-service/util/sse.ts +0 -341
- package/src/bin/chat.ts +0 -79
- package/src/conversation/conversation.test.ts +0 -73
- package/src/conversation/conversation.ts +0 -257
- package/src/conversation/index.ts +0 -5
- package/src/conversation/types.ts +0 -129
- package/src/cypher/ast.ts +0 -75
- package/src/cypher/combinators.test.ts +0 -137
- package/src/cypher/combinators.ts +0 -148
- package/src/cypher/echo-data-source.ts +0 -105
- package/src/cypher/execution-plan.test.ts +0 -44
- package/src/cypher/execution-plan.ts +0 -208
- package/src/cypher/index.ts +0 -8
- package/src/cypher/parjs-shims.d.ts +0 -10
- package/src/cypher/parjs.ts +0 -10
- package/src/cypher/parser.ts +0 -19
- package/src/cypher/query-executor.test.ts +0 -47
- package/src/cypher/query-executor.ts +0 -145
- package/src/cypher/schema.test.ts +0 -17
- package/src/cypher/schema.ts +0 -86
- package/src/testing/artifacts.test.ts +0 -182
- package/src/testing/data.ts +0 -13
- package/src/testing/defs.ts +0 -9
- package/src/testing/logger.ts +0 -129
- package/src/testing/object-extraction.test.ts +0 -71
- package/src/testing/ollama.ts +0 -15
- package/src/testing/query-promts.ts +0 -75
- package/src/testing/query.test.ts +0 -91
- package/src/testing/test-data.ts +0 -372
- package/src/testing/test-schema.ts +0 -80
- package/src/util/index.ts +0 -5
- package/src/util/trim.ts +0 -15
- package/vendor/parjs-browser.mjs +0 -4
- package/vendor/parjs-default.mjs +0 -8
- /package/dist/types/{src/bin → bin}/chat.d.ts +0 -0
package/src/ai-service/parser.ts
DELETED
|
@@ -1,358 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2025 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { Message, type MessageContentBlock } from '@dxos/artifact';
|
|
6
|
-
import { Event } from '@dxos/async';
|
|
7
|
-
import { createStatic } from '@dxos/echo-schema';
|
|
8
|
-
import { invariant } from '@dxos/invariant';
|
|
9
|
-
import { log } from '@dxos/log';
|
|
10
|
-
import { isNotFalsy, safeParseJson } from '@dxos/util';
|
|
11
|
-
|
|
12
|
-
import { type GenerationStream } from './service';
|
|
13
|
-
import { StreamTransform, type StreamBlock } from './transform';
|
|
14
|
-
import type { GenerationStreamEvent } from './types';
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Parse mixed content of plain text, XML fragments, and JSON blocks.
|
|
18
|
-
*/
|
|
19
|
-
export class MixedStreamParser {
|
|
20
|
-
/**
|
|
21
|
-
* New message.
|
|
22
|
-
*/
|
|
23
|
-
public message = new Event<Message>();
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Complete block added to Message.
|
|
27
|
-
*/
|
|
28
|
-
public block = new Event<MessageContentBlock>();
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Update partial block (while streaming).
|
|
32
|
-
*/
|
|
33
|
-
public update = new Event<MessageContentBlock>();
|
|
34
|
-
|
|
35
|
-
public streamEvent = new Event<GenerationStreamEvent>();
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Current message.
|
|
39
|
-
*/
|
|
40
|
-
private _message?: Message | undefined;
|
|
41
|
-
|
|
42
|
-
private _emitBlock(contentBlock: MessageContentBlock, streamBlock?: StreamBlock) {
|
|
43
|
-
const messageBlock = streamBlock ? mergeMessageBlock(contentBlock, streamBlock) : contentBlock;
|
|
44
|
-
if (messageBlock) {
|
|
45
|
-
if (messageBlock.type === 'text' && messageBlock.text.length === 0) {
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
invariant(this._message);
|
|
50
|
-
this._message.content.push(messageBlock);
|
|
51
|
-
this.block.emit(messageBlock);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
private _emitUpdate(contentBlock: MessageContentBlock, streamBlock: StreamBlock) {
|
|
56
|
-
const messageBlock = mergeMessageBlock(contentBlock, streamBlock);
|
|
57
|
-
if (messageBlock) {
|
|
58
|
-
messageBlock.pending = true;
|
|
59
|
-
this.update.emit(messageBlock);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Parse stream until end.
|
|
65
|
-
*/
|
|
66
|
-
async parse(stream: GenerationStream): Promise<Message[]> {
|
|
67
|
-
const transformer = new StreamTransform();
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Current content message block.
|
|
71
|
-
*/
|
|
72
|
-
let contentBlock: MessageContentBlock | undefined;
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Current partial block used to accumulate content.
|
|
76
|
-
*/
|
|
77
|
-
let streamBlock: StreamBlock | undefined;
|
|
78
|
-
const stack: StreamBlock[] = [];
|
|
79
|
-
|
|
80
|
-
const messagesCollected: Message[] = [];
|
|
81
|
-
|
|
82
|
-
for await (const event of stream) {
|
|
83
|
-
log('streamEvent', { event });
|
|
84
|
-
this.streamEvent.emit(event);
|
|
85
|
-
|
|
86
|
-
// log('event', { type: event.type, event });
|
|
87
|
-
switch (event.type) {
|
|
88
|
-
//
|
|
89
|
-
// Messages.
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
case 'message_start': {
|
|
93
|
-
if (this._message) {
|
|
94
|
-
log.warn('unexpected message_start');
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
this._message = createStatic(Message, { role: event.message.role, content: [...event.message.content] });
|
|
98
|
-
this.message.emit(this._message);
|
|
99
|
-
break;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
case 'message_delta': {
|
|
103
|
-
if (!this._message) {
|
|
104
|
-
log.warn('unexpected message_delta');
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
break;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
case 'message_stop': {
|
|
111
|
-
if (!this._message) {
|
|
112
|
-
log.warn('unexpected message_stop');
|
|
113
|
-
} else {
|
|
114
|
-
messagesCollected.push(this._message);
|
|
115
|
-
this._message = undefined;
|
|
116
|
-
}
|
|
117
|
-
break;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
//
|
|
121
|
-
// Content blocks.
|
|
122
|
-
//
|
|
123
|
-
|
|
124
|
-
case 'content_block_start': {
|
|
125
|
-
if (contentBlock) {
|
|
126
|
-
log.warn('unexpected content_block_start', { content: contentBlock });
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// TODO(burdon): Parse initial content (factor out from content_block_delta).
|
|
130
|
-
contentBlock = event.content;
|
|
131
|
-
break;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
case 'content_block_delta': {
|
|
135
|
-
if (!contentBlock) {
|
|
136
|
-
log.warn('unexpected content_block_delta');
|
|
137
|
-
break;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
switch (event.delta.type) {
|
|
141
|
-
//
|
|
142
|
-
// Text
|
|
143
|
-
//
|
|
144
|
-
case 'text_delta': {
|
|
145
|
-
const chunks = transformer.transform(event.delta.text);
|
|
146
|
-
for (const chunk of chunks) {
|
|
147
|
-
log('text_delta', { chunk });
|
|
148
|
-
|
|
149
|
-
switch (streamBlock?.type) {
|
|
150
|
-
//
|
|
151
|
-
// XML Fragment.
|
|
152
|
-
//
|
|
153
|
-
case 'tag': {
|
|
154
|
-
if (chunk.type === 'tag') {
|
|
155
|
-
if (chunk.selfClosing) {
|
|
156
|
-
streamBlock.content.push(chunk);
|
|
157
|
-
} else if (chunk.closing) {
|
|
158
|
-
if (stack.length > 0) {
|
|
159
|
-
const top = stack.pop();
|
|
160
|
-
invariant(top && top.type === 'tag');
|
|
161
|
-
log('pop', { top });
|
|
162
|
-
top.content.push(streamBlock);
|
|
163
|
-
streamBlock = top;
|
|
164
|
-
} else {
|
|
165
|
-
this._emitBlock(contentBlock, streamBlock);
|
|
166
|
-
streamBlock = undefined;
|
|
167
|
-
}
|
|
168
|
-
} else {
|
|
169
|
-
stack.push(streamBlock);
|
|
170
|
-
streamBlock = chunk;
|
|
171
|
-
}
|
|
172
|
-
} else {
|
|
173
|
-
// Append text.
|
|
174
|
-
if (streamBlock.content.length === 0) {
|
|
175
|
-
streamBlock.content.push(chunk);
|
|
176
|
-
} else {
|
|
177
|
-
const last = streamBlock.content.at(-1);
|
|
178
|
-
invariant(last);
|
|
179
|
-
if (last.type === 'text') {
|
|
180
|
-
last.content += chunk.content;
|
|
181
|
-
} else {
|
|
182
|
-
streamBlock.content.push(chunk);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
break;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
//
|
|
190
|
-
// Text Fragment.
|
|
191
|
-
//
|
|
192
|
-
case 'text': {
|
|
193
|
-
if (chunk.type === 'tag') {
|
|
194
|
-
this._emitBlock(contentBlock, streamBlock);
|
|
195
|
-
if (chunk.selfClosing) {
|
|
196
|
-
this._emitBlock(contentBlock, chunk);
|
|
197
|
-
streamBlock = undefined;
|
|
198
|
-
} else {
|
|
199
|
-
streamBlock = chunk;
|
|
200
|
-
}
|
|
201
|
-
} else {
|
|
202
|
-
// Append text.
|
|
203
|
-
streamBlock.content += chunk.content;
|
|
204
|
-
}
|
|
205
|
-
break;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
//
|
|
209
|
-
// No current chunk.
|
|
210
|
-
//
|
|
211
|
-
default: {
|
|
212
|
-
if (chunk.type === 'tag' && chunk.selfClosing) {
|
|
213
|
-
this._emitBlock(contentBlock, chunk);
|
|
214
|
-
} else {
|
|
215
|
-
streamBlock = chunk;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
break;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
//
|
|
224
|
-
// JSON
|
|
225
|
-
//
|
|
226
|
-
case 'input_json_delta': {
|
|
227
|
-
if (!contentBlock) {
|
|
228
|
-
log.warn('unexpected input_json_delta', { contentBlock });
|
|
229
|
-
break;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (streamBlock?.type === 'json') {
|
|
233
|
-
streamBlock.content += event.delta.partial_json;
|
|
234
|
-
} else {
|
|
235
|
-
streamBlock = { type: 'json', content: event.delta.partial_json };
|
|
236
|
-
}
|
|
237
|
-
break;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
break;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
case 'content_block_stop': {
|
|
244
|
-
if (!contentBlock) {
|
|
245
|
-
log.warn('unexpected content_block_stop');
|
|
246
|
-
break;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
this._emitBlock(contentBlock, streamBlock);
|
|
250
|
-
contentBlock = undefined;
|
|
251
|
-
streamBlock = undefined;
|
|
252
|
-
break;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
if (contentBlock && streamBlock) {
|
|
257
|
-
this._emitUpdate(contentBlock, streamBlock);
|
|
258
|
-
}
|
|
259
|
-
} // for.
|
|
260
|
-
|
|
261
|
-
return messagesCollected;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Convert stream block to message content block.
|
|
267
|
-
*/
|
|
268
|
-
export const mergeMessageBlock = (
|
|
269
|
-
contentBlock: MessageContentBlock,
|
|
270
|
-
streamBlock: StreamBlock,
|
|
271
|
-
): MessageContentBlock | undefined => {
|
|
272
|
-
log('mergeMessageBlock', { contentBlock, streamBlock });
|
|
273
|
-
|
|
274
|
-
switch (streamBlock.type) {
|
|
275
|
-
//
|
|
276
|
-
// Text
|
|
277
|
-
//
|
|
278
|
-
case 'text': {
|
|
279
|
-
return { ...contentBlock, type: 'text', text: streamBlock.content };
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
//
|
|
283
|
-
// XML
|
|
284
|
-
//
|
|
285
|
-
case 'tag': {
|
|
286
|
-
switch (streamBlock.tag) {
|
|
287
|
-
case 'cot': {
|
|
288
|
-
const content = streamBlock.content
|
|
289
|
-
.map((block) => {
|
|
290
|
-
switch (block.type) {
|
|
291
|
-
case 'text':
|
|
292
|
-
return block.content;
|
|
293
|
-
default:
|
|
294
|
-
return null;
|
|
295
|
-
}
|
|
296
|
-
})
|
|
297
|
-
.filter(isNotFalsy)
|
|
298
|
-
.join('\n');
|
|
299
|
-
|
|
300
|
-
return { ...contentBlock, type: 'text', disposition: 'cot', text: content };
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
case 'artifact': {
|
|
304
|
-
const { attributes } = streamBlock;
|
|
305
|
-
return { type: 'json', disposition: 'artifact', json: JSON.stringify(attributes) };
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
case 'suggest': {
|
|
309
|
-
if (streamBlock.content.length === 1 && streamBlock.content[0].type === 'text') {
|
|
310
|
-
return {
|
|
311
|
-
type: 'json',
|
|
312
|
-
disposition: 'suggest',
|
|
313
|
-
json: JSON.stringify({ text: streamBlock.content[0].content }),
|
|
314
|
-
};
|
|
315
|
-
}
|
|
316
|
-
break;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
case 'select': {
|
|
320
|
-
return {
|
|
321
|
-
type: 'json',
|
|
322
|
-
disposition: 'select',
|
|
323
|
-
json: JSON.stringify({
|
|
324
|
-
options: streamBlock.content.flatMap((content) =>
|
|
325
|
-
content.type === 'tag' && content.content.length === 1 && content.content[0].type === 'text'
|
|
326
|
-
? [content.content[0].content]
|
|
327
|
-
: [],
|
|
328
|
-
),
|
|
329
|
-
}),
|
|
330
|
-
};
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
case 'tool-list': {
|
|
334
|
-
return {
|
|
335
|
-
type: 'json',
|
|
336
|
-
disposition: 'tool_list',
|
|
337
|
-
json: JSON.stringify({}),
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
break;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
//
|
|
346
|
-
// JSON
|
|
347
|
-
//
|
|
348
|
-
case 'json': {
|
|
349
|
-
switch (contentBlock.type) {
|
|
350
|
-
case 'tool_use': {
|
|
351
|
-
return { ...contentBlock, input: safeParseJson(streamBlock.content) ?? {} };
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
return { ...contentBlock, type: 'json', disposition: 'artifact', json: streamBlock.content };
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2025 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { type GenerateRequest, type GenerationStreamEvent } from './types';
|
|
6
|
-
|
|
7
|
-
// TODO(burdon): Create wrapper for edge/ollama. Create session?
|
|
8
|
-
export interface AIServiceClient {
|
|
9
|
-
exec(request: GenerateRequest): Promise<GenerationStream>;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface GenerationStream extends AsyncIterable<GenerationStreamEvent> {
|
|
13
|
-
abort(): void;
|
|
14
|
-
complete(): Promise<void>;
|
|
15
|
-
}
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2025 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { describe, test } from 'vitest';
|
|
6
|
-
|
|
7
|
-
import { type Message } from '@dxos/artifact';
|
|
8
|
-
import { log } from '@dxos/log';
|
|
9
|
-
|
|
10
|
-
import { MixedStreamParser } from './parser';
|
|
11
|
-
import { createGenerationStream } from './stream';
|
|
12
|
-
import { createTestSSEStream } from './testing';
|
|
13
|
-
import { type GenerationStreamEvent } from './types';
|
|
14
|
-
|
|
15
|
-
// TODO(burdon): Tool request/response.
|
|
16
|
-
|
|
17
|
-
const TEST_BLOCKS = [
|
|
18
|
-
[
|
|
19
|
-
// Text
|
|
20
|
-
'some text',
|
|
21
|
-
'on multiple lines.',
|
|
22
|
-
|
|
23
|
-
// XML
|
|
24
|
-
'<cot>',
|
|
25
|
-
' 1. Analyze content.',
|
|
26
|
-
' 2. Create plan.',
|
|
27
|
-
' 3. Generate artifacts.',
|
|
28
|
-
'</cot>',
|
|
29
|
-
|
|
30
|
-
// Text
|
|
31
|
-
'some more text.',
|
|
32
|
-
|
|
33
|
-
// XML
|
|
34
|
-
'<artifact id="123" />',
|
|
35
|
-
|
|
36
|
-
// XML
|
|
37
|
-
'<artifact id="456" />',
|
|
38
|
-
|
|
39
|
-
// Text
|
|
40
|
-
'and some more text.',
|
|
41
|
-
|
|
42
|
-
'<suggest>Plan me a trip to the Rio.</suggest>',
|
|
43
|
-
'<suggest>Show me steak recipes.</suggest>',
|
|
44
|
-
'<select><option>Yes</option><option>No</option></select>',
|
|
45
|
-
].join('\n'),
|
|
46
|
-
|
|
47
|
-
// JSON
|
|
48
|
-
{
|
|
49
|
-
type: 'input',
|
|
50
|
-
value: {
|
|
51
|
-
level: 1,
|
|
52
|
-
optional: true,
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
];
|
|
56
|
-
|
|
57
|
-
describe('GenerationStream', () => {
|
|
58
|
-
test('should generate a stream of blocks', async ({ expect }) => {
|
|
59
|
-
const stream = createGenerationStream(new Response(createTestSSEStream(TEST_BLOCKS)));
|
|
60
|
-
const events: GenerationStreamEvent[] = [];
|
|
61
|
-
for await (const event of stream) {
|
|
62
|
-
events.push(event);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
expect(events.map((event) => event.type === 'content_block_start').filter(Boolean)).to.have.length(2);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
for (const splitBy of ['word'] as const) {
|
|
69
|
-
test(`should emit xml blocks (splitBy: ${splitBy})`, async ({ expect }) => {
|
|
70
|
-
const stream = createGenerationStream(new Response(createTestSSEStream(TEST_BLOCKS, { splitBy })));
|
|
71
|
-
const parser = new MixedStreamParser();
|
|
72
|
-
|
|
73
|
-
let message: Message | undefined;
|
|
74
|
-
parser.message.on((_message) => {
|
|
75
|
-
message = _message;
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
await parser.parse(stream);
|
|
79
|
-
|
|
80
|
-
for (const block of message?.content ?? []) {
|
|
81
|
-
log('block', { block });
|
|
82
|
-
}
|
|
83
|
-
expect(message?.content.map((block) => block.type)).to.deep.eq([
|
|
84
|
-
//
|
|
85
|
-
'text',
|
|
86
|
-
'text',
|
|
87
|
-
'text',
|
|
88
|
-
'json',
|
|
89
|
-
'text',
|
|
90
|
-
'json',
|
|
91
|
-
'text',
|
|
92
|
-
'json',
|
|
93
|
-
'text',
|
|
94
|
-
'json',
|
|
95
|
-
'text',
|
|
96
|
-
'json',
|
|
97
|
-
'json',
|
|
98
|
-
]);
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
test.skip('invalid xml', async ({ expect }) => {
|
|
103
|
-
const BLOCKS = [
|
|
104
|
-
//
|
|
105
|
-
'<cot> thoughts <tool-list> more thoughts </cot> <tool-list/>',
|
|
106
|
-
];
|
|
107
|
-
|
|
108
|
-
const stream = createGenerationStream(new Response(createTestSSEStream(BLOCKS, { splitBy: 'word' })));
|
|
109
|
-
const parser = new MixedStreamParser();
|
|
110
|
-
|
|
111
|
-
const result = await parser.parse(stream);
|
|
112
|
-
expect(result[0].content).to.deep.eq([
|
|
113
|
-
{
|
|
114
|
-
type: 'text',
|
|
115
|
-
disposition: 'cot',
|
|
116
|
-
text: 'thoughts more thoughts',
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
type: 'json',
|
|
120
|
-
disposition: 'tool_list',
|
|
121
|
-
json: '{}',
|
|
122
|
-
},
|
|
123
|
-
]);
|
|
124
|
-
});
|
|
125
|
-
});
|
package/src/ai-service/stream.ts
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2024 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { Trigger } from '@dxos/async';
|
|
6
|
-
import { log } from '@dxos/log';
|
|
7
|
-
|
|
8
|
-
import type { GenerationStream } from './service';
|
|
9
|
-
import { type GenerationStreamEvent } from './types';
|
|
10
|
-
import { iterSSEMessages } from './util';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Creates a stream from an SSE response.
|
|
14
|
-
*/
|
|
15
|
-
export const createGenerationStream = (response: Response, controller = new AbortController()): GenerationStream => {
|
|
16
|
-
const iterator = async function* () {
|
|
17
|
-
for await (const sse of iterSSEMessages(response, controller)) {
|
|
18
|
-
if (sse.event === 'completion') {
|
|
19
|
-
try {
|
|
20
|
-
yield JSON.parse(sse.data);
|
|
21
|
-
} catch (err) {
|
|
22
|
-
log.error('could not parse message into JSON:', { data: sse.data, raw: sse.raw });
|
|
23
|
-
throw err;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if (
|
|
28
|
-
sse.event === 'message_start' ||
|
|
29
|
-
sse.event === 'message_delta' ||
|
|
30
|
-
sse.event === 'message_stop' ||
|
|
31
|
-
sse.event === 'content_block_start' ||
|
|
32
|
-
sse.event === 'content_block_delta' ||
|
|
33
|
-
sse.event === 'content_block_stop'
|
|
34
|
-
) {
|
|
35
|
-
try {
|
|
36
|
-
yield JSON.parse(sse.data);
|
|
37
|
-
} catch (err) {
|
|
38
|
-
log.error('could not parse message into JSON:', { data: sse.data, raw: sse.raw });
|
|
39
|
-
throw err;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (sse.event === 'ping') {
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (sse.event === 'error') {
|
|
48
|
-
throw new Error(`Message generation error: ${sse.data}`);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
return new GenerationStreamImpl(controller, iterator);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Server-Sent Events (SSE) stream from the AI service.
|
|
58
|
-
* https://html.spec.whatwg.org/multipage/server-sent-events.html#server-sent-events
|
|
59
|
-
*/
|
|
60
|
-
export class GenerationStreamImpl implements GenerationStream {
|
|
61
|
-
/**
|
|
62
|
-
* Trigger event when the stream is done.
|
|
63
|
-
*/
|
|
64
|
-
private readonly _done = new Trigger();
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Iterator over the stream.
|
|
68
|
-
*/
|
|
69
|
-
private _iterator?: AsyncIterator<GenerationStreamEvent> = undefined;
|
|
70
|
-
|
|
71
|
-
constructor(
|
|
72
|
-
private readonly _controller: AbortController,
|
|
73
|
-
private readonly _getIterator: () => AsyncIterableIterator<GenerationStreamEvent>,
|
|
74
|
-
) {}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Returns an iterator over the stream.
|
|
78
|
-
*/
|
|
79
|
-
[Symbol.asyncIterator](): AsyncIterator<GenerationStreamEvent> {
|
|
80
|
-
return this._createIterator();
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Aborts the stream.
|
|
85
|
-
*/
|
|
86
|
-
abort() {
|
|
87
|
-
this._controller.abort();
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Returns the complete message list generated by the AI service.
|
|
92
|
-
*/
|
|
93
|
-
async complete() {
|
|
94
|
-
await this._done.wait();
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Creates an iterator over the stream.
|
|
99
|
-
*/
|
|
100
|
-
private _createIterator(): AsyncIterator<GenerationStreamEvent> {
|
|
101
|
-
const self = this;
|
|
102
|
-
return (this._iterator ??= (() => {
|
|
103
|
-
const generator = async function* (this: GenerationStreamImpl) {
|
|
104
|
-
try {
|
|
105
|
-
for await (const event of self._getIterator()) {
|
|
106
|
-
yield event;
|
|
107
|
-
}
|
|
108
|
-
this._done.wake();
|
|
109
|
-
} catch (err: any) {
|
|
110
|
-
this._done.throw(err);
|
|
111
|
-
throw err;
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
return generator.call(this);
|
|
116
|
-
})());
|
|
117
|
-
}
|
|
118
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2025 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
type GenerationStream,
|
|
7
|
-
type AIServiceClient,
|
|
8
|
-
type GenerateRequest,
|
|
9
|
-
createGenerationStream,
|
|
10
|
-
} from '@dxos/assistant';
|
|
11
|
-
|
|
12
|
-
import { createTestSSEStream } from './test-stream';
|
|
13
|
-
|
|
14
|
-
export class MockAIService implements AIServiceClient {
|
|
15
|
-
constructor(private readonly _responses: string[]) {}
|
|
16
|
-
|
|
17
|
-
// TODO(burdon): Match response to request.
|
|
18
|
-
// TODO(burdon): See MockGpt (from conductor).
|
|
19
|
-
async exec(request: GenerateRequest): Promise<GenerationStream> {
|
|
20
|
-
return createGenerationStream(new Response(createTestSSEStream(this._responses)));
|
|
21
|
-
}
|
|
22
|
-
}
|