melony 0.2.0 → 0.2.2
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 +26 -26
- package/dist/client.d.ts +0 -8
- package/dist/client.js +1 -2
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,33 +8,23 @@ Fast, unopinionated, minimalist event-based framework for AI agents.
|
|
|
8
8
|
npm install melony
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
## Quick Start
|
|
12
|
-
|
|
13
11
|
### 🔥 New: Fluent Builder API (Recommended)
|
|
14
12
|
|
|
15
13
|
```ts
|
|
16
|
-
import { melony
|
|
14
|
+
import { melony } from "melony";
|
|
17
15
|
|
|
18
16
|
const agent = melony()
|
|
19
17
|
.action("getWeather", async function* ({ city }: { city: string }) {
|
|
20
|
-
yield {
|
|
21
|
-
type: "ui",
|
|
22
|
-
data: {
|
|
23
|
-
type: "card",
|
|
24
|
-
title: `Weather in ${city}`,
|
|
25
|
-
children: [{ type: "text", value: "Sunny, 24°C" }]
|
|
26
|
-
}
|
|
27
|
-
};
|
|
18
|
+
yield { type: "text", data: { content: `Weather in ${city} is 24°C` } };
|
|
28
19
|
})
|
|
29
20
|
.on("text", async function* (event, { runtime }) {
|
|
30
21
|
if (event.data.content.includes("weather")) {
|
|
31
22
|
yield* runtime.execute("getWeather", { city: "London" });
|
|
32
23
|
}
|
|
33
|
-
})
|
|
34
|
-
.build();
|
|
24
|
+
});
|
|
35
25
|
|
|
36
|
-
// Run it
|
|
37
|
-
for await (const event of agent.run({ type: "text", data: { content: "How's the weather?" } })) {
|
|
26
|
+
// Run it (or use agent.stream(event) for HTTP)
|
|
27
|
+
for await (const event of agent.build().run({ type: "text", data: { content: "How's the weather?" } })) {
|
|
38
28
|
console.log(event);
|
|
39
29
|
}
|
|
40
30
|
```
|
|
@@ -42,7 +32,7 @@ for await (const event of agent.run({ type: "text", data: { content: "How's the
|
|
|
42
32
|
### Legacy: Runtime Class API (Still Supported)
|
|
43
33
|
|
|
44
34
|
```ts
|
|
45
|
-
import { MelonyRuntime
|
|
35
|
+
import { MelonyRuntime } from "melony";
|
|
46
36
|
|
|
47
37
|
// 1. Create the runtime
|
|
48
38
|
const agent = new MelonyRuntime({
|
|
@@ -69,17 +59,9 @@ The fluent builder provides an excellent developer experience with method chaini
|
|
|
69
59
|
### Action Definition
|
|
70
60
|
```ts
|
|
71
61
|
const agent = melony()
|
|
72
|
-
//
|
|
62
|
+
// Register an async generator with a name
|
|
73
63
|
.action("getWeather", async function* ({ city }) {
|
|
74
64
|
yield { type: "text", data: { content: `Weather in ${city} is sunny!` } };
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
// Action with full config object
|
|
78
|
-
.action({
|
|
79
|
-
name: "placeOrder",
|
|
80
|
-
execute: async function* ({ itemId, quantity }) {
|
|
81
|
-
yield { type: "text", data: { content: `Ordered ${quantity} items!` } };
|
|
82
|
-
}
|
|
83
65
|
});
|
|
84
66
|
```
|
|
85
67
|
|
|
@@ -98,6 +80,25 @@ const agent = melony()
|
|
|
98
80
|
.build();
|
|
99
81
|
```
|
|
100
82
|
|
|
83
|
+
### Plugin System
|
|
84
|
+
Plugins allow you to modularize and reuse actions and handlers across different agents. A plugin is simply a function that receives the `MelonyBuilder`.
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import { melony, MelonyPlugin } from "melony";
|
|
88
|
+
|
|
89
|
+
const loggingPlugin: MelonyPlugin = (builder) => {
|
|
90
|
+
builder.on("action:before", async function* (event) {
|
|
91
|
+
console.log(`[Plugin] Executing: ${event.data.action}`);
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const agent = melony()
|
|
96
|
+
.use(loggingPlugin)
|
|
97
|
+
.action("greet", async function* () {
|
|
98
|
+
yield { type: "text", data: { content: "Hello!" } };
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
101
102
|
### TypeScript Benefits
|
|
102
103
|
- **Full type inference** through the entire chain
|
|
103
104
|
- **IntelliSense** for all methods and parameters
|
|
@@ -109,7 +110,6 @@ const agent = melony()
|
|
|
109
110
|
- **Event**: The universal unit of streaming (`{ type, data, meta }`).
|
|
110
111
|
- **Action**: An async generator that yields events.
|
|
111
112
|
- **Event Handlers**: Reactive functions that listen to and emit events.
|
|
112
|
-
- **SDUI**: Stream typed UI structures as JSON events to your frontend.
|
|
113
113
|
|
|
114
114
|
## License
|
|
115
115
|
|
package/dist/client.d.ts
CHANGED
|
@@ -5,10 +5,6 @@ interface ClientState<TEvent extends Event = Event> {
|
|
|
5
5
|
events: TEvent[];
|
|
6
6
|
isLoading: boolean;
|
|
7
7
|
error: Error | null;
|
|
8
|
-
loadingStatus?: {
|
|
9
|
-
message: string;
|
|
10
|
-
details?: string;
|
|
11
|
-
};
|
|
12
8
|
}
|
|
13
9
|
interface MelonyClientOptions<TEvent extends Event = Event> {
|
|
14
10
|
url: string;
|
|
@@ -28,10 +24,6 @@ declare class MelonyClient<TEvent extends Event = Event> {
|
|
|
28
24
|
events: TEvent[];
|
|
29
25
|
isLoading: boolean;
|
|
30
26
|
error: Error | null;
|
|
31
|
-
loadingStatus?: {
|
|
32
|
-
message: string;
|
|
33
|
-
details?: string;
|
|
34
|
-
};
|
|
35
27
|
};
|
|
36
28
|
private getRequestHeaders;
|
|
37
29
|
private setState;
|
package/dist/client.js
CHANGED
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts"],"names":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"client.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 isLoading: boolean;\n error: Error | null;\n}\n\nexport interface MelonyClientOptions<TEvent extends Event = Event> {\n url: string;\n initialEvents?: TEvent[];\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 isLoading: false,\n error: null,\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 *sendEvent(event: TEvent): AsyncGenerator<TEvent> {\n if (this.abortController) this.abortController.abort();\n this.abortController = new AbortController();\n\n const runId = event.meta?.runId ?? generateId();\n\n // if the state comes from the client, no last server state is preserved\n const state = event.meta?.state ?? this.lastServerState;\n\n const optimisticEvent: TEvent = {\n ...event,\n meta: {\n ...event.meta,\n id: event.meta?.id ?? generateId(),\n runId,\n state,\n role: event.meta?.role ?? \"user\",\n timestamp: event.meta?.timestamp ?? Date.now(),\n },\n } as TEvent;\n\n this.setState({\n isLoading: true,\n error: null,\n events: [...this.state.events, optimisticEvent],\n });\n\n try {\n const headers = await this.getRequestHeaders();\n const response = await fetch(this.url, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ event: optimisticEvent }),\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 this.handleIncomingEvent(incomingEvent);\n yield incomingEvent;\n } catch (e) {\n console.error(\"Failed to parse event\", e);\n }\n }\n }\n this.setState({ isLoading: false });\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") {\n this.setState({ isLoading: false });\n return;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n this.setState({ error, isLoading: false });\n throw error;\n }\n }\n\n private handleIncomingEvent(event: TEvent) {\n if (event.meta?.state) {\n this.lastServerState = event.meta.state;\n }\n\n const events = [...this.state.events];\n\n events.push(event);\n\n this.setState({ events });\n }\n\n reset(events: TEvent[] = []) {\n if (this.abortController) this.abortController.abort();\n this.setState({\n events,\n error: null,\n isLoading: false,\n });\n }\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,11 @@ declare function action<TParams = any>(name: string, execute: ActionExecute<TPar
|
|
|
13
13
|
*/
|
|
14
14
|
declare function action<TParams = any, TState = any, TEvent extends Event = Event>(config: Action<TParams, TState, TEvent>): Action<TParams, TState, TEvent>;
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* A Melony plugin is a function that receives the builder and extends it.
|
|
18
|
+
* This allows for modularizing common actions and handlers.
|
|
19
|
+
*/
|
|
20
|
+
type MelonyPlugin<TState = any, TEvent extends Event = Event> = (builder: MelonyBuilder<TState, TEvent>) => void;
|
|
16
21
|
/**
|
|
17
22
|
* Fluent builder for creating Melony agents with excellent developer experience.
|
|
18
23
|
* Provides method chaining for actions and plugins with full TypeScript support.
|
|
@@ -39,6 +44,11 @@ declare class MelonyBuilder<TState = any, TEvent extends Event = Event> {
|
|
|
39
44
|
on<K extends TEvent["type"]>(eventType: K, handler: (event: Extract<TEvent, {
|
|
40
45
|
type: K;
|
|
41
46
|
}>, context: RuntimeContext<TState, TEvent>) => AsyncGenerator<TEvent, void, unknown> | void): this;
|
|
47
|
+
/**
|
|
48
|
+
* Use a plugin to extend the builder.
|
|
49
|
+
* This is ideal for modularizing common actions and handlers.
|
|
50
|
+
*/
|
|
51
|
+
use(plugin: MelonyPlugin<TState, TEvent>): this;
|
|
42
52
|
/**
|
|
43
53
|
* Build and return the Melony runtime instance.
|
|
44
54
|
* This is the final method in the fluent chain.
|
|
@@ -68,4 +78,4 @@ declare function melony<TState = any, TEvent extends Event = Event>(initialConfi
|
|
|
68
78
|
*/
|
|
69
79
|
declare function createStreamResponse(generator: AsyncGenerator<Event>): Response;
|
|
70
80
|
|
|
71
|
-
export { Action, ActionExecute, Config, Event, MelonyBuilder, MelonyRuntime, Runtime, RuntimeContext, action, createStreamResponse, melony };
|
|
81
|
+
export { Action, ActionExecute, Config, Event, MelonyBuilder, type MelonyPlugin, MelonyRuntime, Runtime, RuntimeContext, action, createStreamResponse, melony };
|
package/dist/index.js
CHANGED
|
@@ -251,6 +251,14 @@ var MelonyBuilder = class {
|
|
|
251
251
|
this.config.eventHandlers.get(eventType).push(handler);
|
|
252
252
|
return this;
|
|
253
253
|
}
|
|
254
|
+
/**
|
|
255
|
+
* Use a plugin to extend the builder.
|
|
256
|
+
* This is ideal for modularizing common actions and handlers.
|
|
257
|
+
*/
|
|
258
|
+
use(plugin) {
|
|
259
|
+
plugin(this);
|
|
260
|
+
return this;
|
|
261
|
+
}
|
|
254
262
|
/**
|
|
255
263
|
* Build and return the Melony runtime instance.
|
|
256
264
|
* This is the final method in the fluent chain.
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runtime.ts","../src/melony.ts","../src/action.ts","../src/utils/create-stream-response.ts","../src/builder.ts"],"names":["action","event"],"mappings":"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","file":"index.js","sourcesContent":["import {\n Action,\n Event,\n RuntimeContext,\n Config,\n EventHandler,\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 - executes a single action per run.\n * Chaining/looping is left to userland.\n */\nexport class Runtime<TState = any, TEvent extends Event = Event> {\n public readonly config: Config<TState, TEvent>;\n private queue: TEvent[] = [];\n private isEmitting = false;\n\n constructor(config: Config<TState, TEvent>) {\n this.config = config;\n }\n\n /**\n * Run an action by name with given params.\n * This is the primary way to execute actions.\n */\n public async *execute(\n actionName: string,\n params: any,\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 actions: this.config.actions,\n suspend: (event?: TEvent) => {\n throw event || { type: \"run-suspended\", data: {} };\n },\n };\n\n const action = this.config.actions[actionName];\n if (!action) {\n yield* this.emit(\n {\n type: \"error\",\n data: { message: `Action \"${actionName}\" not found` },\n } as TEvent,\n context,\n );\n return;\n }\n\n try {\n // Emit action:before event\n yield* this.emit(\n {\n type: \"action:before\",\n data: { action: actionName, params },\n } as TEvent,\n context,\n );\n\n // Execute the action - users handle lifecycle events explicitly\n const generator = action.execute(params, context);\n let result: any = undefined;\n\n while (true) {\n const { value, done } = await generator.next();\n if (done) {\n result = value; // Capture the return value\n break;\n }\n yield* this.emit(value as TEvent, context);\n }\n\n // Emit action:after event\n yield* this.emit(\n {\n type: \"action:after\",\n data: { action: actionName, result },\n } as TEvent,\n context,\n );\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 action: actionName,\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 * Process an incoming event through the runtime.\n * All event processing is handled by user-defined event handlers.\n */\n public async *run(event: TEvent): AsyncGenerator<TEvent> {\n const runId = event.meta?.runId ?? generateId();\n\n const context: RuntimeContext<TState, TEvent> = {\n state: (event.meta?.state ?? {}) as TState,\n runtime: this,\n runId,\n actions: this.config.actions,\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 const handlers = this.config.eventHandlers.get(event.type) || [];\n for (const handler of handlers) {\n const result = handler(event, context);\n if (result) {\n for await (const yieldedEvent of result) {\n yield yieldedEvent;\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 * Handlers are invoked by runEventHandlers when events bubble up.\n */\n private async *emit(\n event: TEvent,\n context: RuntimeContext<TState, TEvent>,\n ): AsyncGenerator<TEvent> {\n this.queue.push(event);\n\n if (this.isEmitting) return;\n\n this.isEmitting = true;\n try {\n while (this.queue.length > 0) {\n const current = this.queue.shift()!;\n\n const finalEvent: TEvent = {\n ...current,\n meta: {\n ...current.meta,\n id: current.meta?.id ?? generateId(), \n runtime: this,\n runId: context.runId,\n timestamp: current.meta?.timestamp ?? Date.now(),\n role: current.meta?.role ?? \"assistant\",\n state: context.state,\n },\n };\n\n yield finalEvent;\n }\n } finally {\n this.isEmitting = false;\n }\n }\n}\n","import { Runtime } from \"./runtime\";\n\nexport const MelonyRuntime = Runtime;"," import { Action, ActionExecute, Event } from \"./types\";\n\n/**\n * Create an action with just a name and handler.\n * Compatible with any agent - types are resolved automatically when added to an agent.\n */\nexport function action<TParams = any>(\n name: string,\n execute: ActionExecute<TParams, any, any>,\n): Action<TParams, any, any>;\n/**\n * Helper to define an action with full type inference (for advanced use cases).\n */\nexport function action<\n TParams = any,\n TState = any,\n TEvent extends Event = Event,\n>(\n config: Action<TParams, TState, TEvent>,\n): Action<TParams, TState, TEvent>;\nexport function action<\n TParams = any,\n TState = any,\n TEvent extends Event = Event,\n>(\n ...args: [Action<TParams, TState, TEvent>] | [string, ActionExecute<TParams, any, any>]\n): Action<TParams, TState, TEvent> | Action<TParams, any, any> {\n if (typeof args[0] === \"string\") {\n const [name, execute] = args as [string, ActionExecute<TParams, any, any>];\n return { name, execute };\n }\n\n if (typeof args[0] === \"object\" && args[0] !== null && 'name' in args[0] && 'execute' in args[0]) {\n return args[0] as Action<TParams, TState, TEvent>;\n }\n\n throw new Error(\"Invalid action parameters\");\n}\n","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 Action,\n Event,\n EventHandler,\n Config,\n ActionExecute,\n RuntimeContext,\n} from \"./types\";\nimport { Runtime } from \"./runtime\";\nimport { createStreamResponse } from \"./utils/create-stream-response\";\n\n/**\n * Fluent builder for creating Melony agents with excellent developer experience.\n * Provides method chaining for actions 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 actions: {},\n eventHandlers: new Map(),\n ...initialConfig,\n };\n\n // Add built-in call-action handler\n this.addBuiltInHandlers();\n }\n\n /**\n * Add built-in event handlers that are available in all agents.\n */\n private addBuiltInHandlers(): void {\n // Built-in call-action handler\n this.on(\"call-action\", async function* (event, context) {\n const { action: actionName, params } = event.data as { action: string; params: unknown };\n\n // Execute the action (runtime will automatically emit action:before and action:after events)\n yield* context.runtime.execute(actionName, params);\n });\n }\n\n /**\n * Add an action to the agent with fluent method chaining.\n * Supports two patterns:\n * - Pass a pre-defined Action object\n * - Define action inline with name and handler\n */\n action<TParams = any>(\n action: Action<TParams, any, any>\n ): this;\n action<TParams = any>(\n name: string,\n execute: ActionExecute<TParams, any, any>\n ): this;\n action<TParams = any>(\n nameOrAction: string | Action<TParams, any, any>,\n execute?: ActionExecute<TParams, any, any>\n ): this {\n if (typeof nameOrAction !== 'string') {\n // Called as: .action(action) - pre-defined action object\n // Auto-cast to agent types for better DX\n const typedAction: Action<TParams, TState, TEvent> = {\n name: nameOrAction.name,\n execute: nameOrAction.execute as ActionExecute<TParams, TState, TEvent>,\n };\n this.config.actions[nameOrAction.name] = typedAction;\n return this;\n }\n\n // Called as: .action(name, execute)\n const name = nameOrAction;\n const actionObj: Action<TParams, TState, TEvent> = {\n name,\n execute: execute! as ActionExecute<TParams, TState, TEvent>,\n };\n this.config.actions[name] = actionObj;\n return this;\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: 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 * 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 stream(\n event: TEvent,\n options?: { state?: TState }\n ): Promise<Response> {\n const runtime = this.build();\n const generator = runtime.run(event);\n return createStreamResponse(generator);\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}"]}
|
|
1
|
+
{"version":3,"sources":["../src/runtime.ts","../src/melony.ts","../src/action.ts","../src/utils/create-stream-response.ts","../src/builder.ts"],"names":["action","event"],"mappings":"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","file":"index.js","sourcesContent":["import {\n Action,\n Event,\n RuntimeContext,\n Config,\n EventHandler,\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 - executes a single action per run.\n * Chaining/looping is left to userland.\n */\nexport class Runtime<TState = any, TEvent extends Event = Event> {\n public readonly config: Config<TState, TEvent>;\n private queue: TEvent[] = [];\n private isEmitting = false;\n\n constructor(config: Config<TState, TEvent>) {\n this.config = config;\n }\n\n /**\n * Run an action by name with given params.\n * This is the primary way to execute actions.\n */\n public async *execute(\n actionName: string,\n params: any,\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 actions: this.config.actions,\n suspend: (event?: TEvent) => {\n throw event || { type: \"run-suspended\", data: {} };\n },\n };\n\n const action = this.config.actions[actionName];\n if (!action) {\n yield* this.emit(\n {\n type: \"error\",\n data: { message: `Action \"${actionName}\" not found` },\n } as TEvent,\n context,\n );\n return;\n }\n\n try {\n // Emit action:before event\n yield* this.emit(\n {\n type: \"action:before\",\n data: { action: actionName, params },\n } as TEvent,\n context,\n );\n\n // Execute the action - users handle lifecycle events explicitly\n const generator = action.execute(params, context);\n let result: any = undefined;\n\n while (true) {\n const { value, done } = await generator.next();\n if (done) {\n result = value; // Capture the return value\n break;\n }\n yield* this.emit(value as TEvent, context);\n }\n\n // Emit action:after event\n yield* this.emit(\n {\n type: \"action:after\",\n data: { action: actionName, result },\n } as TEvent,\n context,\n );\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 action: actionName,\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 * Process an incoming event through the runtime.\n * All event processing is handled by user-defined event handlers.\n */\n public async *run(event: TEvent): AsyncGenerator<TEvent> {\n const runId = event.meta?.runId ?? generateId();\n\n const context: RuntimeContext<TState, TEvent> = {\n state: (event.meta?.state ?? {}) as TState,\n runtime: this,\n runId,\n actions: this.config.actions,\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 const handlers = this.config.eventHandlers.get(event.type) || [];\n for (const handler of handlers) {\n const result = handler(event, context);\n if (result) {\n for await (const yieldedEvent of result) {\n yield yieldedEvent;\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 * Handlers are invoked by runEventHandlers when events bubble up.\n */\n private async *emit(\n event: TEvent,\n context: RuntimeContext<TState, TEvent>,\n ): AsyncGenerator<TEvent> {\n this.queue.push(event);\n\n if (this.isEmitting) return;\n\n this.isEmitting = true;\n try {\n while (this.queue.length > 0) {\n const current = this.queue.shift()!;\n\n const finalEvent: TEvent = {\n ...current,\n meta: {\n ...current.meta,\n id: current.meta?.id ?? generateId(), \n runtime: this,\n runId: context.runId,\n timestamp: current.meta?.timestamp ?? Date.now(),\n role: current.meta?.role ?? \"assistant\",\n state: context.state,\n },\n };\n\n yield finalEvent;\n }\n } finally {\n this.isEmitting = false;\n }\n }\n}\n","import { Runtime } from \"./runtime\";\n\nexport const MelonyRuntime = Runtime;"," import { Action, ActionExecute, Event } from \"./types\";\n\n/**\n * Create an action with just a name and handler.\n * Compatible with any agent - types are resolved automatically when added to an agent.\n */\nexport function action<TParams = any>(\n name: string,\n execute: ActionExecute<TParams, any, any>,\n): Action<TParams, any, any>;\n/**\n * Helper to define an action with full type inference (for advanced use cases).\n */\nexport function action<\n TParams = any,\n TState = any,\n TEvent extends Event = Event,\n>(\n config: Action<TParams, TState, TEvent>,\n): Action<TParams, TState, TEvent>;\nexport function action<\n TParams = any,\n TState = any,\n TEvent extends Event = Event,\n>(\n ...args: [Action<TParams, TState, TEvent>] | [string, ActionExecute<TParams, any, any>]\n): Action<TParams, TState, TEvent> | Action<TParams, any, any> {\n if (typeof args[0] === \"string\") {\n const [name, execute] = args as [string, ActionExecute<TParams, any, any>];\n return { name, execute };\n }\n\n if (typeof args[0] === \"object\" && args[0] !== null && 'name' in args[0] && 'execute' in args[0]) {\n return args[0] as Action<TParams, TState, TEvent>;\n }\n\n throw new Error(\"Invalid action parameters\");\n}\n","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 Action,\n Event,\n EventHandler,\n Config,\n ActionExecute,\n RuntimeContext,\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 actions and 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 actions 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 actions: {},\n eventHandlers: new Map(),\n ...initialConfig,\n };\n\n // Add built-in call-action handler\n this.addBuiltInHandlers();\n }\n\n /**\n * Add built-in event handlers that are available in all agents.\n */\n private addBuiltInHandlers(): void {\n // Built-in call-action handler\n this.on(\"call-action\", async function* (event, context) {\n const { action: actionName, params } = event.data as { action: string; params: unknown };\n\n // Execute the action (runtime will automatically emit action:before and action:after events)\n yield* context.runtime.execute(actionName, params);\n });\n }\n\n /**\n * Add an action to the agent with fluent method chaining.\n * Supports two patterns:\n * - Pass a pre-defined Action object\n * - Define action inline with name and handler\n */\n action<TParams = any>(\n action: Action<TParams, any, any>\n ): this;\n action<TParams = any>(\n name: string,\n execute: ActionExecute<TParams, any, any>\n ): this;\n action<TParams = any>(\n nameOrAction: string | Action<TParams, any, any>,\n execute?: ActionExecute<TParams, any, any>\n ): this {\n if (typeof nameOrAction !== 'string') {\n // Called as: .action(action) - pre-defined action object\n // Auto-cast to agent types for better DX\n const typedAction: Action<TParams, TState, TEvent> = {\n name: nameOrAction.name,\n execute: nameOrAction.execute as ActionExecute<TParams, TState, TEvent>,\n };\n this.config.actions[nameOrAction.name] = typedAction;\n return this;\n }\n\n // Called as: .action(name, execute)\n const name = nameOrAction;\n const actionObj: Action<TParams, TState, TEvent> = {\n name,\n execute: execute! as ActionExecute<TParams, TState, TEvent>,\n };\n this.config.actions[name] = actionObj;\n return this;\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: 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 * Use a plugin to extend the builder.\n * This is ideal for modularizing common actions and 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 stream(\n event: TEvent,\n options?: { state?: TState }\n ): Promise<Response> {\n const runtime = this.build();\n const generator = runtime.run(event);\n return createStreamResponse(generator);\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}"]}
|