melony 0.3.2 → 0.3.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/dist/{chunk-OQTLZW4W.js → chunk-2LVJG7WL.js} +30 -8
- package/dist/chunk-2LVJG7WL.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/client.d.ts +9 -3
- package/dist/client.js +1 -1
- package/dist/{generate-id-wXNQEJ8t.d.ts → generate-id-DOokX68f.d.ts} +6 -31
- package/dist/index.d.ts +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-OQTLZW4W.js.map +0 -1
|
@@ -3,7 +3,6 @@ import { generateId } from './chunk-WAI5H335.js';
|
|
|
3
3
|
// src/client.ts
|
|
4
4
|
var MelonyClient = class {
|
|
5
5
|
constructor(options) {
|
|
6
|
-
this.lastServerState = null;
|
|
7
6
|
this.abortController = null;
|
|
8
7
|
this.stateListeners = /* @__PURE__ */ new Set();
|
|
9
8
|
this.url = options.url;
|
|
@@ -64,10 +63,33 @@ var MelonyClient = class {
|
|
|
64
63
|
if (!runResponse.ok)
|
|
65
64
|
throw new Error(`HTTP error! status: ${runResponse.status}`);
|
|
66
65
|
const { runId, threadId } = await runResponse.json();
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (
|
|
70
|
-
|
|
66
|
+
yield* this.stream({ runId, threadId });
|
|
67
|
+
} catch (err) {
|
|
68
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
69
|
+
this.setState({ streaming: false });
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
73
|
+
this.setState({ error, streaming: false });
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Stream events from a specific run or thread.
|
|
79
|
+
*/
|
|
80
|
+
async *stream(filter) {
|
|
81
|
+
if (this.abortController) this.abortController.abort();
|
|
82
|
+
this.abortController = new AbortController();
|
|
83
|
+
this.setState({
|
|
84
|
+
streaming: true,
|
|
85
|
+
error: null
|
|
86
|
+
});
|
|
87
|
+
try {
|
|
88
|
+
const headers = await this.getRequestHeaders();
|
|
89
|
+
const streamUrl = new URL(`${this.url}/stream`);
|
|
90
|
+
if (filter.runId) streamUrl.searchParams.set("runId", filter.runId);
|
|
91
|
+
if (filter.threadId) streamUrl.searchParams.set("threadId", filter.threadId);
|
|
92
|
+
const response = await fetch(streamUrl.toString(), {
|
|
71
93
|
headers: {
|
|
72
94
|
...headers,
|
|
73
95
|
"Accept": "text/event-stream"
|
|
@@ -93,7 +115,7 @@ var MelonyClient = class {
|
|
|
93
115
|
const handled = this.handleIncomingEvent(incomingEvent);
|
|
94
116
|
if (!handled) continue;
|
|
95
117
|
yield incomingEvent;
|
|
96
|
-
if (incomingEvent.type === "run:status
|
|
118
|
+
if (incomingEvent.type === "run:status") {
|
|
97
119
|
const data = incomingEvent.data;
|
|
98
120
|
if (data?.status === "completed" || data?.status === "failed") {
|
|
99
121
|
this.setState({ streaming: false });
|
|
@@ -145,5 +167,5 @@ var MelonyClient = class {
|
|
|
145
167
|
};
|
|
146
168
|
|
|
147
169
|
export { MelonyClient };
|
|
148
|
-
//# sourceMappingURL=chunk-
|
|
149
|
-
//# sourceMappingURL=chunk-
|
|
170
|
+
//# sourceMappingURL=chunk-2LVJG7WL.js.map
|
|
171
|
+
//# sourceMappingURL=chunk-2LVJG7WL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"chunk-2LVJG7WL.js","sourcesContent":["import { Event } from \"./types\";\nimport { generateId } from \"./utils/generate-id\";\n\nexport type { Event };\nexport { generateId };\n\nexport interface ClientState<TEvent extends Event = Event> {\n events: TEvent[];\n streaming: boolean;\n error: Error | null;\n context: Record<string, any>;\n}\n\nexport interface MelonyClientOptions<TEvent extends Event = Event> {\n url: string;\n initialEvents?: TEvent[];\n initialContext?: Record<string, any>;\n headers?:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>);\n}\n\nexport class MelonyClient<TEvent extends Event = Event> {\n private state: ClientState<TEvent>;\n public readonly url: string;\n private headers?: MelonyClientOptions<TEvent>[\"headers\"];\n private abortController: AbortController | null = null;\n private stateListeners: Set<(state: ClientState<TEvent>) => void> = new Set();\n\n constructor(options: MelonyClientOptions<TEvent>) {\n this.url = options.url;\n this.headers = options.headers;\n this.state = {\n events: options.initialEvents ?? [],\n streaming: false,\n error: null,\n context: options.initialContext ?? {},\n };\n }\n\n subscribe(listener: (state: ClientState<TEvent>) => void) {\n this.stateListeners.add(listener);\n return () => {\n this.stateListeners.delete(listener);\n };\n }\n\n getState() {\n return { ...this.state };\n }\n\n private async getRequestHeaders() {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n if (this.headers) {\n const extraHeaders =\n typeof this.headers === \"function\"\n ? await this.headers()\n : this.headers;\n Object.assign(headers, extraHeaders);\n }\n return headers;\n }\n\n private setState(updates: Partial<ClientState<TEvent>>) {\n this.state = { ...this.state, ...updates };\n this.stateListeners.forEach((l) => l(this.getState()));\n }\n\n async *send(\n event: TEvent,\n additionalBody?: Record<string, any>\n ): AsyncGenerator<TEvent> {\n if (this.abortController) this.abortController.abort();\n this.abortController = new AbortController();\n\n const optimisticEvent: TEvent = {\n id: generateId(),\n ...event\n } as TEvent;\n\n this.setState({\n streaming: true,\n error: null,\n events: [...this.state.events, optimisticEvent],\n });\n\n try {\n const headers = await this.getRequestHeaders();\n \n // 1. Create a Run\n const runResponse = await fetch(`${this.url}/runs`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n event: optimisticEvent,\n ...additionalBody,\n }),\n signal: this.abortController.signal,\n });\n\n if (!runResponse.ok)\n throw new Error(`HTTP error! status: ${runResponse.status}`);\n \n const { runId, threadId } = await runResponse.json();\n yield* this.stream({ runId, threadId });\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") {\n this.setState({ streaming: false });\n return;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n this.setState({ error, streaming: false });\n throw error;\n }\n }\n\n /**\n * Stream events from a specific run or thread.\n */\n async *stream(filter: { runId?: string; threadId?: string }): AsyncGenerator<TEvent> {\n if (this.abortController) this.abortController.abort();\n this.abortController = new AbortController();\n\n this.setState({\n streaming: true,\n error: null,\n });\n\n try {\n const headers = await this.getRequestHeaders();\n const streamUrl = new URL(`${this.url}/stream`);\n if (filter.runId) streamUrl.searchParams.set(\"runId\", filter.runId);\n if (filter.threadId) streamUrl.searchParams.set(\"threadId\", filter.threadId);\n\n const response = await fetch(streamUrl.toString(), {\n headers: {\n ...headers,\n \"Accept\": \"text/event-stream\",\n },\n signal: this.abortController.signal,\n });\n\n if (!response.ok)\n throw new Error(`HTTP error! status: ${response.status}`);\n if (!response.body) throw new Error(\"No response body\");\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\\n\");\n buffer = lines.pop() || \"\";\n\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue;\n try {\n const incomingEvent: TEvent = JSON.parse(line.slice(6));\n const handled = this.handleIncomingEvent(incomingEvent);\n if (!handled) continue;\n yield incomingEvent;\n\n // If we receive a run:status event with completed/failed, we can stop\n if (incomingEvent.type === \"run:status\") {\n const data = incomingEvent.data as { status?: string };\n if (data?.status === \"completed\" || data?.status === \"failed\") {\n this.setState({ streaming: false });\n return;\n }\n }\n } catch (e) {\n console.error(\"Failed to parse event\", e);\n }\n }\n }\n this.setState({ streaming: false });\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") {\n this.setState({ streaming: false });\n return;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n this.setState({ error, streaming: false });\n throw error;\n }\n }\n\n private handleIncomingEvent(event: TEvent) {\n const events = [...this.state.events];\n\n // Replace optimistic event if IDs match, otherwise push\n const index = event.id ? events.findIndex((e) => e.id === event.id) : -1;\n if (index !== -1) {\n events[index] = event;\n } else {\n events.push(event);\n }\n\n this.setState({ events });\n return true;\n }\n\n reset(events: TEvent[] = []) {\n this.stop();\n this.setState({\n events,\n error: null,\n streaming: false,\n });\n }\n\n stop() {\n if (this.abortController) {\n this.abortController.abort();\n this.abortController = null;\n this.setState({ streaming: false });\n }\n }\n}\n"]}
|
package/dist/cli.js
CHANGED
package/dist/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { E as Event } from './generate-id-
|
|
2
|
-
export { g as generateId } from './generate-id-
|
|
1
|
+
import { E as Event } from './generate-id-DOokX68f.js';
|
|
2
|
+
export { g as generateId } from './generate-id-DOokX68f.js';
|
|
3
3
|
|
|
4
4
|
interface ClientState<TEvent extends Event = Event> {
|
|
5
5
|
events: TEvent[];
|
|
@@ -17,7 +17,6 @@ declare class MelonyClient<TEvent extends Event = Event> {
|
|
|
17
17
|
private state;
|
|
18
18
|
readonly url: string;
|
|
19
19
|
private headers?;
|
|
20
|
-
private lastServerState;
|
|
21
20
|
private abortController;
|
|
22
21
|
private stateListeners;
|
|
23
22
|
constructor(options: MelonyClientOptions<TEvent>);
|
|
@@ -31,6 +30,13 @@ declare class MelonyClient<TEvent extends Event = Event> {
|
|
|
31
30
|
private getRequestHeaders;
|
|
32
31
|
private setState;
|
|
33
32
|
send(event: TEvent, additionalBody?: Record<string, any>): AsyncGenerator<TEvent>;
|
|
33
|
+
/**
|
|
34
|
+
* Stream events from a specific run or thread.
|
|
35
|
+
*/
|
|
36
|
+
stream(filter: {
|
|
37
|
+
runId?: string;
|
|
38
|
+
threadId?: string;
|
|
39
|
+
}): AsyncGenerator<TEvent>;
|
|
34
40
|
private handleIncomingEvent;
|
|
35
41
|
reset(events?: TEvent[]): void;
|
|
36
42
|
stop(): void;
|
package/dist/client.js
CHANGED
|
@@ -25,39 +25,14 @@ declare class Runtime<TState = any, TEvent extends Event = Event> {
|
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* The core Event structure.
|
|
28
|
-
*
|
|
28
|
+
* Truly unopinionated - only 'type' is strictly required for dispatching.
|
|
29
29
|
*/
|
|
30
|
-
type Event
|
|
31
|
-
/**
|
|
32
|
-
id?: string;
|
|
33
|
-
/** The type of the event */
|
|
30
|
+
type Event = {
|
|
31
|
+
/** The type of the event (required for runtime dispatching) */
|
|
34
32
|
type: string;
|
|
35
|
-
/**
|
|
36
|
-
|
|
37
|
-
/** Optional metadata associated with the event */
|
|
38
|
-
meta?: TMeta;
|
|
39
|
-
/** Timestamp of when the event occurred */
|
|
40
|
-
timestamp?: number;
|
|
33
|
+
/** Catch-all for any other custom fields */
|
|
34
|
+
[key: string]: any;
|
|
41
35
|
};
|
|
42
|
-
/**
|
|
43
|
-
* Built-in error event emitted by the runtime.
|
|
44
|
-
*/
|
|
45
|
-
interface ErrorEvent extends Event<{
|
|
46
|
-
message: string;
|
|
47
|
-
stack?: string;
|
|
48
|
-
}> {
|
|
49
|
-
type: "error";
|
|
50
|
-
}
|
|
51
|
-
type RunStatus = "pending" | "running" | "completed" | "failed" | "suspended";
|
|
52
|
-
interface Run<TState = any, TEvent extends Event = Event> {
|
|
53
|
-
id: string;
|
|
54
|
-
threadId?: string;
|
|
55
|
-
status: RunStatus;
|
|
56
|
-
events: TEvent[];
|
|
57
|
-
state: TState;
|
|
58
|
-
startTime: number;
|
|
59
|
-
endTime?: number;
|
|
60
|
-
}
|
|
61
36
|
interface RuntimeContext<TState = any, TEvent extends Event = Event> {
|
|
62
37
|
state: TState;
|
|
63
38
|
runId: string;
|
|
@@ -85,4 +60,4 @@ interface Config<TState = any, TEvent extends Event = Event> {
|
|
|
85
60
|
|
|
86
61
|
declare const generateId: () => string;
|
|
87
62
|
|
|
88
|
-
export { type Config as C, type Event as E, type Interceptor as I, Runtime as R, type RuntimeContext as a, type
|
|
63
|
+
export { type Config as C, type Event as E, type Interceptor as I, Runtime as R, type RuntimeContext as a, type EventHandler as b, generateId as g };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { R as Runtime, E as Event, C as Config, a as RuntimeContext, I as Interceptor } from './generate-id-
|
|
2
|
-
export { b as
|
|
1
|
+
import { R as Runtime, E as Event, C as Config, a as RuntimeContext, I as Interceptor } from './generate-id-DOokX68f.js';
|
|
2
|
+
export { b as EventHandler, g as generateId } from './generate-id-DOokX68f.js';
|
|
3
3
|
|
|
4
4
|
declare const MelonyRuntime: typeof Runtime;
|
|
5
5
|
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runtime.ts","../src/melony.ts","../src/utils/create-stream-response.ts","../src/builder.ts"],"names":["event"],"mappings":"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","file":"index.js","sourcesContent":["import {\n Event,\n RuntimeContext,\n Config,\n} from \"./types\";\nimport { generateId } from \"./utils/generate-id\";\n\n/**\n * Helper to check if a value is a Melony Event.\n */\nfunction isEvent(val: any): val is Event {\n return val && typeof val === \"object\" && typeof val.type === \"string\";\n}\n\n/**\n * The Melony Runtime.\n * Fully unopinionated - processes events through handlers.\n */\nexport class Runtime<TState = any, TEvent extends Event = Event> {\n public readonly config: Config<TState, TEvent>;\n\n constructor(config: Config<TState, TEvent>) {\n this.config = config;\n }\n\n /**\n * Process an incoming event through the runtime.\n * All event processing is handled by user-defined event handlers.\n */\n public async *run(\n event: TEvent, \n options?: { state?: TState; runId?: string }\n ): AsyncGenerator<TEvent> {\n const runId = options?.runId ?? generateId();\n \n const context: RuntimeContext<TState, TEvent> = {\n state: (options?.state ?? {}) as TState,\n runtime: this,\n runId,\n suspend: (event?: TEvent) => {\n throw event || { type: \"run-suspended\", data: {} };\n },\n };\n\n try {\n // Process the incoming event through handlers\n yield* this.runEventHandlers(event, context);\n } catch (error) {\n let eventToEmit: TEvent | undefined;\n\n if (isEvent(error)) {\n eventToEmit = error as TEvent;\n } else {\n eventToEmit = {\n type: \"error\",\n data: {\n message: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n },\n } as TEvent;\n }\n\n if (eventToEmit) {\n yield* this.emit(eventToEmit, context);\n }\n }\n }\n\n\n /**\n * Run all event handlers that match the given event type.\n */\n private async *runEventHandlers(\n event: TEvent,\n context: RuntimeContext<TState, TEvent>,\n ): AsyncGenerator<TEvent> {\n let currentEvent = event;\n\n // 1. Run global interceptors first\n const globalInterceptors = this.config.interceptors.get(\"*\") || [];\n for (const interceptor of globalInterceptors) {\n const result = await interceptor(currentEvent, context);\n if (result && typeof result === \"object\" && \"type\" in result) {\n currentEvent = result as TEvent;\n }\n }\n\n // 2. Run specific interceptors for the (possibly new) event type\n // If currentEvent.type is \"*\", it's already been handled by the global interceptors\n if (currentEvent.type !== \"*\") {\n const specificInterceptors = this.config.interceptors.get(currentEvent.type) || [];\n for (const interceptor of specificInterceptors) {\n const result = await interceptor(currentEvent, context);\n if (result && typeof result === \"object\" && \"type\" in result) {\n currentEvent = result as TEvent;\n }\n }\n }\n\n const handlers = [\n ...(this.config.eventHandlers.get(\"*\") || []),\n ...(this.config.eventHandlers.get(currentEvent.type) || []),\n ];\n \n // First emit the event itself\n yield* this.emit(currentEvent, context);\n\n for (const handler of handlers) {\n const result = handler(currentEvent, context);\n if (result) {\n for await (const yieldedEvent of result) {\n // Recursively process yielded events through their handlers\n yield* this.runEventHandlers(yieldedEvent, context);\n }\n }\n }\n }\n\n /**\n * Internal helper to yield an event with metadata.\n */\n private async *emit(\n event: TEvent,\n context?: RuntimeContext<TState, TEvent>,\n ): AsyncGenerator<TEvent> {\n yield event;\n }\n}\n","import { Runtime } from \"./runtime\";\n\nexport const MelonyRuntime = Runtime;","import { Event } from \"../types\";\n\n/**\n * Convert an async generator of events to an HTTP streaming response\n * Exported for backward compatibility and standalone usage\n */\nexport function createStreamResponse(\n generator: AsyncGenerator<Event>,\n): Response {\n const encoder = new TextEncoder();\n const stream = new ReadableStream({\n async start(controller) {\n try {\n for await (const message of generator) {\n // Format as SSE: data: {...}\\n\\n\n const chunk = `data: ${JSON.stringify(message)}\\n\\n`;\n controller.enqueue(encoder.encode(chunk));\n }\n controller.close();\n } catch (error) {\n controller.error(error);\n }\n },\n });\n\n return new Response(stream, {\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n },\n });\n}\n","import {\n Event,\n EventHandler,\n Config,\n RuntimeContext,\n Interceptor,\n} from \"./types\";\nimport { Runtime } from \"./runtime\";\nimport { createStreamResponse } from \"./utils/create-stream-response\";\n\n/**\n * A Melony plugin is a function that receives the builder and extends it.\n * This allows for modularizing common handlers.\n */\nexport type MelonyPlugin<TState = any, TEvent extends Event = Event> = (\n builder: MelonyBuilder<TState, TEvent>\n) => void;\n\n/**\n * Fluent builder for creating Melony agents with excellent developer experience.\n * Provides method chaining for handlers and plugins with full TypeScript support.\n */\nexport class MelonyBuilder<\n TState = any,\n TEvent extends Event = Event\n> {\n private config: Config<TState, TEvent>;\n\n constructor(initialConfig?: Partial<Config<TState, TEvent>>) {\n this.config = {\n eventHandlers: initialConfig?.eventHandlers ?? new Map(),\n interceptors: initialConfig?.interceptors ?? new Map(),\n };\n }\n\n /**\n * Add an event handler for a specific event type. Supports method chaining.\n * The handler receives the narrowed event type based on the eventType string.\n */\n on<K extends TEvent[\"type\"]>(\n eventType: K | \"*\",\n handler: (\n event: K extends \"*\" ? TEvent : Extract<TEvent, { type: K }>,\n context: RuntimeContext<TState, TEvent>\n ) => AsyncGenerator<TEvent, void, unknown> | void\n ): this {\n if (!this.config.eventHandlers.has(eventType)) {\n this.config.eventHandlers.set(eventType, []);\n }\n // Cast is safe because runtime only calls this handler for matching event types\n this.config.eventHandlers.get(eventType)!.push(handler as EventHandler<TState, TEvent>);\n return this;\n }\n\n /**\n * Register an interceptor that runs before any handlers.\n * Useful for logging, validation, or suspending for approval.\n */\n intercept(interceptor: Interceptor<TState, TEvent>): this;\n intercept<K extends TEvent[\"type\"]>(\n eventType: K,\n interceptor: (\n event: Extract<TEvent, { type: K }>,\n context: RuntimeContext<TState, TEvent>\n ) => Promise<TEvent | void> | TEvent | void\n ): this;\n intercept(\n arg1: string | Interceptor<TState, TEvent>,\n arg2?: any\n ): this {\n if (typeof arg1 === \"string\") {\n const type = arg1;\n const interceptor = arg2!;\n if (!this.config.interceptors.has(type)) {\n this.config.interceptors.set(type, []);\n }\n this.config.interceptors.get(type)!.push(interceptor as Interceptor<TState, TEvent>);\n } else {\n const interceptor = arg1;\n if (!this.config.interceptors.has(\"*\")) {\n this.config.interceptors.set(\"*\", []);\n }\n this.config.interceptors.get(\"*\")!.push(interceptor);\n }\n return this;\n }\n\n /**\n * Use a plugin to extend the builder.\n * This is ideal for modularizing common handlers.\n */\n use(plugin: MelonyPlugin<TState, TEvent>): this {\n plugin(this);\n return this;\n }\n\n /**\n * Build and return the Melony runtime instance.\n * This is the final method in the fluent chain.\n */\n build(): Runtime<TState, TEvent> {\n return new Runtime(this.config);\n }\n\n /**\n * Execute and stream the response for an event.\n * This is a convenience method that builds the runtime and calls run().\n */\n async streamResponse(\n event: TEvent,\n options?: { state?: TState; runId?: string }\n ): Promise<Response> {\n const runtime = this.build();\n const generator = runtime.run(event, options);\n return createStreamResponse(generator);\n }\n\n /**\n * Execute the agent and return the data from the last event of a specific type as a JSON response.\n * Ideal for initialization or non-streaming requests where you only need the final UI state.\n */\n async jsonResponse(\n event: TEvent,\n options?: {\n state?: TState;\n runId?: string;\n }\n ): Promise<Response> {\n const events = [];\n const runtime = this.build();\n\n for await (const e of runtime.run(event, options)) {\n events.push(e);\n }\n\n return new Response(JSON.stringify({ events }), {\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n /**\n * Get the current configuration (useful for debugging or serialization).\n */\n getConfig(): Config<TState, TEvent> {\n return { ...this.config };\n }\n}\n\n/**\n * Factory function to create a new Melony builder instance.\n * This is the entry point for the fluent API.\n */\nexport function melony<\n TState = any,\n TEvent extends Event = Event\n>(initialConfig?: Partial<Config<TState, TEvent>>): MelonyBuilder<TState, TEvent> {\n return new MelonyBuilder<TState, TEvent>(initialConfig);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/runtime.ts","../src/melony.ts","../src/utils/create-stream-response.ts","../src/builder.ts"],"names":["event"],"mappings":";;;;AAUA,SAAS,QAAQ,GAAA,EAAwB;AACvC,EAAA,OAAO,OAAO,OAAO,GAAA,KAAQ,QAAA,IAAY,OAAO,IAAI,IAAA,KAAS,QAAA;AAC/D;AAMO,IAAM,UAAN,MAA0D;AAAA,EAG/D,YAAY,MAAA,EAAgC;AAC1C,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAc,GAAA,CACZ,KAAA,EACA,OAAA,EACwB;AACxB,IAAA,MAAM,KAAA,GAAQ,OAAA,EAAS,KAAA,IAAS,UAAA,EAAW;AAE3C,IAAA,MAAM,OAAA,GAA0C;AAAA,MAC9C,KAAA,EAAQ,OAAA,EAAS,KAAA,IAAS,EAAC;AAAA,MAC3B,OAAA,EAAS,IAAA;AAAA,MACT,KAAA;AAAA,MACA,OAAA,EAAS,CAACA,MAAAA,KAAmB;AAC3B,QAAA,MAAMA,UAAS,EAAE,IAAA,EAAM,eAAA,EAAiB,IAAA,EAAM,EAAC,EAAE;AAAA,MACnD;AAAA,KACF;AAEA,IAAA,IAAI;AAEF,MAAA,OAAO,IAAA,CAAK,gBAAA,CAAiB,KAAA,EAAO,OAAO,CAAA;AAAA,IAC7C,SAAS,KAAA,EAAO;AACd,MAAA,IAAI,WAAA;AAEJ,MAAA,IAAI,OAAA,CAAQ,KAAK,CAAA,EAAG;AAClB,QAAA,WAAA,GAAc,KAAA;AAAA,MAChB,CAAA,MAAO;AACL,QAAA,WAAA,GAAc;AAAA,UACZ,IAAA,EAAM,OAAA;AAAA,UACN,IAAA,EAAM;AAAA,YACJ,SAAS,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AAAA,YAC9D,KAAA,EAAO,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,KAAA,GAAQ;AAAA;AAChD,SACF;AAAA,MACF;AAEA,MAAA,IAAI,WAAA,EAAa;AACf,QAAA,OAAO,IAAA,CAAK,IAAA,CAAK,WAAA,EAAa,OAAO,CAAA;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,OAAe,gBAAA,CACb,KAAA,EACA,OAAA,EACwB;AACxB,IAAA,IAAI,YAAA,GAAe,KAAA;AAGnB,IAAA,MAAM,qBAAqB,IAAA,CAAK,MAAA,CAAO,aAAa,GAAA,CAAI,GAAG,KAAK,EAAC;AACjE,IAAA,KAAA,MAAW,eAAe,kBAAA,EAAoB;AAC5C,MAAA,MAAM,MAAA,GAAS,MAAM,WAAA,CAAY,YAAA,EAAc,OAAO,CAAA;AACtD,MAAA,IAAI,MAAA,IAAU,OAAO,MAAA,KAAW,QAAA,IAAY,UAAU,MAAA,EAAQ;AAC5D,QAAA,YAAA,GAAe,MAAA;AAAA,MACjB;AAAA,IACF;AAIA,IAAA,IAAI,YAAA,CAAa,SAAS,GAAA,EAAK;AAC7B,MAAA,MAAM,oBAAA,GAAuB,KAAK,MAAA,CAAO,YAAA,CAAa,IAAI,YAAA,CAAa,IAAI,KAAK,EAAC;AACjF,MAAA,KAAA,MAAW,eAAe,oBAAA,EAAsB;AAC9C,QAAA,MAAM,MAAA,GAAS,MAAM,WAAA,CAAY,YAAA,EAAc,OAAO,CAAA;AACtD,QAAA,IAAI,MAAA,IAAU,OAAO,MAAA,KAAW,QAAA,IAAY,UAAU,MAAA,EAAQ;AAC5D,UAAA,YAAA,GAAe,MAAA;AAAA,QACjB;AAAA,MACF;AAAA,IACF;AAEA,IAAA,MAAM,QAAA,GAAW;AAAA,MACf,GAAI,IAAA,CAAK,MAAA,CAAO,cAAc,GAAA,CAAI,GAAG,KAAK,EAAC;AAAA,MAC3C,GAAI,KAAK,MAAA,CAAO,aAAA,CAAc,IAAI,YAAA,CAAa,IAAI,KAAK;AAAC,KAC3D;AAGA,IAAA,OAAO,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,OAAO,CAAA;AAEtC,IAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,MAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,YAAA,EAAc,OAAO,CAAA;AAC5C,MAAA,IAAI,MAAA,EAAQ;AACV,QAAA,WAAA,MAAiB,gBAAgB,MAAA,EAAQ;AAEvC,UAAA,OAAO,IAAA,CAAK,gBAAA,CAAiB,YAAA,EAAc,OAAO,CAAA;AAAA,QACpD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAe,IAAA,CACb,KAAA,EACA,OAAA,EACwB;AACxB,IAAA,MAAM,KAAA;AAAA,EACR;AACF;;;AC7HO,IAAM,aAAA,GAAgB;;;ACItB,SAAS,qBACd,SAAA,EACU;AACV,EAAA,MAAM,OAAA,GAAU,IAAI,WAAA,EAAY;AAChC,EAAA,MAAM,MAAA,GAAS,IAAI,cAAA,CAAe;AAAA,IAChC,MAAM,MAAM,UAAA,EAAY;AACtB,MAAA,IAAI;AACF,QAAA,WAAA,MAAiB,WAAW,SAAA,EAAW;AAErC,UAAA,MAAM,KAAA,GAAQ,CAAA,MAAA,EAAS,IAAA,CAAK,SAAA,CAAU,OAAO,CAAC;;AAAA,CAAA;AAC9C,UAAA,UAAA,CAAW,OAAA,CAAQ,OAAA,CAAQ,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,QAC1C;AACA,QAAA,UAAA,CAAW,KAAA,EAAM;AAAA,MACnB,SAAS,KAAA,EAAO;AACd,QAAA,UAAA,CAAW,MAAM,KAAK,CAAA;AAAA,MACxB;AAAA,IACF;AAAA,GACD,CAAA;AAED,EAAA,OAAO,IAAI,SAAS,MAAA,EAAQ;AAAA,IAC1B,OAAA,EAAS;AAAA,MACP,cAAA,EAAgB,mBAAA;AAAA,MAChB,eAAA,EAAiB,UAAA;AAAA,MACjB,UAAA,EAAY;AAAA;AACd,GACD,CAAA;AACH;;;ACVO,IAAM,gBAAN,MAGL;AAAA,EAGA,YAAY,aAAA,EAAiD;AAC3D,IAAA,IAAA,CAAK,MAAA,GAAS;AAAA,MACZ,aAAA,EAAe,aAAA,EAAe,aAAA,oBAAiB,IAAI,GAAA,EAAI;AAAA,MACvD,YAAA,EAAc,aAAA,EAAe,YAAA,oBAAgB,IAAI,GAAA;AAAI,KACvD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,EAAA,CACE,WACA,OAAA,EAIM;AACN,IAAA,IAAI,CAAC,IAAA,CAAK,MAAA,CAAO,aAAA,CAAc,GAAA,CAAI,SAAS,CAAA,EAAG;AAC7C,MAAA,IAAA,CAAK,MAAA,CAAO,aAAA,CAAc,GAAA,CAAI,SAAA,EAAW,EAAE,CAAA;AAAA,IAC7C;AAEA,IAAA,IAAA,CAAK,OAAO,aAAA,CAAc,GAAA,CAAI,SAAS,CAAA,CAAG,KAAK,OAAuC,CAAA;AACtF,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAcA,SAAA,CACE,MACA,IAAA,EACM;AACN,IAAA,IAAI,OAAO,SAAS,QAAA,EAAU;AAC5B,MAAA,MAAM,IAAA,GAAO,IAAA;AACb,MAAA,MAAM,WAAA,GAAc,IAAA;AACpB,MAAA,IAAI,CAAC,IAAA,CAAK,MAAA,CAAO,YAAA,CAAa,GAAA,CAAI,IAAI,CAAA,EAAG;AACvC,QAAA,IAAA,CAAK,MAAA,CAAO,YAAA,CAAa,GAAA,CAAI,IAAA,EAAM,EAAE,CAAA;AAAA,MACvC;AACA,MAAA,IAAA,CAAK,OAAO,YAAA,CAAa,GAAA,CAAI,IAAI,CAAA,CAAG,KAAK,WAA0C,CAAA;AAAA,IACrF,CAAA,MAAO;AACL,MAAA,MAAM,WAAA,GAAc,IAAA;AACpB,MAAA,IAAI,CAAC,IAAA,CAAK,MAAA,CAAO,YAAA,CAAa,GAAA,CAAI,GAAG,CAAA,EAAG;AACtC,QAAA,IAAA,CAAK,MAAA,CAAO,YAAA,CAAa,GAAA,CAAI,GAAA,EAAK,EAAE,CAAA;AAAA,MACtC;AACA,MAAA,IAAA,CAAK,OAAO,YAAA,CAAa,GAAA,CAAI,GAAG,CAAA,CAAG,KAAK,WAAW,CAAA;AAAA,IACrD;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,MAAA,EAA4C;AAC9C,IAAA,MAAA,CAAO,IAAI,CAAA;AACX,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,KAAA,GAAiC;AAC/B,IAAA,OAAO,IAAI,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAA;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,cAAA,CACJ,KAAA,EACA,OAAA,EACmB;AACnB,IAAA,MAAM,OAAA,GAAU,KAAK,KAAA,EAAM;AAC3B,IAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,GAAA,CAAI,KAAA,EAAO,OAAO,CAAA;AAC5C,IAAA,OAAO,qBAAqB,SAAS,CAAA;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,YAAA,CACJ,KAAA,EACA,OAAA,EAImB;AACnB,IAAA,MAAM,SAAS,EAAC;AAChB,IAAA,MAAM,OAAA,GAAU,KAAK,KAAA,EAAM;AAE3B,IAAA,WAAA,MAAiB,CAAA,IAAK,OAAA,CAAQ,GAAA,CAAI,KAAA,EAAO,OAAO,CAAA,EAAG;AACjD,MAAA,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,IACf;AAEA,IAAA,OAAO,IAAI,QAAA,CAAS,IAAA,CAAK,UAAU,EAAE,MAAA,EAAQ,CAAA,EAAG;AAAA,MAC9C,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA;AAAmB,KAC/C,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,SAAA,GAAoC;AAClC,IAAA,OAAO,EAAE,GAAG,IAAA,CAAK,MAAA,EAAO;AAAA,EAC1B;AACF;AAMO,SAAS,OAGd,aAAA,EAAgF;AAChF,EAAA,OAAO,IAAI,cAA8B,aAAa,CAAA;AACxD","file":"index.js","sourcesContent":["import {\n Event,\n RuntimeContext,\n Config,\n} from \"./types\";\nimport { generateId } from \"./utils/generate-id\";\n\n/**\n * Helper to check if a value is a Melony Event.\n */\nfunction isEvent(val: any): val is Event {\n return val && typeof val === \"object\" && typeof val.type === \"string\";\n}\n\n/**\n * The Melony Runtime.\n * Fully unopinionated - processes events through handlers.\n */\nexport class Runtime<TState = any, TEvent extends Event = Event> {\n public readonly config: Config<TState, TEvent>;\n\n constructor(config: Config<TState, TEvent>) {\n this.config = config;\n }\n\n /**\n * Process an incoming event through the runtime.\n * All event processing is handled by user-defined event handlers.\n */\n public async *run(\n event: TEvent, \n options?: { state?: TState; runId?: string }\n ): AsyncGenerator<TEvent> {\n const runId = options?.runId ?? generateId();\n \n const context: RuntimeContext<TState, TEvent> = {\n state: (options?.state ?? {}) as TState,\n runtime: this,\n runId,\n suspend: (event?: TEvent) => {\n throw event || { type: \"run-suspended\", data: {} };\n },\n };\n\n try {\n // Process the incoming event through handlers\n yield* this.runEventHandlers(event, context);\n } catch (error) {\n let eventToEmit: TEvent | undefined;\n\n if (isEvent(error)) {\n eventToEmit = error as TEvent;\n } else {\n eventToEmit = {\n type: \"error\",\n data: {\n message: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n },\n } as unknown as TEvent;\n }\n\n if (eventToEmit) {\n yield* this.emit(eventToEmit, context);\n }\n }\n }\n\n\n /**\n * Run all event handlers that match the given event type.\n */\n private async *runEventHandlers(\n event: TEvent,\n context: RuntimeContext<TState, TEvent>,\n ): AsyncGenerator<TEvent> {\n let currentEvent = event;\n\n // 1. Run global interceptors first\n const globalInterceptors = this.config.interceptors.get(\"*\") || [];\n for (const interceptor of globalInterceptors) {\n const result = await interceptor(currentEvent, context);\n if (result && typeof result === \"object\" && \"type\" in result) {\n currentEvent = result as TEvent;\n }\n }\n\n // 2. Run specific interceptors for the (possibly new) event type\n // If currentEvent.type is \"*\", it's already been handled by the global interceptors\n if (currentEvent.type !== \"*\") {\n const specificInterceptors = this.config.interceptors.get(currentEvent.type) || [];\n for (const interceptor of specificInterceptors) {\n const result = await interceptor(currentEvent, context);\n if (result && typeof result === \"object\" && \"type\" in result) {\n currentEvent = result as TEvent;\n }\n }\n }\n\n const handlers = [\n ...(this.config.eventHandlers.get(\"*\") || []),\n ...(this.config.eventHandlers.get(currentEvent.type) || []),\n ];\n \n // First emit the event itself\n yield* this.emit(currentEvent, context);\n\n for (const handler of handlers) {\n const result = handler(currentEvent, context);\n if (result) {\n for await (const yieldedEvent of result) {\n // Recursively process yielded events through their handlers\n yield* this.runEventHandlers(yieldedEvent, context);\n }\n }\n }\n }\n\n /**\n * Internal helper to yield an event with metadata.\n */\n private async *emit(\n event: TEvent,\n context?: RuntimeContext<TState, TEvent>,\n ): AsyncGenerator<TEvent> {\n yield event;\n }\n}\n","import { Runtime } from \"./runtime\";\n\nexport const MelonyRuntime = Runtime;","import { Event } from \"../types\";\n\n/**\n * Convert an async generator of events to an HTTP streaming response\n * Exported for backward compatibility and standalone usage\n */\nexport function createStreamResponse(\n generator: AsyncGenerator<Event>,\n): Response {\n const encoder = new TextEncoder();\n const stream = new ReadableStream({\n async start(controller) {\n try {\n for await (const message of generator) {\n // Format as SSE: data: {...}\\n\\n\n const chunk = `data: ${JSON.stringify(message)}\\n\\n`;\n controller.enqueue(encoder.encode(chunk));\n }\n controller.close();\n } catch (error) {\n controller.error(error);\n }\n },\n });\n\n return new Response(stream, {\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n },\n });\n}\n","import {\n Event,\n EventHandler,\n Config,\n RuntimeContext,\n Interceptor,\n} from \"./types\";\nimport { Runtime } from \"./runtime\";\nimport { createStreamResponse } from \"./utils/create-stream-response\";\n\n/**\n * A Melony plugin is a function that receives the builder and extends it.\n * This allows for modularizing common handlers.\n */\nexport type MelonyPlugin<TState = any, TEvent extends Event = Event> = (\n builder: MelonyBuilder<TState, TEvent>\n) => void;\n\n/**\n * Fluent builder for creating Melony agents with excellent developer experience.\n * Provides method chaining for handlers and plugins with full TypeScript support.\n */\nexport class MelonyBuilder<\n TState = any,\n TEvent extends Event = Event\n> {\n private config: Config<TState, TEvent>;\n\n constructor(initialConfig?: Partial<Config<TState, TEvent>>) {\n this.config = {\n eventHandlers: initialConfig?.eventHandlers ?? new Map(),\n interceptors: initialConfig?.interceptors ?? new Map(),\n };\n }\n\n /**\n * Add an event handler for a specific event type. Supports method chaining.\n * The handler receives the narrowed event type based on the eventType string.\n */\n on<K extends TEvent[\"type\"]>(\n eventType: K | \"*\",\n handler: (\n event: K extends \"*\" ? TEvent : Extract<TEvent, { type: K }>,\n context: RuntimeContext<TState, TEvent>\n ) => AsyncGenerator<TEvent, void, unknown> | void\n ): this {\n if (!this.config.eventHandlers.has(eventType)) {\n this.config.eventHandlers.set(eventType, []);\n }\n // Cast is safe because runtime only calls this handler for matching event types\n this.config.eventHandlers.get(eventType)!.push(handler as EventHandler<TState, TEvent>);\n return this;\n }\n\n /**\n * Register an interceptor that runs before any handlers.\n * Useful for logging, validation, or suspending for approval.\n */\n intercept(interceptor: Interceptor<TState, TEvent>): this;\n intercept<K extends TEvent[\"type\"]>(\n eventType: K,\n interceptor: (\n event: Extract<TEvent, { type: K }>,\n context: RuntimeContext<TState, TEvent>\n ) => Promise<TEvent | void> | TEvent | void\n ): this;\n intercept(\n arg1: string | Interceptor<TState, TEvent>,\n arg2?: any\n ): this {\n if (typeof arg1 === \"string\") {\n const type = arg1;\n const interceptor = arg2!;\n if (!this.config.interceptors.has(type)) {\n this.config.interceptors.set(type, []);\n }\n this.config.interceptors.get(type)!.push(interceptor as Interceptor<TState, TEvent>);\n } else {\n const interceptor = arg1;\n if (!this.config.interceptors.has(\"*\")) {\n this.config.interceptors.set(\"*\", []);\n }\n this.config.interceptors.get(\"*\")!.push(interceptor);\n }\n return this;\n }\n\n /**\n * Use a plugin to extend the builder.\n * This is ideal for modularizing common handlers.\n */\n use(plugin: MelonyPlugin<TState, TEvent>): this {\n plugin(this);\n return this;\n }\n\n /**\n * Build and return the Melony runtime instance.\n * This is the final method in the fluent chain.\n */\n build(): Runtime<TState, TEvent> {\n return new Runtime(this.config);\n }\n\n /**\n * Execute and stream the response for an event.\n * This is a convenience method that builds the runtime and calls run().\n */\n async streamResponse(\n event: TEvent,\n options?: { state?: TState; runId?: string }\n ): Promise<Response> {\n const runtime = this.build();\n const generator = runtime.run(event, options);\n return createStreamResponse(generator);\n }\n\n /**\n * Execute the agent and return the data from the last event of a specific type as a JSON response.\n * Ideal for initialization or non-streaming requests where you only need the final UI state.\n */\n async jsonResponse(\n event: TEvent,\n options?: {\n state?: TState;\n runId?: string;\n }\n ): Promise<Response> {\n const events = [];\n const runtime = this.build();\n\n for await (const e of runtime.run(event, options)) {\n events.push(e);\n }\n\n return new Response(JSON.stringify({ events }), {\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n /**\n * Get the current configuration (useful for debugging or serialization).\n */\n getConfig(): Config<TState, TEvent> {\n return { ...this.config };\n }\n}\n\n/**\n * Factory function to create a new Melony builder instance.\n * This is the entry point for the fluent API.\n */\nexport function melony<\n TState = any,\n TEvent extends Event = Event\n>(initialConfig?: Partial<Config<TState, TEvent>>): MelonyBuilder<TState, TEvent> {\n return new MelonyBuilder<TState, TEvent>(initialConfig);\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"chunk-OQTLZW4W.js","sourcesContent":["import { Event } from \"./types\";\nimport { generateId } from \"./utils/generate-id\";\n\nexport type { Event };\nexport { generateId };\n\nexport interface ClientState<TEvent extends Event = Event> {\n events: TEvent[];\n streaming: boolean;\n error: Error | null;\n context: Record<string, any>;\n}\n\nexport interface MelonyClientOptions<TEvent extends Event = Event> {\n url: string;\n initialEvents?: TEvent[];\n initialContext?: Record<string, any>;\n headers?:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>);\n}\n\nexport class MelonyClient<TEvent extends Event = Event> {\n private state: ClientState<TEvent>;\n public readonly url: string;\n private headers?: MelonyClientOptions<TEvent>[\"headers\"];\n private lastServerState: any = null;\n private abortController: AbortController | null = null;\n private stateListeners: Set<(state: ClientState<TEvent>) => void> = new Set();\n\n constructor(options: MelonyClientOptions<TEvent>) {\n this.url = options.url;\n this.headers = options.headers;\n this.state = {\n events: options.initialEvents ?? [],\n streaming: false,\n error: null,\n context: options.initialContext ?? {},\n };\n }\n\n subscribe(listener: (state: ClientState<TEvent>) => void) {\n this.stateListeners.add(listener);\n return () => {\n this.stateListeners.delete(listener);\n };\n }\n\n getState() {\n return { ...this.state };\n }\n\n private async getRequestHeaders() {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n if (this.headers) {\n const extraHeaders =\n typeof this.headers === \"function\"\n ? await this.headers()\n : this.headers;\n Object.assign(headers, extraHeaders);\n }\n return headers;\n }\n\n private setState(updates: Partial<ClientState<TEvent>>) {\n this.state = { ...this.state, ...updates };\n this.stateListeners.forEach((l) => l(this.getState()));\n }\n\n async *send(\n event: TEvent,\n additionalBody?: Record<string, any>\n ): AsyncGenerator<TEvent> {\n if (this.abortController) this.abortController.abort();\n this.abortController = new AbortController();\n\n const optimisticEvent: TEvent = {\n id: generateId(),\n ...event\n } as TEvent;\n\n this.setState({\n streaming: true,\n error: null,\n events: [...this.state.events, optimisticEvent],\n });\n\n try {\n const headers = await this.getRequestHeaders();\n \n // 1. Create a Run\n const runResponse = await fetch(`${this.url}/runs`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n event: optimisticEvent,\n ...additionalBody,\n }),\n signal: this.abortController.signal,\n });\n\n if (!runResponse.ok)\n throw new Error(`HTTP error! status: ${runResponse.status}`);\n \n const { runId, threadId } = await runResponse.json();\n\n // 2. Subscribe to Events\n const eventsUrl = new URL(`${this.url}/events`);\n eventsUrl.searchParams.set(\"runId\", runId);\n if (threadId) eventsUrl.searchParams.set(\"threadId\", threadId);\n\n const response = await fetch(eventsUrl.toString(), {\n headers: {\n ...headers,\n \"Accept\": \"text/event-stream\",\n },\n signal: this.abortController.signal,\n });\n\n if (!response.ok)\n throw new Error(`HTTP error! status: ${response.status}`);\n if (!response.body) throw new Error(\"No response body\");\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\\n\");\n buffer = lines.pop() || \"\";\n\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue;\n try {\n const incomingEvent: TEvent = JSON.parse(line.slice(6));\n const handled = this.handleIncomingEvent(incomingEvent);\n if (!handled) continue;\n yield incomingEvent;\n\n // If we receive a run:status:updated event with completed/failed, we can stop\n if (incomingEvent.type === \"run:status:updated\") {\n const data = incomingEvent.data as { status?: string };\n if (data?.status === \"completed\" || data?.status === \"failed\") {\n this.setState({ streaming: false });\n return;\n }\n }\n } catch (e) {\n console.error(\"Failed to parse event\", e);\n }\n }\n }\n this.setState({ streaming: false });\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") {\n this.setState({ streaming: false });\n return;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n this.setState({ error, streaming: false });\n throw error;\n }\n }\n\n private handleIncomingEvent(event: TEvent) {\n const events = [...this.state.events];\n\n // Replace optimistic event if IDs match, otherwise push\n const index = event.id ? events.findIndex((e) => e.id === event.id) : -1;\n if (index !== -1) {\n events[index] = event;\n } else {\n events.push(event);\n }\n\n this.setState({ events });\n return true;\n }\n\n reset(events: TEvent[] = []) {\n this.stop();\n this.setState({\n events,\n error: null,\n streaming: false,\n });\n }\n\n stop() {\n if (this.abortController) {\n this.abortController.abort();\n this.abortController = null;\n this.setState({ streaming: false });\n }\n }\n}\n"]}
|