melony 0.2.2 → 0.2.3
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 +20 -39
- package/dist/client.d.ts +5 -5
- package/dist/client.js +8 -22
- package/dist/client.js.map +1 -1
- package/dist/generate-id-BoQwaY2G.d.ts +66 -0
- package/dist/index.d.ts +8 -29
- package/dist/index.js +14 -136
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/generate-id-DUrFIhxI.d.ts +0 -118
package/README.md
CHANGED
|
@@ -14,17 +14,14 @@ npm install melony
|
|
|
14
14
|
import { melony } from "melony";
|
|
15
15
|
|
|
16
16
|
const agent = melony()
|
|
17
|
-
.
|
|
18
|
-
yield { type: "text", data: { content: `Weather in ${city} is 24°C` } };
|
|
19
|
-
})
|
|
20
|
-
.on("text", async function* (event, { runtime }) {
|
|
17
|
+
.on("user:text", async function* (event, { runtime }) {
|
|
21
18
|
if (event.data.content.includes("weather")) {
|
|
22
|
-
yield
|
|
19
|
+
yield { type: "assistant:text", data: { content: "Weather in London is 24°C" } };
|
|
23
20
|
}
|
|
24
21
|
});
|
|
25
22
|
|
|
26
|
-
// Run it (or use agent.
|
|
27
|
-
for await (const event of agent.build().run({ type: "text", data: { content: "How's the weather?" } })) {
|
|
23
|
+
// Run it (or use agent.streamResponse(event) for HTTP)
|
|
24
|
+
for await (const event of agent.build().run({ type: "user:text", data: { content: "How's the weather?" } })) {
|
|
28
25
|
console.log(event);
|
|
29
26
|
}
|
|
30
27
|
```
|
|
@@ -32,21 +29,15 @@ for await (const event of agent.build().run({ type: "text", data: { content: "Ho
|
|
|
32
29
|
### Legacy: Runtime Class API (Still Supported)
|
|
33
30
|
|
|
34
31
|
```ts
|
|
35
|
-
import {
|
|
32
|
+
import { Runtime } from "melony";
|
|
36
33
|
|
|
37
34
|
// 1. Create the runtime
|
|
38
|
-
const agent = new
|
|
39
|
-
actions: {
|
|
40
|
-
getWeather: {
|
|
41
|
-
name: "getWeather",
|
|
42
|
-
execute: async function* ({ city }: { city: string }) {
|
|
43
|
-
yield { type: "text", data: { content: `Weather in ${city} is sunny!` } };
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
},
|
|
35
|
+
const agent = new Runtime({
|
|
47
36
|
eventHandlers: new Map([
|
|
48
|
-
["text", [async function* (event, { runtime }) {
|
|
49
|
-
|
|
37
|
+
["user:text", [async function* (event, { runtime }) {
|
|
38
|
+
if (event.data.content.includes("weather")) {
|
|
39
|
+
yield { type: "assistant:text", data: { content: "Weather in London is sunny!" } };
|
|
40
|
+
}
|
|
50
41
|
}]]
|
|
51
42
|
])
|
|
52
43
|
});
|
|
@@ -56,46 +47,37 @@ const agent = new MelonyRuntime({
|
|
|
56
47
|
|
|
57
48
|
The fluent builder provides an excellent developer experience with method chaining:
|
|
58
49
|
|
|
59
|
-
### Action Definition
|
|
60
|
-
```ts
|
|
61
|
-
const agent = melony()
|
|
62
|
-
// Register an async generator with a name
|
|
63
|
-
.action("getWeather", async function* ({ city }) {
|
|
64
|
-
yield { type: "text", data: { content: `Weather in ${city} is sunny!` } };
|
|
65
|
-
});
|
|
66
|
-
```
|
|
67
|
-
|
|
68
50
|
### Event Handlers
|
|
69
51
|
```ts
|
|
70
52
|
const agent = melony()
|
|
71
|
-
.on("text", async function* (event, { runtime }) {
|
|
53
|
+
.on("user:text", async function* (event, { runtime }) {
|
|
72
54
|
// Intercept and handle events
|
|
73
55
|
if (event.data.content.includes("help")) {
|
|
74
|
-
yield { type: "text", data: { content: "How can I help you?" } };
|
|
56
|
+
yield { type: "assistant:text", data: { content: "How can I help you?" } };
|
|
75
57
|
}
|
|
76
58
|
})
|
|
77
|
-
.on("
|
|
78
|
-
console.log(`
|
|
59
|
+
.on("assistant:text", async function* (event) {
|
|
60
|
+
console.log(`Agent said: ${event.data.content}`);
|
|
79
61
|
})
|
|
80
62
|
.build();
|
|
81
63
|
```
|
|
82
64
|
|
|
83
65
|
### Plugin System
|
|
84
|
-
Plugins allow you to modularize and reuse
|
|
66
|
+
Plugins allow you to modularize and reuse handlers across different agents. A plugin is simply a function that receives the `MelonyBuilder`.
|
|
85
67
|
|
|
86
68
|
```ts
|
|
87
69
|
import { melony, MelonyPlugin } from "melony";
|
|
88
70
|
|
|
89
71
|
const loggingPlugin: MelonyPlugin = (builder) => {
|
|
90
|
-
builder.on("
|
|
91
|
-
console.log(`[Plugin]
|
|
72
|
+
builder.on("*", async function* (event) {
|
|
73
|
+
console.log(`[Plugin] Event: ${event.type}`);
|
|
92
74
|
});
|
|
93
75
|
};
|
|
94
76
|
|
|
95
77
|
const agent = melony()
|
|
96
78
|
.use(loggingPlugin)
|
|
97
|
-
.
|
|
98
|
-
yield { type: "text", data: { content: "Hello!" } };
|
|
79
|
+
.on("user:text", async function* () {
|
|
80
|
+
yield { type: "assistant:text", data: { content: "Hello!" } };
|
|
99
81
|
});
|
|
100
82
|
```
|
|
101
83
|
|
|
@@ -103,12 +85,11 @@ const agent = melony()
|
|
|
103
85
|
- **Full type inference** through the entire chain
|
|
104
86
|
- **IntelliSense** for all methods and parameters
|
|
105
87
|
- **Generic propagation** maintains type safety
|
|
106
|
-
- **Minimalist core** with zero required dependencies
|
|
88
|
+
- **Minimalist core** with zero required dependencies
|
|
107
89
|
|
|
108
90
|
## Core Concepts
|
|
109
91
|
|
|
110
92
|
- **Event**: The universal unit of streaming (`{ type, data, meta }`).
|
|
111
|
-
- **Action**: An async generator that yields events.
|
|
112
93
|
- **Event Handlers**: Reactive functions that listen to and emit events.
|
|
113
94
|
|
|
114
95
|
## License
|
package/dist/client.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { E as Event } from './generate-id-
|
|
2
|
-
export {
|
|
1
|
+
import { E as Event } from './generate-id-BoQwaY2G.js';
|
|
2
|
+
export { g as generateId } from './generate-id-BoQwaY2G.js';
|
|
3
3
|
|
|
4
4
|
interface ClientState<TEvent extends Event = Event> {
|
|
5
5
|
events: TEvent[];
|
|
6
|
-
|
|
6
|
+
streaming: boolean;
|
|
7
7
|
error: Error | null;
|
|
8
8
|
}
|
|
9
9
|
interface MelonyClientOptions<TEvent extends Event = Event> {
|
|
@@ -22,12 +22,12 @@ declare class MelonyClient<TEvent extends Event = Event> {
|
|
|
22
22
|
subscribe(listener: (state: ClientState<TEvent>) => void): () => void;
|
|
23
23
|
getState(): {
|
|
24
24
|
events: TEvent[];
|
|
25
|
-
|
|
25
|
+
streaming: boolean;
|
|
26
26
|
error: Error | null;
|
|
27
27
|
};
|
|
28
28
|
private getRequestHeaders;
|
|
29
29
|
private setState;
|
|
30
|
-
|
|
30
|
+
send(event: TEvent): AsyncGenerator<TEvent>;
|
|
31
31
|
private handleIncomingEvent;
|
|
32
32
|
reset(events?: TEvent[]): void;
|
|
33
33
|
}
|
package/dist/client.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { generateId } from './chunk-WAI5H335.js';
|
|
2
1
|
export { generateId } from './chunk-WAI5H335.js';
|
|
3
2
|
|
|
4
3
|
// src/client.ts
|
|
@@ -11,7 +10,7 @@ var MelonyClient = class {
|
|
|
11
10
|
this.headers = options.headers;
|
|
12
11
|
this.state = {
|
|
13
12
|
events: options.initialEvents ?? [],
|
|
14
|
-
|
|
13
|
+
streaming: false,
|
|
15
14
|
error: null
|
|
16
15
|
};
|
|
17
16
|
}
|
|
@@ -38,24 +37,14 @@ var MelonyClient = class {
|
|
|
38
37
|
this.state = { ...this.state, ...updates };
|
|
39
38
|
this.stateListeners.forEach((l) => l(this.getState()));
|
|
40
39
|
}
|
|
41
|
-
async *
|
|
40
|
+
async *send(event) {
|
|
42
41
|
if (this.abortController) this.abortController.abort();
|
|
43
42
|
this.abortController = new AbortController();
|
|
44
|
-
const runId = event.meta?.runId ?? generateId();
|
|
45
|
-
const state = event.meta?.state ?? this.lastServerState;
|
|
46
43
|
const optimisticEvent = {
|
|
47
|
-
...event
|
|
48
|
-
meta: {
|
|
49
|
-
...event.meta,
|
|
50
|
-
id: event.meta?.id ?? generateId(),
|
|
51
|
-
runId,
|
|
52
|
-
state,
|
|
53
|
-
role: event.meta?.role ?? "user",
|
|
54
|
-
timestamp: event.meta?.timestamp ?? Date.now()
|
|
55
|
-
}
|
|
44
|
+
...event
|
|
56
45
|
};
|
|
57
46
|
this.setState({
|
|
58
|
-
|
|
47
|
+
streaming: true,
|
|
59
48
|
error: null,
|
|
60
49
|
events: [...this.state.events, optimisticEvent]
|
|
61
50
|
});
|
|
@@ -90,21 +79,18 @@ var MelonyClient = class {
|
|
|
90
79
|
}
|
|
91
80
|
}
|
|
92
81
|
}
|
|
93
|
-
this.setState({
|
|
82
|
+
this.setState({ streaming: false });
|
|
94
83
|
} catch (err) {
|
|
95
84
|
if (err instanceof Error && err.name === "AbortError") {
|
|
96
|
-
this.setState({
|
|
85
|
+
this.setState({ streaming: false });
|
|
97
86
|
return;
|
|
98
87
|
}
|
|
99
88
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
100
|
-
this.setState({ error,
|
|
89
|
+
this.setState({ error, streaming: false });
|
|
101
90
|
throw error;
|
|
102
91
|
}
|
|
103
92
|
}
|
|
104
93
|
handleIncomingEvent(event) {
|
|
105
|
-
if (event.meta?.state) {
|
|
106
|
-
this.lastServerState = event.meta.state;
|
|
107
|
-
}
|
|
108
94
|
const events = [...this.state.events];
|
|
109
95
|
events.push(event);
|
|
110
96
|
this.setState({ events });
|
|
@@ -114,7 +100,7 @@ var MelonyClient = class {
|
|
|
114
100
|
this.setState({
|
|
115
101
|
events,
|
|
116
102
|
error: null,
|
|
117
|
-
|
|
103
|
+
streaming: false
|
|
118
104
|
});
|
|
119
105
|
}
|
|
120
106
|
};
|
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 streaming: 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 streaming: 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 *send(event: TEvent): AsyncGenerator<TEvent> {\n if (this.abortController) this.abortController.abort();\n this.abortController = new AbortController();\n\n const optimisticEvent: TEvent = {\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 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({ 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 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 streaming: false,\n });\n }\n}\n"]}
|
|
@@ -0,0 +1,66 @@
|
|
|
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
|
+
private queue;
|
|
8
|
+
private isEmitting;
|
|
9
|
+
constructor(config: Config<TState, TEvent>);
|
|
10
|
+
/**
|
|
11
|
+
* Process an incoming event through the runtime.
|
|
12
|
+
* All event processing is handled by user-defined event handlers.
|
|
13
|
+
*/
|
|
14
|
+
run(event: TEvent, options?: {
|
|
15
|
+
state?: TState;
|
|
16
|
+
runId?: string;
|
|
17
|
+
}): AsyncGenerator<TEvent>;
|
|
18
|
+
/**
|
|
19
|
+
* Run all event handlers that match the given event type.
|
|
20
|
+
*/
|
|
21
|
+
private runEventHandlers;
|
|
22
|
+
/**
|
|
23
|
+
* Internal helper to yield an event with metadata.
|
|
24
|
+
*/
|
|
25
|
+
private emit;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The core Event structure.
|
|
30
|
+
* Fully unopinionated - just type, data, and optional metadata.
|
|
31
|
+
*/
|
|
32
|
+
type Event<TData = any> = {
|
|
33
|
+
type: string;
|
|
34
|
+
data: TData;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Built-in error event emitted by the runtime.
|
|
38
|
+
*/
|
|
39
|
+
interface ErrorEvent extends Event<{
|
|
40
|
+
message: string;
|
|
41
|
+
stack?: string;
|
|
42
|
+
}> {
|
|
43
|
+
type: "error";
|
|
44
|
+
}
|
|
45
|
+
interface RuntimeContext<TState = any, TEvent extends Event = Event> {
|
|
46
|
+
state: TState;
|
|
47
|
+
runId: string;
|
|
48
|
+
runtime: Runtime<TState, TEvent>;
|
|
49
|
+
/**
|
|
50
|
+
* Immediately interrupts the runtime execution.
|
|
51
|
+
* If an event is provided, it will be emitted before the runtime stops.
|
|
52
|
+
*/
|
|
53
|
+
suspend: (event?: TEvent) => never;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Event handler function for processing events.
|
|
57
|
+
* Can return events to emit or undefined to continue processing.
|
|
58
|
+
*/
|
|
59
|
+
type EventHandler<TState = any, TEvent extends Event = Event> = (event: TEvent, context?: RuntimeContext<TState, TEvent>) => AsyncGenerator<TEvent, void, unknown> | void;
|
|
60
|
+
interface Config<TState = any, TEvent extends Event = Event> {
|
|
61
|
+
eventHandlers: Map<string, EventHandler<TState, TEvent>[]>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
declare const generateId: () => string;
|
|
65
|
+
|
|
66
|
+
export { type Config as C, type Event as E, Runtime as R, type RuntimeContext as a, type ErrorEvent as b, type EventHandler as c, generateId as g };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,42 +1,20 @@
|
|
|
1
|
-
import { R as Runtime,
|
|
2
|
-
export {
|
|
1
|
+
import { R as Runtime, E as Event, C as Config, a as RuntimeContext } from './generate-id-BoQwaY2G.js';
|
|
2
|
+
export { b as ErrorEvent, c as EventHandler, g as generateId } from './generate-id-BoQwaY2G.js';
|
|
3
3
|
|
|
4
4
|
declare const MelonyRuntime: typeof Runtime;
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* Create an action with just a name and handler.
|
|
8
|
-
* Compatible with any agent - types are resolved automatically when added to an agent.
|
|
9
|
-
*/
|
|
10
|
-
declare function action<TParams = any>(name: string, execute: ActionExecute<TParams, any, any>): Action<TParams, any, any>;
|
|
11
|
-
/**
|
|
12
|
-
* Helper to define an action with full type inference (for advanced use cases).
|
|
13
|
-
*/
|
|
14
|
-
declare function action<TParams = any, TState = any, TEvent extends Event = Event>(config: Action<TParams, TState, TEvent>): Action<TParams, TState, TEvent>;
|
|
15
|
-
|
|
16
6
|
/**
|
|
17
7
|
* A Melony plugin is a function that receives the builder and extends it.
|
|
18
|
-
* This allows for modularizing common
|
|
8
|
+
* This allows for modularizing common handlers.
|
|
19
9
|
*/
|
|
20
10
|
type MelonyPlugin<TState = any, TEvent extends Event = Event> = (builder: MelonyBuilder<TState, TEvent>) => void;
|
|
21
11
|
/**
|
|
22
12
|
* Fluent builder for creating Melony agents with excellent developer experience.
|
|
23
|
-
* Provides method chaining for
|
|
13
|
+
* Provides method chaining for handlers and plugins with full TypeScript support.
|
|
24
14
|
*/
|
|
25
15
|
declare class MelonyBuilder<TState = any, TEvent extends Event = Event> {
|
|
26
16
|
private config;
|
|
27
17
|
constructor(initialConfig?: Partial<Config<TState, TEvent>>);
|
|
28
|
-
/**
|
|
29
|
-
* Add built-in event handlers that are available in all agents.
|
|
30
|
-
*/
|
|
31
|
-
private addBuiltInHandlers;
|
|
32
|
-
/**
|
|
33
|
-
* Add an action to the agent with fluent method chaining.
|
|
34
|
-
* Supports two patterns:
|
|
35
|
-
* - Pass a pre-defined Action object
|
|
36
|
-
* - Define action inline with name and handler
|
|
37
|
-
*/
|
|
38
|
-
action<TParams = any>(action: Action<TParams, any, any>): this;
|
|
39
|
-
action<TParams = any>(name: string, execute: ActionExecute<TParams, any, any>): this;
|
|
40
18
|
/**
|
|
41
19
|
* Add an event handler for a specific event type. Supports method chaining.
|
|
42
20
|
* The handler receives the narrowed event type based on the eventType string.
|
|
@@ -46,7 +24,7 @@ declare class MelonyBuilder<TState = any, TEvent extends Event = Event> {
|
|
|
46
24
|
}>, context: RuntimeContext<TState, TEvent>) => AsyncGenerator<TEvent, void, unknown> | void): this;
|
|
47
25
|
/**
|
|
48
26
|
* Use a plugin to extend the builder.
|
|
49
|
-
* This is ideal for modularizing common
|
|
27
|
+
* This is ideal for modularizing common handlers.
|
|
50
28
|
*/
|
|
51
29
|
use(plugin: MelonyPlugin<TState, TEvent>): this;
|
|
52
30
|
/**
|
|
@@ -58,8 +36,9 @@ declare class MelonyBuilder<TState = any, TEvent extends Event = Event> {
|
|
|
58
36
|
* Execute and stream the response for an event.
|
|
59
37
|
* This is a convenience method that builds the runtime and calls run().
|
|
60
38
|
*/
|
|
61
|
-
|
|
39
|
+
streamResponse(event: TEvent, options?: {
|
|
62
40
|
state?: TState;
|
|
41
|
+
runId?: string;
|
|
63
42
|
}): Promise<Response>;
|
|
64
43
|
/**
|
|
65
44
|
* Get the current configuration (useful for debugging or serialization).
|
|
@@ -78,4 +57,4 @@ declare function melony<TState = any, TEvent extends Event = Event>(initialConfi
|
|
|
78
57
|
*/
|
|
79
58
|
declare function createStreamResponse(generator: AsyncGenerator<Event>): Response;
|
|
80
59
|
|
|
81
|
-
export {
|
|
60
|
+
export { Config, Event, MelonyBuilder, type MelonyPlugin, MelonyRuntime, Runtime, RuntimeContext, createStreamResponse, melony };
|
package/dist/index.js
CHANGED
|
@@ -11,87 +11,16 @@ var Runtime = class {
|
|
|
11
11
|
this.isEmitting = false;
|
|
12
12
|
this.config = config;
|
|
13
13
|
}
|
|
14
|
-
/**
|
|
15
|
-
* Run an action by name with given params.
|
|
16
|
-
* This is the primary way to execute actions.
|
|
17
|
-
*/
|
|
18
|
-
async *execute(actionName, params, options) {
|
|
19
|
-
const runId = options?.runId ?? generateId();
|
|
20
|
-
const context = {
|
|
21
|
-
state: options?.state ?? {},
|
|
22
|
-
runtime: this,
|
|
23
|
-
runId,
|
|
24
|
-
actions: this.config.actions,
|
|
25
|
-
suspend: (event) => {
|
|
26
|
-
throw event || { type: "run-suspended", data: {} };
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
const action2 = this.config.actions[actionName];
|
|
30
|
-
if (!action2) {
|
|
31
|
-
yield* this.emit(
|
|
32
|
-
{
|
|
33
|
-
type: "error",
|
|
34
|
-
data: { message: `Action "${actionName}" not found` }
|
|
35
|
-
},
|
|
36
|
-
context
|
|
37
|
-
);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
try {
|
|
41
|
-
yield* this.emit(
|
|
42
|
-
{
|
|
43
|
-
type: "action:before",
|
|
44
|
-
data: { action: actionName, params }
|
|
45
|
-
},
|
|
46
|
-
context
|
|
47
|
-
);
|
|
48
|
-
const generator = action2.execute(params, context);
|
|
49
|
-
let result = void 0;
|
|
50
|
-
while (true) {
|
|
51
|
-
const { value, done } = await generator.next();
|
|
52
|
-
if (done) {
|
|
53
|
-
result = value;
|
|
54
|
-
break;
|
|
55
|
-
}
|
|
56
|
-
yield* this.emit(value, context);
|
|
57
|
-
}
|
|
58
|
-
yield* this.emit(
|
|
59
|
-
{
|
|
60
|
-
type: "action:after",
|
|
61
|
-
data: { action: actionName, result }
|
|
62
|
-
},
|
|
63
|
-
context
|
|
64
|
-
);
|
|
65
|
-
} catch (error) {
|
|
66
|
-
let eventToEmit;
|
|
67
|
-
if (isEvent(error)) {
|
|
68
|
-
eventToEmit = error;
|
|
69
|
-
} else {
|
|
70
|
-
eventToEmit = {
|
|
71
|
-
type: "error",
|
|
72
|
-
data: {
|
|
73
|
-
action: actionName,
|
|
74
|
-
message: error instanceof Error ? error.message : String(error),
|
|
75
|
-
stack: error instanceof Error ? error.stack : void 0
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
if (eventToEmit) {
|
|
80
|
-
yield* this.emit(eventToEmit, context);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
14
|
/**
|
|
85
15
|
* Process an incoming event through the runtime.
|
|
86
16
|
* All event processing is handled by user-defined event handlers.
|
|
87
17
|
*/
|
|
88
|
-
async *run(event) {
|
|
89
|
-
const runId =
|
|
18
|
+
async *run(event, options) {
|
|
19
|
+
const runId = options?.runId ?? generateId();
|
|
90
20
|
const context = {
|
|
91
|
-
state:
|
|
21
|
+
state: options?.state ?? {},
|
|
92
22
|
runtime: this,
|
|
93
23
|
runId,
|
|
94
|
-
actions: this.config.actions,
|
|
95
24
|
suspend: (event2) => {
|
|
96
25
|
throw event2 || { type: "run-suspended", data: {} };
|
|
97
26
|
}
|
|
@@ -120,12 +49,15 @@ var Runtime = class {
|
|
|
120
49
|
* Run all event handlers that match the given event type.
|
|
121
50
|
*/
|
|
122
51
|
async *runEventHandlers(event, context) {
|
|
123
|
-
const handlers =
|
|
52
|
+
const handlers = [
|
|
53
|
+
...this.config.eventHandlers.get(event.type) || [],
|
|
54
|
+
...this.config.eventHandlers.get("*") || []
|
|
55
|
+
];
|
|
56
|
+
yield* this.emit(event, context);
|
|
124
57
|
for (const handler of handlers) {
|
|
125
58
|
const result = handler(event, context);
|
|
126
59
|
if (result) {
|
|
127
60
|
for await (const yieldedEvent of result) {
|
|
128
|
-
yield yieldedEvent;
|
|
129
61
|
yield* this.runEventHandlers(yieldedEvent, context);
|
|
130
62
|
}
|
|
131
63
|
}
|
|
@@ -133,7 +65,6 @@ var Runtime = class {
|
|
|
133
65
|
}
|
|
134
66
|
/**
|
|
135
67
|
* Internal helper to yield an event with metadata.
|
|
136
|
-
* Handlers are invoked by runEventHandlers when events bubble up.
|
|
137
68
|
*/
|
|
138
69
|
async *emit(event, context) {
|
|
139
70
|
this.queue.push(event);
|
|
@@ -142,19 +73,7 @@ var Runtime = class {
|
|
|
142
73
|
try {
|
|
143
74
|
while (this.queue.length > 0) {
|
|
144
75
|
const current = this.queue.shift();
|
|
145
|
-
|
|
146
|
-
...current,
|
|
147
|
-
meta: {
|
|
148
|
-
...current.meta,
|
|
149
|
-
id: current.meta?.id ?? generateId(),
|
|
150
|
-
runtime: this,
|
|
151
|
-
runId: context.runId,
|
|
152
|
-
timestamp: current.meta?.timestamp ?? Date.now(),
|
|
153
|
-
role: current.meta?.role ?? "assistant",
|
|
154
|
-
state: context.state
|
|
155
|
-
}
|
|
156
|
-
};
|
|
157
|
-
yield finalEvent;
|
|
76
|
+
yield current;
|
|
158
77
|
}
|
|
159
78
|
} finally {
|
|
160
79
|
this.isEmitting = false;
|
|
@@ -165,18 +84,6 @@ var Runtime = class {
|
|
|
165
84
|
// src/melony.ts
|
|
166
85
|
var MelonyRuntime = Runtime;
|
|
167
86
|
|
|
168
|
-
// src/action.ts
|
|
169
|
-
function action(...args) {
|
|
170
|
-
if (typeof args[0] === "string") {
|
|
171
|
-
const [name, execute] = args;
|
|
172
|
-
return { name, execute };
|
|
173
|
-
}
|
|
174
|
-
if (typeof args[0] === "object" && args[0] !== null && "name" in args[0] && "execute" in args[0]) {
|
|
175
|
-
return args[0];
|
|
176
|
-
}
|
|
177
|
-
throw new Error("Invalid action parameters");
|
|
178
|
-
}
|
|
179
|
-
|
|
180
87
|
// src/utils/create-stream-response.ts
|
|
181
88
|
function createStreamResponse(generator) {
|
|
182
89
|
const encoder = new TextEncoder();
|
|
@@ -208,37 +115,8 @@ function createStreamResponse(generator) {
|
|
|
208
115
|
var MelonyBuilder = class {
|
|
209
116
|
constructor(initialConfig) {
|
|
210
117
|
this.config = {
|
|
211
|
-
|
|
212
|
-
eventHandlers: /* @__PURE__ */ new Map(),
|
|
213
|
-
...initialConfig
|
|
118
|
+
eventHandlers: initialConfig?.eventHandlers ?? /* @__PURE__ */ new Map()
|
|
214
119
|
};
|
|
215
|
-
this.addBuiltInHandlers();
|
|
216
|
-
}
|
|
217
|
-
/**
|
|
218
|
-
* Add built-in event handlers that are available in all agents.
|
|
219
|
-
*/
|
|
220
|
-
addBuiltInHandlers() {
|
|
221
|
-
this.on("call-action", async function* (event, context) {
|
|
222
|
-
const { action: actionName, params } = event.data;
|
|
223
|
-
yield* context.runtime.execute(actionName, params);
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
action(nameOrAction, execute) {
|
|
227
|
-
if (typeof nameOrAction !== "string") {
|
|
228
|
-
const typedAction = {
|
|
229
|
-
name: nameOrAction.name,
|
|
230
|
-
execute: nameOrAction.execute
|
|
231
|
-
};
|
|
232
|
-
this.config.actions[nameOrAction.name] = typedAction;
|
|
233
|
-
return this;
|
|
234
|
-
}
|
|
235
|
-
const name = nameOrAction;
|
|
236
|
-
const actionObj = {
|
|
237
|
-
name,
|
|
238
|
-
execute
|
|
239
|
-
};
|
|
240
|
-
this.config.actions[name] = actionObj;
|
|
241
|
-
return this;
|
|
242
120
|
}
|
|
243
121
|
/**
|
|
244
122
|
* Add an event handler for a specific event type. Supports method chaining.
|
|
@@ -253,7 +131,7 @@ var MelonyBuilder = class {
|
|
|
253
131
|
}
|
|
254
132
|
/**
|
|
255
133
|
* Use a plugin to extend the builder.
|
|
256
|
-
* This is ideal for modularizing common
|
|
134
|
+
* This is ideal for modularizing common handlers.
|
|
257
135
|
*/
|
|
258
136
|
use(plugin) {
|
|
259
137
|
plugin(this);
|
|
@@ -270,9 +148,9 @@ var MelonyBuilder = class {
|
|
|
270
148
|
* Execute and stream the response for an event.
|
|
271
149
|
* This is a convenience method that builds the runtime and calls run().
|
|
272
150
|
*/
|
|
273
|
-
async
|
|
151
|
+
async streamResponse(event, options) {
|
|
274
152
|
const runtime = this.build();
|
|
275
|
-
const generator = runtime.run(event);
|
|
153
|
+
const generator = runtime.run(event, options);
|
|
276
154
|
return createStreamResponse(generator);
|
|
277
155
|
}
|
|
278
156
|
/**
|
|
@@ -286,6 +164,6 @@ function melony(initialConfig) {
|
|
|
286
164
|
return new MelonyBuilder(initialConfig);
|
|
287
165
|
}
|
|
288
166
|
|
|
289
|
-
export { MelonyBuilder, MelonyRuntime, Runtime,
|
|
167
|
+
export { MelonyBuilder, MelonyRuntime, Runtime, createStreamResponse, melony };
|
|
290
168
|
//# sourceMappingURL=index.js.map
|
|
291
169
|
//# sourceMappingURL=index.js.map
|
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":";;;;AAYA,SAAS,QAAQ,GAAA,EAAwB;AACvC,EAAA,OAAO,OAAO,OAAO,GAAA,KAAQ,QAAA,IAAY,OAAO,IAAI,IAAA,KAAS,QAAA;AAC/D;AAOO,IAAM,UAAN,MAA0D;AAAA,EAK/D,YAAY,MAAA,EAAgC;AAH5C,IAAA,IAAA,CAAQ,QAAkB,EAAC;AAC3B,IAAA,IAAA,CAAQ,UAAA,GAAa,KAAA;AAGnB,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAc,OAAA,CACZ,UAAA,EACA,MAAA,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,KAAK,MAAA,CAAO,OAAA;AAAA,MACrB,OAAA,EAAS,CAAC,KAAA,KAAmB;AAC3B,QAAA,MAAM,SAAS,EAAE,IAAA,EAAM,eAAA,EAAiB,IAAA,EAAM,EAAC,EAAE;AAAA,MACnD;AAAA,KACF;AAEA,IAAA,MAAMA,OAAAA,GAAS,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,UAAU,CAAA;AAC7C,IAAA,IAAI,CAACA,OAAAA,EAAQ;AACX,MAAA,OAAO,IAAA,CAAK,IAAA;AAAA,QACV;AAAA,UACE,IAAA,EAAM,OAAA;AAAA,UACN,IAAA,EAAM,EAAE,OAAA,EAAS,CAAA,QAAA,EAAW,UAAU,CAAA,WAAA,CAAA;AAAc,SACtD;AAAA,QACA;AAAA,OACF;AACA,MAAA;AAAA,IACF;AAEA,IAAA,IAAI;AAEF,MAAA,OAAO,IAAA,CAAK,IAAA;AAAA,QACV;AAAA,UACE,IAAA,EAAM,eAAA;AAAA,UACN,IAAA,EAAM,EAAE,MAAA,EAAQ,UAAA,EAAY,MAAA;AAAO,SACrC;AAAA,QACA;AAAA,OACF;AAGA,MAAA,MAAM,SAAA,GAAYA,OAAAA,CAAO,OAAA,CAAQ,MAAA,EAAQ,OAAO,CAAA;AAChD,MAAA,IAAI,MAAA,GAAc,KAAA,CAAA;AAElB,MAAA,OAAO,IAAA,EAAM;AACX,QAAA,MAAM,EAAE,KAAA,EAAO,IAAA,EAAK,GAAI,MAAM,UAAU,IAAA,EAAK;AAC7C,QAAA,IAAI,IAAA,EAAM;AACR,UAAA,MAAA,GAAS,KAAA;AACT,UAAA;AAAA,QACF;AACA,QAAA,OAAO,IAAA,CAAK,IAAA,CAAK,KAAA,EAAiB,OAAO,CAAA;AAAA,MAC3C;AAGA,MAAA,OAAO,IAAA,CAAK,IAAA;AAAA,QACV;AAAA,UACE,IAAA,EAAM,cAAA;AAAA,UACN,IAAA,EAAM,EAAE,MAAA,EAAQ,UAAA,EAAY,MAAA;AAAO,SACrC;AAAA,QACA;AAAA,OACF;AAAA,IACF,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,MAAA,EAAQ,UAAA;AAAA,YACR,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;AAAA,EAMA,OAAc,IAAI,KAAA,EAAuC;AACvD,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,IAAA,EAAM,KAAA,IAAS,UAAA,EAAW;AAE9C,IAAA,MAAM,OAAA,GAA0C;AAAA,MAC9C,KAAA,EAAQ,KAAA,CAAM,IAAA,EAAM,KAAA,IAAS,EAAC;AAAA,MAC9B,OAAA,EAAS,IAAA;AAAA,MACT,KAAA;AAAA,MACA,OAAA,EAAS,KAAK,MAAA,CAAO,OAAA;AAAA,MACrB,OAAA,EAAS,CAACC,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,MAAM,QAAA,GAAW,KAAK,MAAA,CAAO,aAAA,CAAc,IAAI,KAAA,CAAM,IAAI,KAAK,EAAC;AAC/D,IAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,MAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,KAAA,EAAO,OAAO,CAAA;AACrC,MAAA,IAAI,MAAA,EAAQ;AACV,QAAA,WAAA,MAAiB,gBAAgB,MAAA,EAAQ;AACvC,UAAA,MAAM,YAAA;AAEN,UAAA,OAAO,IAAA,CAAK,gBAAA,CAAiB,YAAA,EAAc,OAAO,CAAA;AAAA,QACpD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAe,IAAA,CACb,KAAA,EACA,OAAA,EACwB;AACxB,IAAA,IAAA,CAAK,KAAA,CAAM,KAAK,KAAK,CAAA;AAErB,IAAA,IAAI,KAAK,UAAA,EAAY;AAErB,IAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAClB,IAAA,IAAI;AACF,MAAA,OAAO,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG;AAC5B,QAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,KAAA,EAAM;AAEjC,QAAA,MAAM,UAAA,GAAqB;AAAA,UACzB,GAAG,OAAA;AAAA,UACH,IAAA,EAAM;AAAA,YACJ,GAAG,OAAA,CAAQ,IAAA;AAAA,YACX,EAAA,EAAI,OAAA,CAAQ,IAAA,EAAM,EAAA,IAAM,UAAA,EAAW;AAAA,YACnC,OAAA,EAAS,IAAA;AAAA,YACT,OAAO,OAAA,CAAQ,KAAA;AAAA,YACf,SAAA,EAAW,OAAA,CAAQ,IAAA,EAAM,SAAA,IAAa,KAAK,GAAA,EAAI;AAAA,YAC/C,IAAA,EAAM,OAAA,CAAQ,IAAA,EAAM,IAAA,IAAQ,WAAA;AAAA,YAC5B,OAAO,OAAA,CAAQ;AAAA;AACjB,SACF;AAEA,QAAA,MAAM,UAAA;AAAA,MACR;AAAA,IACF,CAAA,SAAE;AACA,MAAA,IAAA,CAAK,UAAA,GAAa,KAAA;AAAA,IACpB;AAAA,EACF;AACF;;;ACpNO,IAAM,aAAA,GAAgB;;;ACkBtB,SAAS,UAKX,IAAA,EAC0D;AAC7D,EAAA,IAAI,OAAO,IAAA,CAAK,CAAC,CAAA,KAAM,QAAA,EAAU;AAC/B,IAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,IAAA;AACxB,IAAA,OAAO,EAAE,MAAM,OAAA,EAAQ;AAAA,EACzB;AAEA,EAAA,IAAI,OAAO,IAAA,CAAK,CAAC,CAAA,KAAM,QAAA,IAAY,KAAK,CAAC,CAAA,KAAM,IAAA,IAAQ,MAAA,IAAU,KAAK,CAAC,CAAA,IAAK,SAAA,IAAa,IAAA,CAAK,CAAC,CAAA,EAAG;AAChG,IAAA,OAAO,KAAK,CAAC,CAAA;AAAA,EACf;AAEA,EAAA,MAAM,IAAI,MAAM,2BAA2B,CAAA;AAC7C;;;AC/BO,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;;;ACTO,IAAM,gBAAN,MAGL;AAAA,EAGA,YAAY,aAAA,EAAiD;AAC3D,IAAA,IAAA,CAAK,MAAA,GAAS;AAAA,MACZ,SAAS,EAAC;AAAA,MACV,aAAA,sBAAmB,GAAA,EAAI;AAAA,MACvB,GAAG;AAAA,KACL;AAGA,IAAA,IAAA,CAAK,kBAAA,EAAmB;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAA,GAA2B;AAEjC,IAAA,IAAA,CAAK,EAAA,CAAG,aAAA,EAAe,iBAAiB,KAAA,EAAO,OAAA,EAAS;AACtD,MAAA,MAAM,EAAE,MAAA,EAAQ,UAAA,EAAY,MAAA,KAAW,KAAA,CAAM,IAAA;AAG7C,MAAA,OAAO,OAAA,CAAQ,OAAA,CAAQ,OAAA,CAAQ,UAAA,EAAY,MAAM,CAAA;AAAA,IACnD,CAAC,CAAA;AAAA,EACH;AAAA,EAeA,MAAA,CACE,cACA,OAAA,EACM;AACN,IAAA,IAAI,OAAO,iBAAiB,QAAA,EAAU;AAGpC,MAAA,MAAM,WAAA,GAA+C;AAAA,QACnD,MAAM,YAAA,CAAa,IAAA;AAAA,QACnB,SAAS,YAAA,CAAa;AAAA,OACxB;AACA,MAAA,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,YAAA,CAAa,IAAI,CAAA,GAAI,WAAA;AACzC,MAAA,OAAO,IAAA;AAAA,IACT;AAGA,IAAA,MAAM,IAAA,GAAO,YAAA;AACb,IAAA,MAAM,SAAA,GAA6C;AAAA,MACjD,IAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,IAAI,CAAA,GAAI,SAAA;AAC5B,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,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;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,MAAA,CACJ,KAAA,EACA,OAAA,EACmB;AACnB,IAAA,MAAM,OAAA,GAAU,KAAK,KAAA,EAAM;AAC3B,IAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA;AACnC,IAAA,OAAO,qBAAqB,SAAS,CAAA;AAAA,EACvC;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 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}"]}
|
|
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 private queue: TEvent[] = [];\n private isEmitting = false;\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 const handlers = [\n ...(this.config.eventHandlers.get(event.type) || []),\n ...(this.config.eventHandlers.get(\"*\") || []),\n ];\n \n // First emit the event itself\n yield* this.emit(event, context);\n\n for (const handler of handlers) {\n const result = handler(event, 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 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 yield current;\n }\n } finally {\n this.isEmitting = false;\n }\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} 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 };\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 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 * 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,118 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The Melony Runtime.
|
|
3
|
-
* Fully unopinionated - executes a single action per run.
|
|
4
|
-
* Chaining/looping is left to userland.
|
|
5
|
-
*/
|
|
6
|
-
declare class Runtime<TState = any, TEvent extends Event = Event> {
|
|
7
|
-
readonly config: Config<TState, TEvent>;
|
|
8
|
-
private queue;
|
|
9
|
-
private isEmitting;
|
|
10
|
-
constructor(config: Config<TState, TEvent>);
|
|
11
|
-
/**
|
|
12
|
-
* Run an action by name with given params.
|
|
13
|
-
* This is the primary way to execute actions.
|
|
14
|
-
*/
|
|
15
|
-
execute(actionName: string, params: any, options?: {
|
|
16
|
-
state?: TState;
|
|
17
|
-
runId?: string;
|
|
18
|
-
}): AsyncGenerator<TEvent>;
|
|
19
|
-
/**
|
|
20
|
-
* Process an incoming event through the runtime.
|
|
21
|
-
* All event processing is handled by user-defined event handlers.
|
|
22
|
-
*/
|
|
23
|
-
run(event: TEvent): 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
|
-
* Handlers are invoked by runEventHandlers when events bubble up.
|
|
31
|
-
*/
|
|
32
|
-
private emit;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
type Role = "user" | "assistant" | "system";
|
|
36
|
-
/**
|
|
37
|
-
* System-managed metadata for an event.
|
|
38
|
-
*/
|
|
39
|
-
interface EventMeta<TState = any> {
|
|
40
|
-
id: string;
|
|
41
|
-
runId: string;
|
|
42
|
-
timestamp: number;
|
|
43
|
-
role: Role;
|
|
44
|
-
state: TState;
|
|
45
|
-
[key: string]: any;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* The core Event structure.
|
|
49
|
-
* Fully unopinionated - just type, data, and optional metadata.
|
|
50
|
-
*/
|
|
51
|
-
type Event<TData = any> = {
|
|
52
|
-
type: string;
|
|
53
|
-
data: TData;
|
|
54
|
-
meta?: EventMeta;
|
|
55
|
-
};
|
|
56
|
-
/**
|
|
57
|
-
* Built-in action lifecycle events emitted by the runtime.
|
|
58
|
-
*/
|
|
59
|
-
interface ActionBeforeEvent extends Event<{
|
|
60
|
-
action: string;
|
|
61
|
-
params: any;
|
|
62
|
-
}> {
|
|
63
|
-
type: "action:before";
|
|
64
|
-
}
|
|
65
|
-
interface ActionAfterEvent extends Event<{
|
|
66
|
-
action: string;
|
|
67
|
-
result: any;
|
|
68
|
-
}> {
|
|
69
|
-
type: "action:after";
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Built-in call-action event for triggering action execution.
|
|
73
|
-
*/
|
|
74
|
-
interface CallActionEvent extends Event<{
|
|
75
|
-
action: string;
|
|
76
|
-
params: unknown;
|
|
77
|
-
}> {
|
|
78
|
-
type: "call-action";
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Built-in error event emitted by the runtime.
|
|
82
|
-
*/
|
|
83
|
-
interface ErrorEvent extends Event<{
|
|
84
|
-
message: string;
|
|
85
|
-
action?: string;
|
|
86
|
-
stack?: string;
|
|
87
|
-
}> {
|
|
88
|
-
type: "error";
|
|
89
|
-
}
|
|
90
|
-
type ActionExecute<TParams = any, TState = any, TEvent extends Event = Event> = (params: TParams, context: RuntimeContext<TState, TEvent>) => AsyncGenerator<TEvent, any, unknown>;
|
|
91
|
-
interface Action<TParams = any, TState = any, TEvent extends Event = Event> {
|
|
92
|
-
name: string;
|
|
93
|
-
execute: ActionExecute<TParams, TState, TEvent>;
|
|
94
|
-
}
|
|
95
|
-
interface RuntimeContext<TState = any, TEvent extends Event = Event> {
|
|
96
|
-
state: TState;
|
|
97
|
-
runId: string;
|
|
98
|
-
actions: Record<string, Action<any, TState, TEvent>>;
|
|
99
|
-
runtime: Runtime<TState, TEvent>;
|
|
100
|
-
/**
|
|
101
|
-
* Immediately interrupts the runtime execution.
|
|
102
|
-
* If an event is provided, it will be emitted before the runtime stops.
|
|
103
|
-
*/
|
|
104
|
-
suspend: (event?: TEvent) => never;
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Event handler function for processing events.
|
|
108
|
-
* Can return events to emit or undefined to continue processing.
|
|
109
|
-
*/
|
|
110
|
-
type EventHandler<TState = any, TEvent extends Event = Event> = (event: TEvent, context: RuntimeContext<TState, TEvent>) => AsyncGenerator<TEvent, void, unknown> | void;
|
|
111
|
-
interface Config<TState = any, TEvent extends Event = Event> {
|
|
112
|
-
actions: Record<string, Action<any, TState, TEvent>>;
|
|
113
|
-
eventHandlers: Map<string, EventHandler<TState, TEvent>[]>;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
declare const generateId: () => string;
|
|
117
|
-
|
|
118
|
-
export { type ActionExecute as A, type Config as C, type Event as E, Runtime as R, type Action as a, type RuntimeContext as b, type Role as c, type EventMeta as d, type ActionBeforeEvent as e, type ActionAfterEvent as f, type CallActionEvent as g, type ErrorEvent as h, type EventHandler as i, generateId as j };
|