@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.
@@ -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
- /** filter out some tokens on the fly */
34
- filter?: ProgrammaticFilter;
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,wCAAwC;IACxC,MAAM,CAAC,EAAE,kBAAkB,CAAA;CAC9B;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,oBAAoB,EAAE,OAAO,CAAA;IACtC,wBAAwB,IAAI,IAAI,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,kBAAkB;IAC/B,oBAAoB,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAA;IACtE,UAAU,EAAE,CACR,KAAK,EAAE,UAAU,EACjB,cAAc,EAAE,MAAM,EAAE,KACvB;QAAE,MAAM,EAAE,oBAAoB,CAAA;KAAE,GAAG;QAAE,MAAM,EAAE,gBAAgB,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAA;IACtF,WAAW,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK;QAAE,eAAe,EAAE,MAAM,EAAE,CAAA;KAAE,CAAA;CAC9F;AAED,MAAM,WAAW,aAAa;IAC1B,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAA;IACxB,KAAK,EAAE,MAAM,CAAA;CAChB"}
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/stream';
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":"AAMA,OAAO,EACH,cAAc,EAGd,qBAAqB,EAGxB,MAAM,sBAAsB,CAAA;AAI7B,wBAAgB,oBAAoB,CAAC,GAAG,SAAS,EAAE,EAC/C,GAAG,EAAE,qBAAqB,GAC3B,cAAc,CAAC,GAAG,CAAC,CAuMrB"}
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, filter = filter_1.defaultFilter, onError, }) {
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
- let currentFilter = null;
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: String(model.getOptions()),
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
- if (mainStepTrace) {
79
- mainStepTrace.error = error instanceof Error ? error : new Error(String(error));
80
- cfg.stepTracer?.addStepTrace(mainStepTrace);
81
- await cfg.stepTracer?.flush();
82
- }
83
- throw error;
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
- logger.debug(`[MARK] stream created: ${(performance.now() - startTime).toFixed(2)}ms`);
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
- let streamCancelled = false;
88
- return new ReadableStream({
89
- cancel: (reason) => {
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
- async start(controller) {
94
- logger.debug('streamingWorkflow.run: starting main stream');
95
- for await (const chunk of mainStepStream) {
96
- if (measureTtft) {
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
- if (currentFilter) {
126
- // stream has ended, but the filter still has some tokens to release
127
- releaseMainStreamTokens(currentFilter.onStreamEnd(transcript, filteredTokens).tokensToRelease);
128
- currentFilter = null;
129
- filteredTokens = [];
130
- }
131
- function releaseMainStreamTokens(tokens) {
132
- for (const token of tokens) {
133
- if (streamCancelled) {
134
- break;
135
- }
136
- transcript.responseChunks.push({ role: 'agent', delta: token });
137
- controller.enqueue({ role: 'agent', delta: token });
138
- }
139
- }
140
- logger.debug('streamingWorkflow.run: markMainResponseFinished', {
141
- elapsedMs: (performance.now() - startTime).toFixed(2),
142
- });
143
- transcript.markMainResponseFinished();
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
- cfg.stepTracer?.addStepTrace(mainStepTrace);
146
- await cfg.stepTracer?.flush();
147
- if (!streamCancelled) {
148
- controller.close();
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, ProgrammaticFilter, LlmStreamAdapter, ResponseChunk, Transcript, StreamingEngineConfig, StreamWorkflowConfig as StreamingWorkflowConfig, } from '../interfaces/stream';
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,kBAAkB,EAClB,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"}
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@recombine-ai/engine",
3
- "version": "1.0.0-beta-3",
3
+ "version": "1.0.0-beta-4",
4
4
  "description": "Recombine AI engine for creating conversational AI agents",
5
5
  "repository": {
6
6
  "url": "git+https://github.com/recombine-ai/engine.git"
@@ -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,6 +0,0 @@
1
- import { ProgrammaticFilter } from '../interfaces/stream';
2
- /**
3
- * filter out 'Agent:' at the beginning of the llm response
4
- */
5
- export declare const defaultFilter: ProgrammaticFilter;
6
- //# sourceMappingURL=filter.d.ts.map
@@ -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
- };