melony 0.3.4 → 0.3.5

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/README.md CHANGED
@@ -33,7 +33,7 @@ import { Runtime } from "melony";
33
33
 
34
34
  // 1. Create the runtime
35
35
  const agent = new Runtime({
36
- eventHandlers: new Map([
36
+ handlers: new Map([
37
37
  ["user:text", [async function* (event, { runtime }) {
38
38
  if (event.data.content.includes("weather")) {
39
39
  yield { type: "assistant:text", data: { content: "Weather in London is sunny!" } };
package/dist/cli.js CHANGED
@@ -1,65 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { MelonyClient } from './chunk-2LVJG7WL.js';
3
- import './chunk-WAI5H335.js';
4
2
  import 'dotenv/config';
5
- import * as readline from 'readline/promises';
6
- import * as path from 'path';
7
- import { fileURLToPath } from 'url';
8
3
  import { Command } from 'commander';
9
4
 
10
- path.dirname(fileURLToPath(import.meta.url));
11
5
  var program = new Command();
12
- program.name("melony").description("Melony CLI - Fast, minimalist AI agent framework").version("0.1.0");
13
- program.command("chat").description("Start an interactive chat session with a Melony agent").option("-u, --url <url>", "Server URL", process.env.MELONY_SERVER_URL ?? "http://localhost:4001/api/chat").action(async (options) => {
14
- const client = new MelonyClient({
15
- url: options.url
16
- });
17
- const rl = readline.createInterface({
18
- input: process.stdin,
19
- output: process.stdout
20
- });
21
- console.log("------------------------------------------");
22
- console.log("\u{1F34E} Melony Interactive CLI");
23
- console.log(`Connected to: ${options.url}`);
24
- console.log("Type your message and press Enter. Type 'exit' to quit.");
25
- console.log("------------------------------------------");
26
- while (true) {
27
- const input = await rl.question("\nYou: ");
28
- if (input.toLowerCase() === "exit" || input.toLowerCase() === "quit") {
29
- break;
30
- }
31
- if (!input.trim()) continue;
32
- process.stdout.write("Agent: ");
33
- try {
34
- const stream = client.send({
35
- type: "user:text",
36
- data: { content: input }
37
- });
38
- let fullResponse = "";
39
- for await (const event of stream) {
40
- if (event.type === "llm:text:delta" || event.type === "assistant:text:delta" || event.type === "assistant:text-delta") {
41
- const data = event.data;
42
- const delta = data.text ?? data.delta ?? "";
43
- process.stdout.write(delta);
44
- fullResponse += delta;
45
- } else if (event.type === "llm:text" || event.type === "assistant:text") {
46
- if (!fullResponse) {
47
- const data = event.data;
48
- process.stdout.write(data.text ?? data.content ?? "");
49
- }
50
- } else if (event.type.startsWith("action:")) {
51
- console.log(`
52
- [Action: ${JSON.stringify(event.data, null, 2)}]`);
53
- }
54
- }
55
- process.stdout.write("\n");
56
- } catch (error) {
57
- console.error("\nError:", error instanceof Error ? error.message : String(error));
58
- }
59
- }
60
- console.log("\nGoodbye!");
61
- rl.close();
62
- });
6
+ program.name("melony").description("Melony CLI - Fast, minimalist AI agent framework").version("0.0.0");
63
7
  if (!process.argv.slice(2).length) {
64
8
  process.argv.push("chat");
65
9
  }
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts"],"names":[],"mappings":"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","file":"cli.js","sourcesContent":["#!/usr/bin/env node\nimport \"dotenv/config\";\nimport * as readline from \"node:readline/promises\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { Command } from \"commander\";\nimport { MelonyClient } from \"./client\";\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nconst program = new Command();\n\nprogram\n .name(\"melony\")\n .description(\"Melony CLI - Fast, minimalist AI agent framework\")\n .version(\"0.1.0\");\n\nprogram\n .command(\"chat\")\n .description(\"Start an interactive chat session with a Melony agent\")\n .option(\"-u, --url <url>\", \"Server URL\", process.env.MELONY_SERVER_URL ?? \"http://localhost:4001/api/chat\")\n .action(async (options) => {\n const client = new MelonyClient({\n url: options.url,\n });\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n console.log(\"------------------------------------------\");\n console.log(\"🍎 Melony Interactive CLI\");\n console.log(`Connected to: ${options.url}`);\n console.log(\"Type your message and press Enter. Type 'exit' to quit.\");\n console.log(\"------------------------------------------\");\n\n while (true) {\n const input = await rl.question(\"\\nYou: \");\n\n if (input.toLowerCase() === \"exit\" || input.toLowerCase() === \"quit\") {\n break;\n }\n\n if (!input.trim()) continue;\n\n process.stdout.write(\"Agent: \");\n\n try {\n const stream = client.send({\n type: \"user:text\",\n data: { content: input },\n } as any);\n\n let fullResponse = \"\";\n\n for await (const event of stream) {\n if (\n event.type === \"llm:text:delta\" ||\n event.type === \"assistant:text:delta\" ||\n event.type === \"assistant:text-delta\"\n ) {\n const data = event.data as any;\n const delta = data.text ?? data.delta ?? \"\";\n process.stdout.write(delta);\n fullResponse += delta;\n } else if (event.type === \"llm:text\" || event.type === \"assistant:text\") {\n if (!fullResponse) {\n const data = event.data as any;\n process.stdout.write(data.text ?? data.content ?? \"\");\n }\n } else if (event.type.startsWith(\"action:\")) {\n console.log(`\\n[Action: ${JSON.stringify(event.data, null, 2)}]`);\n }\n }\n process.stdout.write(\"\\n\");\n } catch (error) {\n console.error(\"\\nError:\", error instanceof Error ? error.message : String(error));\n }\n }\n\n console.log(\"\\nGoodbye!\");\n rl.close();\n });\n\n// Default to chat if no command is provided\nif (!process.argv.slice(2).length) {\n process.argv.push(\"chat\");\n}\n\nprogram.parse();\n"]}
1
+ {"version":3,"sources":["../src/cli.ts"],"names":[],"mappings":";;;;AAIA,IAAM,OAAA,GAAU,IAAI,OAAA,EAAQ;AAE5B,OAAA,CACG,KAAK,QAAQ,CAAA,CACb,YAAY,kDAAkD,CAAA,CAC9D,QAAQ,OAAO,CAAA;AAGlB,IAAI,CAAC,OAAA,CAAQ,IAAA,CAAK,KAAA,CAAM,CAAC,EAAE,MAAA,EAAQ;AACjC,EAAA,OAAA,CAAQ,IAAA,CAAK,KAAK,MAAM,CAAA;AAC1B;AAEA,OAAA,CAAQ,KAAA,EAAM","file":"cli.js","sourcesContent":["#!/usr/bin/env node\nimport \"dotenv/config\";\nimport { Command } from \"commander\";\n\nconst program = new Command();\n\nprogram\n .name(\"melony\")\n .description(\"Melony CLI - Fast, minimalist AI agent framework\")\n .version(\"0.0.0\");\n\n// Default to chat if no command is provided\nif (!process.argv.slice(2).length) {\n process.argv.push(\"chat\");\n}\n\nprogram.parse();\n"]}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,68 @@
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';
1
+ /**
2
+ * The Melony Runtime.
3
+ * Fully unopinionated - processes events through handlers.
4
+ */
5
+ declare class Runtime<TState = any, TEvent = any> {
6
+ readonly config: Config<TState, TEvent>;
7
+ constructor(config: Config<TState, TEvent>);
8
+ /**
9
+ * Helper to get the event type from an event object based on configuration.
10
+ */
11
+ private getEventType;
12
+ /**
13
+ * Helper to check if a value is a Melony Event.
14
+ */
15
+ private isEvent;
16
+ /**
17
+ * Process an incoming event through the runtime.
18
+ * All event processing is handled by user-defined event handlers.
19
+ */
20
+ run(event: TEvent, options?: {
21
+ state?: TState;
22
+ runId?: string;
23
+ }): AsyncGenerator<TEvent>;
24
+ /**
25
+ * Run all event handlers that match the given event type.
26
+ */
27
+ private runEventHandlers;
28
+ /**
29
+ * Internal helper to yield an event with metadata.
30
+ */
31
+ private emit;
32
+ }
33
+
34
+ interface RuntimeContext<TState = any, TEvent = any> {
35
+ state: TState;
36
+ runId: string;
37
+ runtime: Runtime<TState, TEvent>;
38
+ /**
39
+ * Immediately interrupts the runtime execution.
40
+ * If an event is provided, it will be emitted before the runtime stops.
41
+ */
42
+ suspend: (event?: TEvent) => never;
43
+ }
44
+ /**
45
+ * Interceptors run before any event handlers.
46
+ * They can modify the event or call context.suspend() to stop execution.
47
+ */
48
+ type EventInterceptor<TState = any, TEvent = any> = (event: TEvent, context: RuntimeContext<TState, TEvent>) => Promise<TEvent | void> | TEvent | void;
49
+ /**
50
+ * Event handler function for processing events.
51
+ * Can return events to emit or undefined to continue processing.
52
+ */
53
+ type EventHandler<TState = any, TEvent = any> = (event: TEvent, context: RuntimeContext<TState, TEvent>) => AsyncGenerator<TEvent, void, unknown> | void;
54
+ /**
55
+ * Configuration for the Melony runtime.
56
+ */
57
+ interface Config<TState = any, TEvent = any> {
58
+ handlers: Map<string, EventHandler<TState, TEvent>[]>;
59
+ interceptors: Map<string, EventInterceptor<TState, TEvent>[]>;
60
+ /**
61
+ * The key in the event object that defines its type.
62
+ * Defaults to "type".
63
+ */
64
+ eventKey?: string;
65
+ }
3
66
 
4
67
  declare const MelonyRuntime: typeof Runtime;
5
68
 
@@ -7,29 +70,30 @@ declare const MelonyRuntime: typeof Runtime;
7
70
  * A Melony plugin is a function that receives the builder and extends it.
8
71
  * This allows for modularizing common handlers.
9
72
  */
10
- type MelonyPlugin<TState = any, TEvent extends Event = Event> = (builder: MelonyBuilder<TState, TEvent>) => void;
73
+ type MelonyPlugin<TState = any, TEvent = any> = (builder: MelonyBuilder<TState, TEvent>) => void;
11
74
  /**
12
75
  * Fluent builder for creating Melony agents with excellent developer experience.
13
76
  * Provides method chaining for handlers and plugins with full TypeScript support.
14
77
  */
15
- declare class MelonyBuilder<TState = any, TEvent extends Event = Event> {
78
+ declare class MelonyBuilder<TState = any, TEvent = any> {
16
79
  private config;
17
80
  constructor(initialConfig?: Partial<Config<TState, TEvent>>);
81
+ /**
82
+ * Configure the key in the event object that defines its type.
83
+ * Defaults to "type".
84
+ */
85
+ eventKey(key: string): this;
18
86
  /**
19
87
  * Add an event handler for a specific event type. Supports method chaining.
20
88
  * The handler receives the narrowed event type based on the eventType string.
21
89
  */
22
- on<K extends TEvent["type"]>(eventType: K | "*", handler: (event: K extends "*" ? TEvent : Extract<TEvent, {
23
- type: K;
24
- }>, context: RuntimeContext<TState, TEvent>) => AsyncGenerator<TEvent, void, unknown> | void): this;
90
+ on(eventType: string | "*", handler: (event: TEvent, context: RuntimeContext<TState, TEvent>) => AsyncGenerator<TEvent, void, unknown> | void): this;
25
91
  /**
26
92
  * Register an interceptor that runs before any handlers.
27
93
  * Useful for logging, validation, or suspending for approval.
28
94
  */
29
- intercept(interceptor: Interceptor<TState, TEvent>): this;
30
- intercept<K extends TEvent["type"]>(eventType: K, interceptor: (event: Extract<TEvent, {
31
- type: K;
32
- }>, context: RuntimeContext<TState, TEvent>) => Promise<TEvent | void> | TEvent | void): this;
95
+ intercept(interceptor: EventInterceptor<TState, TEvent>): this;
96
+ intercept(eventType: string, interceptor: (event: TEvent, context: RuntimeContext<TState, TEvent>) => Promise<TEvent | void> | TEvent | void): this;
33
97
  /**
34
98
  * Use a plugin to extend the builder.
35
99
  * This is ideal for modularizing common handlers.
@@ -65,12 +129,14 @@ declare class MelonyBuilder<TState = any, TEvent extends Event = Event> {
65
129
  * Factory function to create a new Melony builder instance.
66
130
  * This is the entry point for the fluent API.
67
131
  */
68
- declare function melony<TState = any, TEvent extends Event = Event>(initialConfig?: Partial<Config<TState, TEvent>>): MelonyBuilder<TState, TEvent>;
132
+ declare function melony<TState = any, TEvent = any>(initialConfig?: Partial<Config<TState, TEvent>>): MelonyBuilder<TState, TEvent>;
69
133
 
70
134
  /**
71
135
  * Convert an async generator of events to an HTTP streaming response
72
136
  * Exported for backward compatibility and standalone usage
73
137
  */
74
- declare function createStreamResponse(generator: AsyncGenerator<Event>): Response;
138
+ declare function createStreamResponse<TEvent = any>(generator: AsyncGenerator<TEvent>): Response;
139
+
140
+ declare const generateId: () => string;
75
141
 
76
- export { Config, Event, Interceptor, MelonyBuilder, type MelonyPlugin, MelonyRuntime, Runtime, RuntimeContext, createStreamResponse, melony };
142
+ export { type Config, type EventHandler, type EventInterceptor, MelonyBuilder, type MelonyPlugin, MelonyRuntime, Runtime, type RuntimeContext, createStreamResponse, generateId, melony };
package/dist/index.js CHANGED
@@ -1,37 +1,51 @@
1
- import { generateId } from './chunk-WAI5H335.js';
2
- export { generateId } from './chunk-WAI5H335.js';
1
+ // src/utils/generate-id.ts
2
+ var generateId = () => {
3
+ return typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).substring(7);
4
+ };
3
5
 
4
6
  // src/runtime.ts
5
- function isEvent(val) {
6
- return val && typeof val === "object" && typeof val.type === "string";
7
- }
8
7
  var Runtime = class {
9
8
  constructor(config) {
10
9
  this.config = config;
11
10
  }
11
+ /**
12
+ * Helper to get the event type from an event object based on configuration.
13
+ */
14
+ getEventType(event) {
15
+ const key = this.config.eventKey || "type";
16
+ return event[key] || "*";
17
+ }
18
+ /**
19
+ * Helper to check if a value is a Melony Event.
20
+ */
21
+ isEvent(val) {
22
+ const key = this.config.eventKey || "type";
23
+ return val && typeof val === "object" && typeof val[key] === "string";
24
+ }
12
25
  /**
13
26
  * Process an incoming event through the runtime.
14
27
  * All event processing is handled by user-defined event handlers.
15
28
  */
16
29
  async *run(event, options) {
17
30
  const runId = options?.runId ?? generateId();
31
+ const eventKey = this.config.eventKey || "type";
18
32
  const context = {
19
33
  state: options?.state ?? {},
20
34
  runtime: this,
21
35
  runId,
22
36
  suspend: (event2) => {
23
- throw event2 || { type: "run-suspended", data: {} };
37
+ throw event2 || { [eventKey]: "run-suspended", data: {} };
24
38
  }
25
39
  };
26
40
  try {
27
41
  yield* this.runEventHandlers(event, context);
28
42
  } catch (error) {
29
43
  let eventToEmit;
30
- if (isEvent(error)) {
44
+ if (this.isEvent(error)) {
31
45
  eventToEmit = error;
32
46
  } else {
33
47
  eventToEmit = {
34
- type: "error",
48
+ [eventKey]: "error",
35
49
  data: {
36
50
  message: error instanceof Error ? error.message : String(error),
37
51
  stack: error instanceof Error ? error.stack : void 0
@@ -39,7 +53,7 @@ var Runtime = class {
39
53
  };
40
54
  }
41
55
  if (eventToEmit) {
42
- yield* this.emit(eventToEmit, context);
56
+ yield* this.emit(eventToEmit);
43
57
  }
44
58
  }
45
59
  }
@@ -48,27 +62,29 @@ var Runtime = class {
48
62
  */
49
63
  async *runEventHandlers(event, context) {
50
64
  let currentEvent = event;
65
+ const eventKey = this.config.eventKey || "type";
51
66
  const globalInterceptors = this.config.interceptors.get("*") || [];
52
67
  for (const interceptor of globalInterceptors) {
53
68
  const result = await interceptor(currentEvent, context);
54
- if (result && typeof result === "object" && "type" in result) {
69
+ if (result && typeof result === "object" && eventKey in result) {
55
70
  currentEvent = result;
56
71
  }
57
72
  }
58
- if (currentEvent.type !== "*") {
59
- const specificInterceptors = this.config.interceptors.get(currentEvent.type) || [];
73
+ const eventType = this.getEventType(currentEvent);
74
+ if (eventType !== "*") {
75
+ const specificInterceptors = this.config.interceptors.get(eventType) || [];
60
76
  for (const interceptor of specificInterceptors) {
61
77
  const result = await interceptor(currentEvent, context);
62
- if (result && typeof result === "object" && "type" in result) {
78
+ if (result && typeof result === "object" && eventKey in result) {
63
79
  currentEvent = result;
64
80
  }
65
81
  }
66
82
  }
67
83
  const handlers = [
68
- ...this.config.eventHandlers.get("*") || [],
69
- ...this.config.eventHandlers.get(currentEvent.type) || []
84
+ ...this.config.handlers.get("*") || [],
85
+ ...this.config.handlers.get(this.getEventType(currentEvent)) || []
70
86
  ];
71
- yield* this.emit(currentEvent, context);
87
+ yield* this.emit(currentEvent);
72
88
  for (const handler of handlers) {
73
89
  const result = handler(currentEvent, context);
74
90
  if (result) {
@@ -81,7 +97,7 @@ var Runtime = class {
81
97
  /**
82
98
  * Internal helper to yield an event with metadata.
83
99
  */
84
- async *emit(event, context) {
100
+ async *emit(event) {
85
101
  yield event;
86
102
  }
87
103
  };
@@ -120,19 +136,28 @@ function createStreamResponse(generator) {
120
136
  var MelonyBuilder = class {
121
137
  constructor(initialConfig) {
122
138
  this.config = {
123
- eventHandlers: initialConfig?.eventHandlers ?? /* @__PURE__ */ new Map(),
124
- interceptors: initialConfig?.interceptors ?? /* @__PURE__ */ new Map()
139
+ handlers: initialConfig?.handlers ?? /* @__PURE__ */ new Map(),
140
+ interceptors: initialConfig?.interceptors ?? /* @__PURE__ */ new Map(),
141
+ eventKey: initialConfig?.eventKey ?? "type"
125
142
  };
126
143
  }
144
+ /**
145
+ * Configure the key in the event object that defines its type.
146
+ * Defaults to "type".
147
+ */
148
+ eventKey(key) {
149
+ this.config.eventKey = key;
150
+ return this;
151
+ }
127
152
  /**
128
153
  * Add an event handler for a specific event type. Supports method chaining.
129
154
  * The handler receives the narrowed event type based on the eventType string.
130
155
  */
131
156
  on(eventType, handler) {
132
- if (!this.config.eventHandlers.has(eventType)) {
133
- this.config.eventHandlers.set(eventType, []);
157
+ if (!this.config.handlers.has(eventType)) {
158
+ this.config.handlers.set(eventType, []);
134
159
  }
135
- this.config.eventHandlers.get(eventType).push(handler);
160
+ this.config.handlers.get(eventType).push(handler);
136
161
  return this;
137
162
  }
138
163
  intercept(arg1, arg2) {
@@ -201,6 +226,6 @@ function melony(initialConfig) {
201
226
  return new MelonyBuilder(initialConfig);
202
227
  }
203
228
 
204
- export { MelonyBuilder, MelonyRuntime, Runtime, createStreamResponse, melony };
229
+ export { MelonyBuilder, MelonyRuntime, Runtime, createStreamResponse, generateId, melony };
205
230
  //# sourceMappingURL=index.js.map
206
231
  //# sourceMappingURL=index.js.map
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 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"]}
1
+ {"version":3,"sources":["../src/utils/generate-id.ts","../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":["export const generateId = () => {\n return typeof crypto !== \"undefined\" && crypto.randomUUID\n ? crypto.randomUUID()\n : Math.random().toString(36).substring(7);\n};\n","import {\n RuntimeContext,\n Config,\n} from \"./types\";\nimport { generateId } from \"./utils/generate-id\";\n\n/**\n * The Melony Runtime.\n * Fully unopinionated - processes events through handlers.\n */\nexport class Runtime<TState = any, TEvent = any> {\n public readonly config: Config<TState, TEvent>;\n\n constructor(config: Config<TState, TEvent>) {\n this.config = config;\n }\n\n /**\n * Helper to get the event type from an event object based on configuration.\n */\n private getEventType(event: TEvent): string {\n const key = this.config.eventKey || \"type\";\n return (event as any)[key] || \"*\";\n }\n\n /**\n * Helper to check if a value is a Melony Event.\n */\n private isEvent(val: any): val is TEvent {\n const key = this.config.eventKey || \"type\";\n return val && typeof val === \"object\" && typeof (val as any)[key] === \"string\";\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 const eventKey = this.config.eventKey || \"type\";\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 || { [eventKey]: \"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 (this.isEvent(error)) {\n eventToEmit = error as TEvent;\n } else {\n eventToEmit = {\n [eventKey]: \"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);\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 const eventKey = this.config.eventKey || \"type\";\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\" && eventKey in (result as any)) {\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 const eventType = this.getEventType(currentEvent);\n if (eventType !== \"*\") {\n const specificInterceptors = this.config.interceptors.get(eventType) || [];\n for (const interceptor of specificInterceptors) {\n const result = await interceptor(currentEvent, context);\n if (result && typeof result === \"object\" && eventKey in (result as any)) {\n currentEvent = result as TEvent;\n }\n }\n }\n\n const handlers = [\n ...(this.config.handlers.get(\"*\") || []),\n ...(this.config.handlers.get(this.getEventType(currentEvent)) || []),\n ];\n\n // First emit the event itself\n yield* this.emit(currentEvent);\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 ): AsyncGenerator<TEvent> {\n yield event;\n }\n}\n","import { Runtime } from \"./runtime\";\n\nexport const MelonyRuntime = Runtime;","/**\n * Convert an async generator of events to an HTTP streaming response\n * Exported for backward compatibility and standalone usage\n */\nexport function createStreamResponse<TEvent = any>(\n generator: AsyncGenerator<TEvent>,\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 EventHandler,\n Config,\n RuntimeContext,\n EventInterceptor,\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 = any> = (\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 = any\n> {\n private config: Config<TState, TEvent>;\n\n constructor(initialConfig?: Partial<Config<TState, TEvent>>) {\n this.config = {\n handlers: initialConfig?.handlers ?? new Map(),\n interceptors: initialConfig?.interceptors ?? new Map(),\n eventKey: initialConfig?.eventKey ?? \"type\",\n };\n }\n\n /**\n * Configure the key in the event object that defines its type.\n * Defaults to \"type\".\n */\n eventKey(key: string): this {\n this.config.eventKey = key;\n return this;\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(\n eventType: string | \"*\",\n handler: (\n event: TEvent,\n context: RuntimeContext<TState, TEvent>\n ) => AsyncGenerator<TEvent, void, unknown> | void\n ): this {\n if (!this.config.handlers.has(eventType)) {\n this.config.handlers.set(eventType, []);\n }\n // Cast is safe because runtime only calls this handler for matching event types\n this.config.handlers.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: EventInterceptor<TState, TEvent>): this;\n intercept(\n eventType: string,\n interceptor: (\n event: TEvent,\n context: RuntimeContext<TState, TEvent>\n ) => Promise<TEvent | void> | TEvent | void\n ): this;\n intercept(\n arg1: string | EventInterceptor<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 EventInterceptor<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 = any\n>(initialConfig?: Partial<Config<TState, TEvent>>): MelonyBuilder<TState, TEvent> {\n return new MelonyBuilder<TState, TEvent>(initialConfig);\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "melony",
3
- "version": "0.3.4",
3
+ "version": "0.3.5",
4
4
  "main": "dist/index.js",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -26,11 +26,6 @@
26
26
  "import": "./dist/index.js",
27
27
  "default": "./dist/index.js"
28
28
  },
29
- "./client": {
30
- "types": "./dist/client.d.ts",
31
- "import": "./dist/client.js",
32
- "default": "./dist/client.js"
33
- },
34
29
  "./package.json": "./package.json"
35
30
  },
36
31
  "module": "dist/index.js",
@@ -1,171 +0,0 @@
1
- import { generateId } from './chunk-WAI5H335.js';
2
-
3
- // src/client.ts
4
- var MelonyClient = class {
5
- constructor(options) {
6
- this.abortController = null;
7
- this.stateListeners = /* @__PURE__ */ new Set();
8
- this.url = options.url;
9
- this.headers = options.headers;
10
- this.state = {
11
- events: options.initialEvents ?? [],
12
- streaming: false,
13
- error: null,
14
- context: options.initialContext ?? {}
15
- };
16
- }
17
- subscribe(listener) {
18
- this.stateListeners.add(listener);
19
- return () => {
20
- this.stateListeners.delete(listener);
21
- };
22
- }
23
- getState() {
24
- return { ...this.state };
25
- }
26
- async getRequestHeaders() {
27
- const headers = {
28
- "Content-Type": "application/json"
29
- };
30
- if (this.headers) {
31
- const extraHeaders = typeof this.headers === "function" ? await this.headers() : this.headers;
32
- Object.assign(headers, extraHeaders);
33
- }
34
- return headers;
35
- }
36
- setState(updates) {
37
- this.state = { ...this.state, ...updates };
38
- this.stateListeners.forEach((l) => l(this.getState()));
39
- }
40
- async *send(event, additionalBody) {
41
- if (this.abortController) this.abortController.abort();
42
- this.abortController = new AbortController();
43
- const optimisticEvent = {
44
- id: generateId(),
45
- ...event
46
- };
47
- this.setState({
48
- streaming: true,
49
- error: null,
50
- events: [...this.state.events, optimisticEvent]
51
- });
52
- try {
53
- const headers = await this.getRequestHeaders();
54
- const runResponse = await fetch(`${this.url}/runs`, {
55
- method: "POST",
56
- headers,
57
- body: JSON.stringify({
58
- event: optimisticEvent,
59
- ...additionalBody
60
- }),
61
- signal: this.abortController.signal
62
- });
63
- if (!runResponse.ok)
64
- throw new Error(`HTTP error! status: ${runResponse.status}`);
65
- const { runId, threadId } = await runResponse.json();
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(), {
93
- headers: {
94
- ...headers,
95
- "Accept": "text/event-stream"
96
- },
97
- signal: this.abortController.signal
98
- });
99
- if (!response.ok)
100
- throw new Error(`HTTP error! status: ${response.status}`);
101
- if (!response.body) throw new Error("No response body");
102
- const reader = response.body.getReader();
103
- const decoder = new TextDecoder();
104
- let buffer = "";
105
- while (true) {
106
- const { done, value } = await reader.read();
107
- if (done) break;
108
- buffer += decoder.decode(value, { stream: true });
109
- const lines = buffer.split("\n\n");
110
- buffer = lines.pop() || "";
111
- for (const line of lines) {
112
- if (!line.startsWith("data: ")) continue;
113
- try {
114
- const incomingEvent = JSON.parse(line.slice(6));
115
- const handled = this.handleIncomingEvent(incomingEvent);
116
- if (!handled) continue;
117
- yield incomingEvent;
118
- if (incomingEvent.type === "run:status") {
119
- const data = incomingEvent.data;
120
- if (data?.status === "completed" || data?.status === "failed") {
121
- this.setState({ streaming: false });
122
- return;
123
- }
124
- }
125
- } catch (e) {
126
- console.error("Failed to parse event", e);
127
- }
128
- }
129
- }
130
- this.setState({ streaming: false });
131
- } catch (err) {
132
- if (err instanceof Error && err.name === "AbortError") {
133
- this.setState({ streaming: false });
134
- return;
135
- }
136
- const error = err instanceof Error ? err : new Error(String(err));
137
- this.setState({ error, streaming: false });
138
- throw error;
139
- }
140
- }
141
- handleIncomingEvent(event) {
142
- const events = [...this.state.events];
143
- const index = event.id ? events.findIndex((e) => e.id === event.id) : -1;
144
- if (index !== -1) {
145
- events[index] = event;
146
- } else {
147
- events.push(event);
148
- }
149
- this.setState({ events });
150
- return true;
151
- }
152
- reset(events = []) {
153
- this.stop();
154
- this.setState({
155
- events,
156
- error: null,
157
- streaming: false
158
- });
159
- }
160
- stop() {
161
- if (this.abortController) {
162
- this.abortController.abort();
163
- this.abortController = null;
164
- this.setState({ streaming: false });
165
- }
166
- }
167
- };
168
-
169
- export { MelonyClient };
170
- //# sourceMappingURL=chunk-2LVJG7WL.js.map
171
- //# sourceMappingURL=chunk-2LVJG7WL.js.map
@@ -1 +0,0 @@
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"]}
@@ -1,8 +0,0 @@
1
- // src/utils/generate-id.ts
2
- var generateId = () => {
3
- return typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).substring(7);
4
- };
5
-
6
- export { generateId };
7
- //# sourceMappingURL=chunk-WAI5H335.js.map
8
- //# sourceMappingURL=chunk-WAI5H335.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/generate-id.ts"],"names":[],"mappings":";AAAO,IAAM,aAAa,MAAM;AAC9B,EAAA,OAAO,OAAO,MAAA,KAAW,WAAA,IAAe,MAAA,CAAO,aAC3C,MAAA,CAAO,UAAA,EAAW,GAClB,IAAA,CAAK,QAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,UAAU,CAAC,CAAA;AAC5C","file":"chunk-WAI5H335.js","sourcesContent":["export const generateId = () => {\n return typeof crypto !== \"undefined\" && crypto.randomUUID\n ? crypto.randomUUID()\n : Math.random().toString(36).substring(7);\n};\n"]}
package/dist/client.d.ts DELETED
@@ -1,45 +0,0 @@
1
- import { E as Event } from './generate-id-DOokX68f.js';
2
- export { g as generateId } from './generate-id-DOokX68f.js';
3
-
4
- interface ClientState<TEvent extends Event = Event> {
5
- events: TEvent[];
6
- streaming: boolean;
7
- error: Error | null;
8
- context: Record<string, any>;
9
- }
10
- interface MelonyClientOptions<TEvent extends Event = Event> {
11
- url: string;
12
- initialEvents?: TEvent[];
13
- initialContext?: Record<string, any>;
14
- headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
15
- }
16
- declare class MelonyClient<TEvent extends Event = Event> {
17
- private state;
18
- readonly url: string;
19
- private headers?;
20
- private abortController;
21
- private stateListeners;
22
- constructor(options: MelonyClientOptions<TEvent>);
23
- subscribe(listener: (state: ClientState<TEvent>) => void): () => void;
24
- getState(): {
25
- events: TEvent[];
26
- streaming: boolean;
27
- error: Error | null;
28
- context: Record<string, any>;
29
- };
30
- private getRequestHeaders;
31
- private setState;
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>;
40
- private handleIncomingEvent;
41
- reset(events?: TEvent[]): void;
42
- stop(): void;
43
- }
44
-
45
- export { type ClientState, Event, MelonyClient, type MelonyClientOptions };
package/dist/client.js DELETED
@@ -1,4 +0,0 @@
1
- export { MelonyClient } from './chunk-2LVJG7WL.js';
2
- export { generateId } from './chunk-WAI5H335.js';
3
- //# sourceMappingURL=client.js.map
4
- //# sourceMappingURL=client.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"client.js"}
@@ -1,63 +0,0 @@
1
- /**
2
- * The Melony Runtime.
3
- * Fully unopinionated - processes events through handlers.
4
- */
5
- declare class Runtime<TState = any, TEvent extends Event = Event> {
6
- readonly config: Config<TState, TEvent>;
7
- constructor(config: Config<TState, TEvent>);
8
- /**
9
- * Process an incoming event through the runtime.
10
- * All event processing is handled by user-defined event handlers.
11
- */
12
- run(event: TEvent, options?: {
13
- state?: TState;
14
- runId?: string;
15
- }): AsyncGenerator<TEvent>;
16
- /**
17
- * Run all event handlers that match the given event type.
18
- */
19
- private runEventHandlers;
20
- /**
21
- * Internal helper to yield an event with metadata.
22
- */
23
- private emit;
24
- }
25
-
26
- /**
27
- * The core Event structure.
28
- * Truly unopinionated - only 'type' is strictly required for dispatching.
29
- */
30
- type Event = {
31
- /** The type of the event (required for runtime dispatching) */
32
- type: string;
33
- /** Catch-all for any other custom fields */
34
- [key: string]: any;
35
- };
36
- interface RuntimeContext<TState = any, TEvent extends Event = Event> {
37
- state: TState;
38
- runId: string;
39
- runtime: Runtime<TState, TEvent>;
40
- /**
41
- * Immediately interrupts the runtime execution.
42
- * If an event is provided, it will be emitted before the runtime stops.
43
- */
44
- suspend: (event?: TEvent) => never;
45
- }
46
- /**
47
- * Interceptors run before any event handlers.
48
- * They can modify the event or call context.suspend() to stop execution.
49
- */
50
- type Interceptor<TState = any, TEvent extends Event = Event> = (event: TEvent, context: RuntimeContext<TState, TEvent>) => Promise<TEvent | void> | TEvent | void;
51
- /**
52
- * Event handler function for processing events.
53
- * Can return events to emit or undefined to continue processing.
54
- */
55
- type EventHandler<TState = any, TEvent extends Event = Event> = (event: TEvent, context: RuntimeContext<TState, TEvent>) => AsyncGenerator<TEvent, void, unknown> | void;
56
- interface Config<TState = any, TEvent extends Event = Event> {
57
- eventHandlers: Map<string, EventHandler<TState, TEvent>[]>;
58
- interceptors: Map<string, Interceptor<TState, TEvent>[]>;
59
- }
60
-
61
- declare const generateId: () => string;
62
-
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 };