tasq/node_modules/agentic-flow/dist/sdk/streaming-input.js

336 lines
8.4 KiB
JavaScript

/**
* Streaming Input Mode - Stream prompts as async iterables
*
* Enables streaming prompts to the SDK, allowing:
* - Multi-turn conversations without separate query calls
* - Interactive user input during execution
* - Pipeline-style prompt processing
*/
import { logger } from "../utils/logger.js";
/**
* Create a user text message
*/
export function createTextMessage(text) {
return {
type: 'user',
message: {
content: [{ type: 'text', text }]
}
};
}
/**
* Create an image message from base64 data
*/
export function createImageMessage(base64Data, mediaType = 'image/png') {
return {
type: 'user',
message: {
content: [{
type: 'image',
source: {
type: 'base64',
media_type: mediaType,
data: base64Data
}
}]
}
};
}
/**
* Create a mixed content message (text + images)
*/
export function createMixedMessage(parts) {
return {
type: 'user',
message: {
content: parts.map(part => {
if (part.type === 'text') {
return { type: 'text', text: part.text };
}
else {
return {
type: 'image',
source: {
type: 'base64',
media_type: part.mediaType || 'image/png',
data: part.data
}
};
}
})
}
};
}
/**
* StreamingPromptBuilder - Build streaming prompts with fluent API
*/
export class StreamingPromptBuilder {
messages = [];
delayMs = 0;
/**
* Add a text message
*/
text(content) {
this.messages.push(createTextMessage(content));
return this;
}
/**
* Add an image message
*/
image(base64Data, mediaType) {
this.messages.push(createImageMessage(base64Data, mediaType));
return this;
}
/**
* Set delay between messages (ms)
*/
delay(ms) {
this.delayMs = ms;
return this;
}
/**
* Build async iterable for SDK
*/
build() {
const messages = this.messages;
const delayMs = this.delayMs;
return {
async *[Symbol.asyncIterator]() {
for (const message of messages) {
if (delayMs > 0) {
await new Promise(resolve => setTimeout(resolve, delayMs));
}
yield message;
}
}
};
}
}
/**
* Create a streaming prompt builder
*/
export function streamingPrompt() {
return new StreamingPromptBuilder();
}
/**
* InteractivePromptStream - Stream prompts with user input callbacks
*/
export class InteractivePromptStream {
queue = [];
waiting = [];
closed = false;
/**
* Push a message to the stream
*/
push(message) {
if (this.closed) {
throw new Error('Stream is closed');
}
if (this.waiting.length > 0) {
const resolve = this.waiting.shift();
resolve({ done: false, value: message });
}
else {
this.queue.push(message);
}
}
/**
* Push a text message
*/
pushText(text) {
this.push(createTextMessage(text));
}
/**
* Close the stream
*/
close() {
this.closed = true;
for (const resolve of this.waiting) {
resolve({ done: true });
}
this.waiting = [];
}
/**
* Check if stream is closed
*/
isClosed() {
return this.closed;
}
/**
* Get next message
*/
async next() {
if (this.queue.length > 0) {
return { done: false, value: this.queue.shift() };
}
if (this.closed) {
return { done: true };
}
return new Promise(resolve => {
this.waiting.push(resolve);
});
}
[Symbol.asyncIterator]() {
const self = this;
return {
async next() {
const result = await self.next();
if (result.done) {
return { done: true, value: undefined };
}
return { done: false, value: result.value };
}
};
}
}
/**
* Create an interactive prompt stream
*/
export function createInteractiveStream() {
return new InteractivePromptStream();
}
/**
* Pipeline prompts from multiple sources
*/
export async function* pipelinePrompts(...sources) {
for (const source of sources) {
for await (const message of source) {
yield message;
}
}
}
/**
* Create a prompt stream from an array
*/
export function fromArray(messages) {
return {
async *[Symbol.asyncIterator]() {
for (const text of messages) {
yield createTextMessage(text);
}
}
};
}
/**
* Create a prompt stream from readline (stdin)
*/
export function fromReadline(readline, prompt = '> ') {
const stream = createInteractiveStream();
readline.on('line', (line) => {
if (line.trim()) {
stream.pushText(line);
}
});
readline.on('close', () => {
stream.close();
});
// Prompt for input
process.stdout.write(prompt);
readline.on('line', () => {
if (!stream.isClosed()) {
process.stdout.write(prompt);
}
});
return stream;
}
/**
* Transform a prompt stream
*/
export function transformPrompts(source, transform) {
return {
async *[Symbol.asyncIterator]() {
for await (const message of source) {
yield await transform(message);
}
}
};
}
/**
* Filter a prompt stream
*/
export function filterPrompts(source, predicate) {
return {
async *[Symbol.asyncIterator]() {
for await (const message of source) {
if (await predicate(message)) {
yield message;
}
}
}
};
}
/**
* Rate-limit a prompt stream
*/
export function rateLimitPrompts(source, minIntervalMs) {
let lastEmit = 0;
return {
async *[Symbol.asyncIterator]() {
for await (const message of source) {
const now = Date.now();
const elapsed = now - lastEmit;
if (elapsed < minIntervalMs) {
await new Promise(resolve => setTimeout(resolve, minIntervalMs - elapsed));
}
lastEmit = Date.now();
yield message;
}
}
};
}
/**
* Batch prompts together
*/
export function batchPrompts(source, batchSize, separator = '\n\n') {
return {
async *[Symbol.asyncIterator]() {
let batch = [];
for await (const message of source) {
const text = message.message.content
.filter((c) => c.type === 'text')
.map(c => c.text)
.join(' ');
batch.push(text);
if (batch.length >= batchSize) {
yield createTextMessage(batch.join(separator));
batch = [];
}
}
if (batch.length > 0) {
yield createTextMessage(batch.join(separator));
}
}
};
}
/**
* Wrap a string or array as streaming input for SDK
*/
export function toStreamingInput(input) {
if (typeof input === 'string') {
return fromArray([input]);
}
if (Array.isArray(input)) {
return fromArray(input);
}
return input;
}
/**
* Log streaming input for debugging
*/
export function logStreamingInput(source, label = 'StreamInput') {
return {
async *[Symbol.asyncIterator]() {
let count = 0;
for await (const message of source) {
count++;
logger.debug(`[${label}] Message ${count}`, {
type: message.type,
contentTypes: message.message.content.map(c => c.type)
});
yield message;
}
logger.debug(`[${label}] Stream completed`, { total: count });
}
};
}
//# sourceMappingURL=streaming-input.js.map