@recombine-ai/engine 1.0.0-beta-3 → 1.0.0-beta-4
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/build/lib/interfaces/stream.d.ts +2 -16
- package/build/lib/interfaces/stream.d.ts.map +1 -1
- package/build/lib/stream/engine.d.ts +1 -1
- package/build/lib/stream/engine.d.ts.map +1 -1
- package/build/lib/stream/engine.js +60 -110
- package/build/lib/stream/index.d.ts +1 -1
- package/build/lib/stream/index.d.ts.map +1 -1
- package/build/lib/stream/token-transformers.d.ts +6 -0
- package/build/lib/stream/token-transformers.d.ts.map +1 -0
- package/build/lib/stream/token-transformers.js +62 -0
- package/package.json +1 -1
- package/build/lib/interfaces/ai.d.ts +0 -1
- package/build/lib/interfaces/ai.d.ts.map +0 -1
- package/build/lib/interfaces/ai.js +0 -1
- package/build/lib/stream/filter.d.ts +0 -6
- package/build/lib/stream/filter.d.ts.map +0 -1
- package/build/lib/stream/filter.js +0 -20
|
@@ -30,15 +30,13 @@ export interface StreamWorkflowConfig<CTX> {
|
|
|
30
30
|
/** LLM model with streaming support */
|
|
31
31
|
model: LlmStreamAdapter;
|
|
32
32
|
onError: (error: Error | string, ctx: CTX) => Promise<void>;
|
|
33
|
-
/**
|
|
34
|
-
|
|
33
|
+
/** transform LLM-tokens on the fly */
|
|
34
|
+
tokenTransformers?: (() => TransformStream<string, string>)[];
|
|
35
35
|
}
|
|
36
36
|
export interface Transcript {
|
|
37
37
|
responseChunks: ResponseChunk[];
|
|
38
38
|
messages: Message[];
|
|
39
39
|
readonly currentResponse: string;
|
|
40
|
-
readonly mainResponseFinished: boolean;
|
|
41
|
-
markMainResponseFinished(): void;
|
|
42
40
|
toString(ignoreDirectives?: boolean): string;
|
|
43
41
|
getConversation(): Message[];
|
|
44
42
|
}
|
|
@@ -52,18 +50,6 @@ export interface LlmStreamAdapter {
|
|
|
52
50
|
/** Returns adapter's configuration/options for tracing */
|
|
53
51
|
getOptions: () => unknown;
|
|
54
52
|
}
|
|
55
|
-
export interface ProgrammaticFilter {
|
|
56
|
-
shouldStartFiltering: (state: Transcript, newToken: string) => boolean;
|
|
57
|
-
onNewToken: (state: Transcript, filteredTokens: string[]) => {
|
|
58
|
-
action: 'CONTINUE_FILTERING';
|
|
59
|
-
} | {
|
|
60
|
-
action: 'RELEASE_TOKENS';
|
|
61
|
-
tokens: string[];
|
|
62
|
-
};
|
|
63
|
-
onStreamEnd: (state: Transcript, filteredTokens: string[]) => {
|
|
64
|
-
tokensToRelease: string[];
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
53
|
export interface ResponseChunk {
|
|
68
54
|
role: 'agent' | 'system';
|
|
69
55
|
delta: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../../src/lib/interfaces/stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAEhC,MAAM,WAAW,cAAc,CAAC,GAAG,SAAS,EAAE;IAC1C,iCAAiC;IACjC,cAAc,EAAE,CAAC,MAAM,EAAE,oBAAoB,CAAC,GAAG,CAAC,KAAK;QACnD;;;;;WAKG;QACH,GAAG,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC,CAAA;KACjF,CAAA;CACJ;AAED,MAAM,WAAW,qBAAqB;IAClC,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,+DAA+D;IAC/D,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B,iGAAiG;IACjG,UAAU,CAAC,EAAE,UAAU,CAAA;CAC1B;AAED,MAAM,WAAW,oBAAoB,CAAC,GAAG;IACrC,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAA;IACZ,oBAAoB;IACpB,MAAM,EAAE,MAAM,GAAG,UAAU,CAAA;IAC3B,uCAAuC;IACvC,KAAK,EAAE,gBAAgB,CAAA;IACvB,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3D,
|
|
1
|
+
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../../src/lib/interfaces/stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAEhC,MAAM,WAAW,cAAc,CAAC,GAAG,SAAS,EAAE;IAC1C,iCAAiC;IACjC,cAAc,EAAE,CAAC,MAAM,EAAE,oBAAoB,CAAC,GAAG,CAAC,KAAK;QACnD;;;;;WAKG;QACH,GAAG,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC,CAAA;KACjF,CAAA;CACJ;AAED,MAAM,WAAW,qBAAqB;IAClC,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,+DAA+D;IAC/D,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B,iGAAiG;IACjG,UAAU,CAAC,EAAE,UAAU,CAAA;CAC1B;AAED,MAAM,WAAW,oBAAoB,CAAC,GAAG;IACrC,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAA;IACZ,oBAAoB;IACpB,MAAM,EAAE,MAAM,GAAG,UAAU,CAAA;IAC3B,uCAAuC;IACvC,KAAK,EAAE,gBAAgB,CAAA;IACvB,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3D,sCAAsC;IACtC,iBAAiB,CAAC,EAAE,CAAC,MAAM,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAA;CAChE;AAED,MAAM,WAAW,UAAU;IACvB,cAAc,EAAE,aAAa,EAAE,CAAA;IAC/B,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IAC5C,eAAe,IAAI,OAAO,EAAE,CAAA;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC7B;;;;OAIG;IACH,cAAc,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAA;IAC3F,0DAA0D;IAC1D,UAAU,EAAE,MAAM,OAAO,CAAA;CAC5B;AAED,MAAM,WAAW,aAAa;IAC1B,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAA;IACxB,KAAK,EAAE,MAAM,CAAA;CAChB"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { AIStreamEngine, StreamingEngineConfig } from '../interfaces
|
|
1
|
+
import { AIStreamEngine, StreamingEngineConfig } from '../interfaces';
|
|
2
2
|
export declare function createAIStreamEngine<CTX extends {}>(cfg: StreamingEngineConfig): AIStreamEngine<CTX>;
|
|
3
3
|
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/lib/stream/engine.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/lib/stream/engine.ts"],"names":[],"mappings":"AAKA,OAAO,EAGH,cAAc,EAEd,qBAAqB,EAGxB,MAAM,eAAe,CAAA;AAItB,wBAAgB,oBAAoB,CAAC,GAAG,SAAS,EAAE,EAC/C,GAAG,EAAE,qBAAqB,GAC3B,cAAc,CAAC,GAAG,CAAC,CAgJrB"}
|
|
@@ -7,10 +7,10 @@ exports.createAIStreamEngine = createAIStreamEngine;
|
|
|
7
7
|
// cspell:words TTFT lstrip
|
|
8
8
|
const nunjucks_1 = __importDefault(require("nunjucks"));
|
|
9
9
|
const bosun_1 = require("../bosun");
|
|
10
|
-
const filter_1 = require("./filter");
|
|
11
10
|
const step_registry_1 = require("../bosun/step-registry");
|
|
11
|
+
const token_transformers_1 = require("./token-transformers");
|
|
12
12
|
function createAIStreamEngine(cfg) {
|
|
13
|
-
function createWorkflow({ name, prompt, model,
|
|
13
|
+
function createWorkflow({ name, prompt, model, tokenTransformers = [token_transformers_1.agentFilter], onError, }) {
|
|
14
14
|
const logger = cfg.logger || console;
|
|
15
15
|
logger.debug('streamAiEngine.createWorkflow');
|
|
16
16
|
const stepTracer = cfg.stepTracer || (0, bosun_1.createStubStepTracer)(logger);
|
|
@@ -20,48 +20,17 @@ function createAIStreamEngine(cfg) {
|
|
|
20
20
|
prompt: (0, step_registry_1.stdPrompt)(prompt),
|
|
21
21
|
});
|
|
22
22
|
async function run(messages, ctx) {
|
|
23
|
-
let streamCancelled = false;
|
|
24
|
-
return new ReadableStream({
|
|
25
|
-
cancel: (reason) => {
|
|
26
|
-
logger.debug(`streamingWorkflow.run cancelled: ${reason}`);
|
|
27
|
-
streamCancelled = true;
|
|
28
|
-
},
|
|
29
|
-
start: async (controller) => {
|
|
30
|
-
try {
|
|
31
|
-
const stream = await generateResponseStream(messages, ctx);
|
|
32
|
-
for await (const chunk of stream) {
|
|
33
|
-
if (streamCancelled)
|
|
34
|
-
return;
|
|
35
|
-
controller.enqueue(chunk);
|
|
36
|
-
}
|
|
37
|
-
if (streamCancelled)
|
|
38
|
-
return;
|
|
39
|
-
controller.close();
|
|
40
|
-
}
|
|
41
|
-
catch (e) {
|
|
42
|
-
if (streamCancelled) {
|
|
43
|
-
logger.debug('streamingWorkflow.run will not propagate error due to stream cancellation', e);
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
controller.error(e);
|
|
47
|
-
await onError(e, ctx);
|
|
48
|
-
}
|
|
49
|
-
},
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
async function generateResponseStream(messages, ctx) {
|
|
53
23
|
const runId = crypto.randomUUID();
|
|
54
24
|
logger.debug(`streamingWorkflow.run runId: ${runId}`);
|
|
55
25
|
const startTime = performance.now();
|
|
56
26
|
const transcript = createTranscript(logger, messages);
|
|
57
|
-
|
|
58
|
-
let filteredTokens = [];
|
|
27
|
+
const initiatedTransformers = tokenTransformers.map((init) => init());
|
|
59
28
|
// Create step trace for telescope
|
|
60
29
|
const mainStepTrace = {
|
|
61
30
|
workflowId: name,
|
|
62
31
|
workflowRunId: runId,
|
|
63
32
|
name: name,
|
|
64
|
-
model:
|
|
33
|
+
model: JSON.stringify(model.getOptions()),
|
|
65
34
|
createdAt: Date.now(),
|
|
66
35
|
response: '',
|
|
67
36
|
};
|
|
@@ -75,79 +44,68 @@ function createAIStreamEngine(cfg) {
|
|
|
75
44
|
}
|
|
76
45
|
catch (error) {
|
|
77
46
|
logger.error('AI Engine Stream: LLM error', { error });
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
47
|
+
mainStepTrace.error = error instanceof Error ? error : new Error(String(error));
|
|
48
|
+
stepTracer.addStepTrace(mainStepTrace);
|
|
49
|
+
await stepTracer.flush();
|
|
50
|
+
await onError(error, ctx);
|
|
51
|
+
return new ReadableStream({
|
|
52
|
+
start(controller) {
|
|
53
|
+
controller.error(error);
|
|
54
|
+
},
|
|
55
|
+
});
|
|
84
56
|
}
|
|
85
|
-
|
|
57
|
+
return mainStepStream
|
|
58
|
+
.pipeThrough(metrics(startTime))
|
|
59
|
+
.pipeThrough((0, token_transformers_1.composeTokenTransformers)(initiatedTransformers))
|
|
60
|
+
.pipeThrough(packageAsResponseChunk())
|
|
61
|
+
.pipeThrough(pushToTranscript(transcript))
|
|
62
|
+
.pipeThrough(flushTrace(mainStepTrace, transcript));
|
|
63
|
+
}
|
|
64
|
+
function metrics(startTime) {
|
|
86
65
|
let measureTtft = true;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
logger.debug(`streamingWorkflow.generateResponseStream cancelled: ${reason}`);
|
|
91
|
-
streamCancelled = true;
|
|
66
|
+
return new TransformStream({
|
|
67
|
+
start() {
|
|
68
|
+
logger.debug(`[MARK] LLM stream created: ${(performance.now() - startTime).toFixed(2)}ms`);
|
|
92
69
|
},
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
logger.debug(`[MARK] TTFT: ${(performance.now() - startTime).toFixed(2)}ms`);
|
|
98
|
-
measureTtft = false;
|
|
99
|
-
}
|
|
100
|
-
const delta = chunk;
|
|
101
|
-
if (!delta) {
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
let tokensToRelease = [];
|
|
105
|
-
if (currentFilter) {
|
|
106
|
-
filteredTokens.push(delta);
|
|
107
|
-
const filterResult = currentFilter.onNewToken(transcript, filteredTokens);
|
|
108
|
-
if (filterResult.action === 'RELEASE_TOKENS') {
|
|
109
|
-
logger.debug('streamingWorkflow.run: programmatic filter releasing tokens: ', JSON.stringify(filterResult.tokens));
|
|
110
|
-
tokensToRelease = filterResult.tokens;
|
|
111
|
-
currentFilter = null;
|
|
112
|
-
filteredTokens = [];
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
else if (filter?.shouldStartFiltering(transcript, delta)) {
|
|
116
|
-
filteredTokens = [delta];
|
|
117
|
-
currentFilter = filter;
|
|
118
|
-
logger.debug('streamingWorkflow.run: programmatic filter is applied on token: ', delta);
|
|
119
|
-
}
|
|
120
|
-
else {
|
|
121
|
-
tokensToRelease = [delta];
|
|
122
|
-
}
|
|
123
|
-
releaseMainStreamTokens(tokensToRelease);
|
|
70
|
+
transform(chunk, controller) {
|
|
71
|
+
if (measureTtft) {
|
|
72
|
+
logger.debug(`[MARK] TTFT: ${(performance.now() - startTime).toFixed(2)}ms`);
|
|
73
|
+
measureTtft = false;
|
|
124
74
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
75
|
+
controller.enqueue(chunk);
|
|
76
|
+
},
|
|
77
|
+
flush() {
|
|
78
|
+
logger.debug(`[MARK] LLM stream finished: ${(performance.now() - startTime).toFixed(2)}`);
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function packageAsResponseChunk() {
|
|
83
|
+
return new TransformStream({
|
|
84
|
+
transform(chunk, controller) {
|
|
85
|
+
controller.enqueue({ role: 'agent', delta: chunk });
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
function pushToTranscript(transcript) {
|
|
90
|
+
return new TransformStream({
|
|
91
|
+
transform(chunk, controller) {
|
|
92
|
+
transcript.responseChunks.push(chunk);
|
|
93
|
+
controller.enqueue(chunk);
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function flushTrace(mainStepTrace, transcript) {
|
|
98
|
+
return new TransformStream({
|
|
99
|
+
async flush() {
|
|
144
100
|
// Add step trace and flush to telescope
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
101
|
+
mainStepTrace.response = transcript.currentResponse;
|
|
102
|
+
stepTracer.addStepTrace(mainStepTrace);
|
|
103
|
+
try {
|
|
104
|
+
await stepTracer.flush();
|
|
105
|
+
}
|
|
106
|
+
catch (e) {
|
|
107
|
+
logger.error('stepTracer.flush failed', { error: e });
|
|
149
108
|
}
|
|
150
|
-
await stepTracer.flush();
|
|
151
109
|
},
|
|
152
110
|
});
|
|
153
111
|
}
|
|
@@ -174,7 +132,6 @@ function createAIStreamEngine(cfg) {
|
|
|
174
132
|
};
|
|
175
133
|
}
|
|
176
134
|
function createTranscript(logger, initialMessages) {
|
|
177
|
-
let finished = false;
|
|
178
135
|
const messages = [...initialMessages];
|
|
179
136
|
const directivesFormatter = (msg) => `${msg.sender}: ${msg.text}`;
|
|
180
137
|
const currentResponseFormatter = (partial) => `Current response: ${partial}`;
|
|
@@ -192,16 +149,9 @@ function createTranscript(logger, initialMessages) {
|
|
|
192
149
|
.map((token) => token?.delta)
|
|
193
150
|
.join('');
|
|
194
151
|
},
|
|
195
|
-
get mainResponseFinished() {
|
|
196
|
-
return finished;
|
|
197
|
-
},
|
|
198
152
|
get messages() {
|
|
199
153
|
return initialMessages;
|
|
200
154
|
},
|
|
201
|
-
markMainResponseFinished() {
|
|
202
|
-
logger.debug('Conversation, markMainResponseFinished');
|
|
203
|
-
finished = true;
|
|
204
|
-
},
|
|
205
155
|
toString(ignoreDirectives = false) {
|
|
206
156
|
const serializedMessages = messages
|
|
207
157
|
.map((msg) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { createAIStreamEngine } from './engine';
|
|
2
|
-
export { AIStreamEngine,
|
|
2
|
+
export { AIStreamEngine, LlmStreamAdapter, ResponseChunk, Transcript, StreamingEngineConfig, StreamWorkflowConfig as StreamingWorkflowConfig, } from '../interfaces/stream';
|
|
3
3
|
export { getAzureClient, getOpenAiClient } from './get-client';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/stream/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAE/C,OAAO,EACH,cAAc,EACd,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/stream/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAE/C,OAAO,EACH,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,UAAU,EACV,qBAAqB,EACrB,oBAAoB,IAAI,uBAAuB,GAClD,MAAM,sBAAsB,CAAA;AAE7B,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare class MessageStartFilter extends TransformStream<string, string> {
|
|
2
|
+
constructor(toRemove: string);
|
|
3
|
+
}
|
|
4
|
+
export declare function agentFilter(): MessageStartFilter;
|
|
5
|
+
export declare function composeTokenTransformers(transformers: TransformStream<string, string>[]): TransformStream<string, string>;
|
|
6
|
+
//# sourceMappingURL=token-transformers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-transformers.d.ts","sourceRoot":"","sources":["../../../src/lib/stream/token-transformers.ts"],"names":[],"mappings":"AAAA,qBAAa,kBAAmB,SAAQ,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC;gBACvD,QAAQ,EAAE,MAAM;CA2C/B;AAED,wBAAgB,WAAW,uBAE1B;AAED,wBAAgB,wBAAwB,CACpC,YAAY,EAAE,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAChD,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,CAYjC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MessageStartFilter = void 0;
|
|
4
|
+
exports.agentFilter = agentFilter;
|
|
5
|
+
exports.composeTokenTransformers = composeTokenTransformers;
|
|
6
|
+
class MessageStartFilter extends TransformStream {
|
|
7
|
+
constructor(toRemove) {
|
|
8
|
+
const prefix = toRemove.toLowerCase();
|
|
9
|
+
let buffer = '';
|
|
10
|
+
let done = false;
|
|
11
|
+
const releaseChunks = (controller) => {
|
|
12
|
+
done = true;
|
|
13
|
+
const out = buffer.toLowerCase().startsWith(prefix)
|
|
14
|
+
? buffer.slice(toRemove.length)
|
|
15
|
+
: buffer;
|
|
16
|
+
if (out) {
|
|
17
|
+
controller.enqueue(out);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
super({
|
|
21
|
+
transform(chunk, controller) {
|
|
22
|
+
if (done) {
|
|
23
|
+
// just pass through
|
|
24
|
+
controller.enqueue(chunk);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
buffer += chunk;
|
|
28
|
+
if (buffer.length >= prefix.length) {
|
|
29
|
+
// Seen enough to know for certain.
|
|
30
|
+
releaseChunks(controller);
|
|
31
|
+
}
|
|
32
|
+
else if (!prefix.startsWith(buffer.toLowerCase())) {
|
|
33
|
+
// Still short, but already diverged — no point waiting for more.
|
|
34
|
+
releaseChunks(controller);
|
|
35
|
+
}
|
|
36
|
+
// else: still a viable partial prefix → keep buffering
|
|
37
|
+
},
|
|
38
|
+
flush(controller) {
|
|
39
|
+
// Stream ended before we ever reached a decision.
|
|
40
|
+
if (!done && buffer) {
|
|
41
|
+
releaseChunks(controller);
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.MessageStartFilter = MessageStartFilter;
|
|
48
|
+
function agentFilter() {
|
|
49
|
+
return new MessageStartFilter('agent:');
|
|
50
|
+
}
|
|
51
|
+
function composeTokenTransformers(transformers) {
|
|
52
|
+
if (transformers.length === 0) {
|
|
53
|
+
// Empty pipeline = pass strings through unchanged.
|
|
54
|
+
return new TransformStream();
|
|
55
|
+
}
|
|
56
|
+
const writable = transformers[0].writable;
|
|
57
|
+
let readable = transformers[0].readable;
|
|
58
|
+
for (let i = 1; i < transformers.length; i++) {
|
|
59
|
+
readable = readable.pipeThrough(transformers[i]);
|
|
60
|
+
}
|
|
61
|
+
return { writable, readable };
|
|
62
|
+
}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
//# sourceMappingURL=ai.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../../src/lib/interfaces/ai.ts"],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../../src/lib/stream/filter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAEzD;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,kBAc3B,CAAA"}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.defaultFilter = void 0;
|
|
4
|
-
/**
|
|
5
|
-
* filter out 'Agent:' at the beginning of the llm response
|
|
6
|
-
*/
|
|
7
|
-
exports.defaultFilter = {
|
|
8
|
-
shouldStartFiltering(state, newToken) {
|
|
9
|
-
return state.currentResponse.trim().length === 0 && newToken.toLowerCase() === 'agent';
|
|
10
|
-
},
|
|
11
|
-
onNewToken(_state, filteredTokens) {
|
|
12
|
-
if (filteredTokens.length >= 2 && filteredTokens[1] === ':') {
|
|
13
|
-
return { action: 'RELEASE_TOKENS', tokens: filteredTokens.slice(2) };
|
|
14
|
-
}
|
|
15
|
-
return { action: 'RELEASE_TOKENS', tokens: filteredTokens };
|
|
16
|
-
},
|
|
17
|
-
onStreamEnd(_state, filteredTokens) {
|
|
18
|
-
return { tokensToRelease: filteredTokens };
|
|
19
|
-
},
|
|
20
|
-
};
|