melony 0.1.14 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-WCI7WEZW.js +315 -0
- package/dist/chunk-WCI7WEZW.js.map +1 -0
- package/dist/client.d.ts +10 -2
- package/dist/client.js +24 -5
- package/dist/client.js.map +1 -1
- package/dist/generate-id-DU8kwYc2.d.ts +3 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -311
- package/dist/index.js.map +1 -1
- package/dist/plugins/require-approval.d.ts +31 -0
- package/dist/plugins/require-approval.js +104 -0
- package/dist/plugins/require-approval.js.map +1 -0
- package/dist/{generate-id-CUOAZU5w.d.ts → types-BC3dKPi6.d.ts} +3 -3
- package/package.json +6 -1
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { generateId } from './chunk-WAI5H335.js';
|
|
2
|
+
|
|
3
|
+
// src/types.ts
|
|
4
|
+
var ui = {
|
|
5
|
+
card: (props) => {
|
|
6
|
+
const { children, ...rest } = props;
|
|
7
|
+
return { type: "card", props: rest, children };
|
|
8
|
+
},
|
|
9
|
+
row: (props) => {
|
|
10
|
+
const { children, ...rest } = props;
|
|
11
|
+
return { type: "row", props: rest, children };
|
|
12
|
+
},
|
|
13
|
+
col: (props) => {
|
|
14
|
+
const { children, ...rest } = props;
|
|
15
|
+
return { type: "col", props: rest, children };
|
|
16
|
+
},
|
|
17
|
+
box: (props) => {
|
|
18
|
+
const { children, ...rest } = props;
|
|
19
|
+
return { type: "box", props: rest, children };
|
|
20
|
+
},
|
|
21
|
+
spacer: (props) => ({
|
|
22
|
+
type: "spacer",
|
|
23
|
+
props
|
|
24
|
+
}),
|
|
25
|
+
divider: (props) => ({
|
|
26
|
+
type: "divider",
|
|
27
|
+
props
|
|
28
|
+
}),
|
|
29
|
+
text: (value, props) => ({
|
|
30
|
+
type: "text",
|
|
31
|
+
props: { ...props, value }
|
|
32
|
+
}),
|
|
33
|
+
heading: (value, level = 1) => ({
|
|
34
|
+
type: "heading",
|
|
35
|
+
props: { value, level }
|
|
36
|
+
}),
|
|
37
|
+
badge: (label, variant = "primary", size = "md") => ({
|
|
38
|
+
type: "badge",
|
|
39
|
+
props: { label, variant, size }
|
|
40
|
+
}),
|
|
41
|
+
image: (src, alt, size = "md") => ({
|
|
42
|
+
type: "image",
|
|
43
|
+
props: { src, alt, size }
|
|
44
|
+
}),
|
|
45
|
+
icon: (name, size = "md", color) => ({
|
|
46
|
+
type: "icon",
|
|
47
|
+
props: { name, size, color }
|
|
48
|
+
}),
|
|
49
|
+
chart: (props) => ({
|
|
50
|
+
type: "chart",
|
|
51
|
+
props
|
|
52
|
+
}),
|
|
53
|
+
list: (children) => ({
|
|
54
|
+
type: "list",
|
|
55
|
+
children
|
|
56
|
+
}),
|
|
57
|
+
listItem: (props) => {
|
|
58
|
+
const { children, ...rest } = props;
|
|
59
|
+
return { type: "listItem", props: rest, children };
|
|
60
|
+
},
|
|
61
|
+
form: (props) => {
|
|
62
|
+
const { children, ...rest } = props;
|
|
63
|
+
return { type: "form", props: rest, children };
|
|
64
|
+
},
|
|
65
|
+
input: (props) => ({
|
|
66
|
+
type: "input",
|
|
67
|
+
props
|
|
68
|
+
}),
|
|
69
|
+
textarea: (props) => ({
|
|
70
|
+
type: "textarea",
|
|
71
|
+
props
|
|
72
|
+
}),
|
|
73
|
+
select: (props) => ({
|
|
74
|
+
type: "select",
|
|
75
|
+
props
|
|
76
|
+
}),
|
|
77
|
+
checkbox: (props) => ({
|
|
78
|
+
type: "checkbox",
|
|
79
|
+
props
|
|
80
|
+
}),
|
|
81
|
+
radioGroup: (props) => ({
|
|
82
|
+
type: "radioGroup",
|
|
83
|
+
props
|
|
84
|
+
}),
|
|
85
|
+
label: (value, props) => ({
|
|
86
|
+
type: "label",
|
|
87
|
+
props: { ...props, value }
|
|
88
|
+
}),
|
|
89
|
+
button: (props) => ({
|
|
90
|
+
type: "button",
|
|
91
|
+
props
|
|
92
|
+
})
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// src/runtime.ts
|
|
96
|
+
var Runtime = class {
|
|
97
|
+
constructor(config) {
|
|
98
|
+
this.config = config;
|
|
99
|
+
}
|
|
100
|
+
async *run(input) {
|
|
101
|
+
const runId = input.runId ?? generateId();
|
|
102
|
+
const context = {
|
|
103
|
+
state: input.state ?? {},
|
|
104
|
+
runId,
|
|
105
|
+
stepCount: 0,
|
|
106
|
+
isDone: false,
|
|
107
|
+
actions: this.config.actions,
|
|
108
|
+
ui,
|
|
109
|
+
suspend: () => {
|
|
110
|
+
context.isDone = true;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
let nextAction = void 0;
|
|
114
|
+
for (const plugin2 of this.config.plugins || []) {
|
|
115
|
+
if (plugin2.onBeforeRun) {
|
|
116
|
+
const result = await plugin2.onBeforeRun(
|
|
117
|
+
{ event: input.event, runId, state: context.state },
|
|
118
|
+
context
|
|
119
|
+
);
|
|
120
|
+
if (result) {
|
|
121
|
+
if ("type" in result) {
|
|
122
|
+
yield* this.emit(result, context);
|
|
123
|
+
} else {
|
|
124
|
+
nextAction = result;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (this.config.hooks?.onBeforeRun) {
|
|
130
|
+
const result = await this.config.hooks.onBeforeRun(
|
|
131
|
+
{ event: input.event, runId, state: context.state },
|
|
132
|
+
context
|
|
133
|
+
);
|
|
134
|
+
if (result) {
|
|
135
|
+
if ("type" in result) {
|
|
136
|
+
yield* this.emit(result, context);
|
|
137
|
+
} else {
|
|
138
|
+
nextAction = result;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (context.isDone) return;
|
|
143
|
+
yield* this.emit(
|
|
144
|
+
{ type: "run-started", data: { inputEvent: input.event } },
|
|
145
|
+
context
|
|
146
|
+
);
|
|
147
|
+
if (!nextAction && this.config.brain) {
|
|
148
|
+
nextAction = yield* this.dispatchToBrain(input.event, context);
|
|
149
|
+
}
|
|
150
|
+
while (nextAction && !context.isDone) {
|
|
151
|
+
if (context.stepCount++ >= (this.config.safetyMaxSteps ?? 10)) {
|
|
152
|
+
yield* this.emit(
|
|
153
|
+
{ type: "error", data: { message: "Max steps exceeded" } },
|
|
154
|
+
context
|
|
155
|
+
);
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
const current = nextAction;
|
|
159
|
+
nextAction = void 0;
|
|
160
|
+
const actionName = current.action ?? Object.keys(this.config.actions)[0];
|
|
161
|
+
const action2 = this.config.actions[actionName];
|
|
162
|
+
if (!action2) {
|
|
163
|
+
yield* this.emit(
|
|
164
|
+
{
|
|
165
|
+
type: "error",
|
|
166
|
+
data: { message: `Action ${actionName} not found` }
|
|
167
|
+
},
|
|
168
|
+
context
|
|
169
|
+
);
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
const result = yield* this.executeAction(action2, current, context);
|
|
173
|
+
if (this.config.brain) {
|
|
174
|
+
nextAction = yield* this.dispatchToBrain(
|
|
175
|
+
{
|
|
176
|
+
type: "action-result",
|
|
177
|
+
data: {
|
|
178
|
+
...current,
|
|
179
|
+
// Preserve all metadata (like toolCallId)
|
|
180
|
+
action: actionName,
|
|
181
|
+
params: current.params,
|
|
182
|
+
result
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
context
|
|
186
|
+
);
|
|
187
|
+
} else {
|
|
188
|
+
nextAction = result;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
for (const plugin2 of this.config.plugins || []) {
|
|
192
|
+
if (plugin2.onAfterRun) {
|
|
193
|
+
const extra = await plugin2.onAfterRun(context);
|
|
194
|
+
if (extra) yield* this.emit(extra, context);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (this.config.hooks?.onAfterRun) {
|
|
198
|
+
const extra = await this.config.hooks.onAfterRun(context);
|
|
199
|
+
if (extra) yield* this.emit(extra, context);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
async *dispatchToBrain(event, context) {
|
|
203
|
+
const generator = this.config.brain(event, context);
|
|
204
|
+
while (true) {
|
|
205
|
+
const { value, done } = await generator.next();
|
|
206
|
+
if (done) return value;
|
|
207
|
+
yield* this.emit(value, context);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
async *executeAction(action2, nextAction, context) {
|
|
211
|
+
const params = nextAction.params;
|
|
212
|
+
for (const plugin2 of this.config.plugins || []) {
|
|
213
|
+
if (plugin2.onBeforeAction) {
|
|
214
|
+
const hookResult = await plugin2.onBeforeAction(
|
|
215
|
+
{ action: action2, params, nextAction },
|
|
216
|
+
context
|
|
217
|
+
);
|
|
218
|
+
if (hookResult) {
|
|
219
|
+
yield* this.emit(hookResult, context);
|
|
220
|
+
if (context.isDone) return;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (this.config.hooks?.onBeforeAction) {
|
|
225
|
+
const hookResult = await this.config.hooks.onBeforeAction(
|
|
226
|
+
{ action: action2, params, nextAction },
|
|
227
|
+
context
|
|
228
|
+
);
|
|
229
|
+
if (hookResult) {
|
|
230
|
+
yield* this.emit(hookResult, context);
|
|
231
|
+
if (context.isDone) return;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
try {
|
|
235
|
+
const generator = action2.execute(params, context);
|
|
236
|
+
let result;
|
|
237
|
+
while (true) {
|
|
238
|
+
const { value, done } = await generator.next();
|
|
239
|
+
if (done) {
|
|
240
|
+
result = value;
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
yield* this.emit(value, context);
|
|
244
|
+
if (context.isDone) return;
|
|
245
|
+
}
|
|
246
|
+
for (const plugin2 of this.config.plugins || []) {
|
|
247
|
+
if (plugin2.onAfterAction) {
|
|
248
|
+
const extra = await plugin2.onAfterAction(
|
|
249
|
+
{ action: action2, data: result },
|
|
250
|
+
context
|
|
251
|
+
);
|
|
252
|
+
if (extra) yield* this.emit(extra, context);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (this.config.hooks?.onAfterAction) {
|
|
256
|
+
const extra = await this.config.hooks.onAfterAction(
|
|
257
|
+
{ action: action2, data: result },
|
|
258
|
+
context
|
|
259
|
+
);
|
|
260
|
+
if (extra) yield* this.emit(extra, context);
|
|
261
|
+
}
|
|
262
|
+
return result;
|
|
263
|
+
} catch (error) {
|
|
264
|
+
yield* this.emit(
|
|
265
|
+
{
|
|
266
|
+
type: "error",
|
|
267
|
+
data: {
|
|
268
|
+
action: action2.name,
|
|
269
|
+
error: error instanceof Error ? error.message : String(error)
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
context
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Internal helper to yield an event and trigger the onEvent hook.
|
|
278
|
+
*/
|
|
279
|
+
async *emit(event, context) {
|
|
280
|
+
const finalEvent = {
|
|
281
|
+
...event,
|
|
282
|
+
runId: context.runId,
|
|
283
|
+
timestamp: event.timestamp ?? Date.now(),
|
|
284
|
+
role: event.role ?? "assistant"
|
|
285
|
+
};
|
|
286
|
+
yield finalEvent;
|
|
287
|
+
for (const plugin2 of this.config.plugins || []) {
|
|
288
|
+
if (plugin2.onEvent) {
|
|
289
|
+
const extra = await plugin2.onEvent(finalEvent, context);
|
|
290
|
+
if (extra) {
|
|
291
|
+
yield { ...extra, runId: context.runId, timestamp: Date.now() };
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
if (this.config.hooks?.onEvent) {
|
|
296
|
+
const extra = await this.config.hooks.onEvent(finalEvent, context);
|
|
297
|
+
if (extra) {
|
|
298
|
+
yield { ...extra, runId: context.runId, timestamp: Date.now() };
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
var melony = (config) => {
|
|
304
|
+
const runtime = new Runtime(config);
|
|
305
|
+
return {
|
|
306
|
+
config,
|
|
307
|
+
run: runtime.run.bind(runtime)
|
|
308
|
+
};
|
|
309
|
+
};
|
|
310
|
+
var action = (config) => config;
|
|
311
|
+
var plugin = (config) => config;
|
|
312
|
+
|
|
313
|
+
export { Runtime, action, melony, plugin, ui };
|
|
314
|
+
//# sourceMappingURL=chunk-WCI7WEZW.js.map
|
|
315
|
+
//# sourceMappingURL=chunk-WCI7WEZW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/runtime.ts"],"names":["plugin","action"],"mappings":"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","file":"chunk-WCI7WEZW.js","sourcesContent":["import z from \"zod\";\n\n// ============================================\n// UI Protocol & Contracts\n// ============================================\n\nexport type UISize = \"sm\" | \"md\" | \"lg\";\nexport type UIAlign = \"start\" | \"center\" | \"end\" | \"stretch\";\nexport type UIJustify = \"start\" | \"center\" | \"end\" | \"between\" | \"around\";\nexport type UIWrap = \"nowrap\" | \"wrap\" | \"wrap-reverse\";\nexport type UIOrientation = \"horizontal\" | \"vertical\";\n\nexport type UIColor =\n | \"primary\"\n | \"secondary\"\n | \"success\"\n | \"danger\"\n | \"warning\"\n | \"info\"\n | \"background\"\n | \"foreground\"\n | \"muted\"\n | \"mutedForeground\"\n | \"border\";\n\nexport type UISpacing = \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\" | \"xxl\";\n\n/**\n * UI Component Contracts\n * This acts as the source of truth for the SDUI protocol.\n */\nexport interface UIContract {\n card: {\n title?: string;\n subtitle?: string;\n background?: string;\n isLoading?: boolean;\n };\n row: {\n align?: UIAlign;\n justify?: UIJustify;\n wrap?: UIWrap;\n gap?: UISpacing;\n };\n col: {\n align?: UIAlign;\n justify?: UIJustify;\n gap?: UISpacing;\n width?: string | number;\n height?: string | number;\n padding?: UISpacing;\n };\n box: {\n padding?: UISpacing;\n margin?: string | number;\n background?: string;\n border?: boolean;\n borderRadius?: UISpacing;\n width?: string | number;\n height?: string | number;\n };\n spacer: {\n size?: UISpacing;\n direction?: UIOrientation;\n };\n divider: {\n orientation?: UIOrientation;\n color?: UIColor;\n };\n text: {\n value: string;\n size?: UISpacing;\n weight?: \"normal\" | \"medium\" | \"semibold\" | \"bold\";\n color?: UIColor;\n align?: UIAlign;\n };\n heading: {\n value: string;\n level?: 1 | 2 | 3 | 4 | 5 | 6;\n };\n badge: {\n label: string;\n variant?: \"primary\" | \"secondary\" | \"success\" | \"danger\" | \"warning\";\n size?: UISize;\n };\n image: {\n src: string;\n alt?: string;\n size?: UISize;\n };\n icon: {\n name: string;\n size?: UISize;\n color?: UIColor;\n };\n chart: {\n data: Array<{ label: string; value: number; color?: string }>;\n chartType?: \"bar\" | \"line\" | \"area\" | \"pie\";\n title?: string;\n };\n list: {};\n listItem: {\n onClickAction?: Event;\n gap?: UISpacing;\n };\n form: {\n onSubmitAction?: Event;\n };\n input: {\n name: string;\n label?: string;\n placeholder?: string;\n defaultValue?: string;\n inputType?: string;\n onChangeAction?: Event;\n };\n textarea: {\n name: string;\n label?: string;\n placeholder?: string;\n defaultValue?: string;\n rows?: number;\n onChangeAction?: Event;\n };\n select: {\n name: string;\n label?: string;\n options: Array<{ label: string; value: string }>;\n defaultValue?: string;\n placeholder?: string;\n onChangeAction?: Event;\n };\n checkbox: {\n name: string;\n label?: string;\n checked?: boolean;\n onChangeAction?: Event;\n };\n radioGroup: {\n name: string;\n options: Array<{ label: string; value: string; disabled?: boolean }>;\n label?: string;\n defaultValue?: string;\n orientation?: UIOrientation;\n onChangeAction?: Event;\n };\n label: {\n value: string;\n htmlFor?: string;\n required?: boolean;\n };\n button: {\n label: string;\n variant?: \"primary\" | \"secondary\" | \"success\" | \"danger\" | \"outline\" | \"ghost\" | \"link\";\n size?: UISize;\n disabled?: boolean;\n onClickAction?: Event;\n };\n}\n\nexport type UINode<T extends keyof UIContract = keyof UIContract> = {\n type: T;\n props?: UIContract[T];\n children?: UINode<any>[];\n};\n\n/**\n * UI Builder for SDUI.\n * Typed using the UIContract source of truth.\n */\nexport const ui = {\n card: (props: UIContract[\"card\"] & { children?: UINode<any>[] }): UINode<\"card\"> => {\n const { children, ...rest } = props;\n return { type: \"card\", props: rest, children };\n },\n row: (props: UIContract[\"row\"] & { children?: UINode<any>[] }): UINode<\"row\"> => {\n const { children, ...rest } = props;\n return { type: \"row\", props: rest, children };\n },\n col: (props: UIContract[\"col\"] & { children?: UINode<any>[] }): UINode<\"col\"> => {\n const { children, ...rest } = props;\n return { type: \"col\", props: rest, children };\n },\n box: (props: UIContract[\"box\"] & { children?: UINode<any>[] }): UINode<\"box\"> => {\n const { children, ...rest } = props;\n return { type: \"box\", props: rest, children };\n },\n spacer: (props: UIContract[\"spacer\"]): UINode<\"spacer\"> => ({\n type: \"spacer\",\n props,\n }),\n divider: (props: UIContract[\"divider\"]): UINode<\"divider\"> => ({\n type: \"divider\",\n props,\n }),\n text: (\n value: string,\n props?: Omit<UIContract[\"text\"], \"value\">\n ): UINode<\"text\"> => ({\n type: \"text\",\n props: { ...props, value },\n }),\n heading: (\n value: string,\n level: UIContract[\"heading\"][\"level\"] = 1\n ): UINode<\"heading\"> => ({\n type: \"heading\",\n props: { value, level },\n }),\n badge: (\n label: string,\n variant: UIContract[\"badge\"][\"variant\"] = \"primary\",\n size: UISize = \"md\"\n ): UINode<\"badge\"> => ({\n type: \"badge\",\n props: { label, variant, size },\n }),\n image: (\n src: string,\n alt?: string,\n size: UISize = \"md\"\n ): UINode<\"image\"> => ({\n type: \"image\",\n props: { src, alt, size },\n }),\n icon: (\n name: string,\n size: UISize = \"md\",\n color?: UIColor\n ): UINode<\"icon\"> => ({\n type: \"icon\",\n props: { name, size, color },\n }),\n chart: (props: UIContract[\"chart\"]): UINode<\"chart\"> => ({\n type: \"chart\",\n props,\n }),\n list: (children: UINode<any>[]): UINode<\"list\"> => ({\n type: \"list\",\n children,\n }),\n listItem: (\n props: UIContract[\"listItem\"] & { children: UINode<any>[] }\n ): UINode<\"listItem\"> => {\n const { children, ...rest } = props;\n return { type: \"listItem\", props: rest, children };\n },\n form: (props: UIContract[\"form\"] & { children?: UINode<any>[] }): UINode<\"form\"> => {\n const { children, ...rest } = props;\n return { type: \"form\", props: rest, children };\n },\n input: (props: UIContract[\"input\"]): UINode<\"input\"> => ({\n type: \"input\",\n props,\n }),\n textarea: (props: UIContract[\"textarea\"]): UINode<\"textarea\"> => ({\n type: \"textarea\",\n props,\n }),\n select: (props: UIContract[\"select\"]): UINode<\"select\"> => ({\n type: \"select\",\n props,\n }),\n checkbox: (props: UIContract[\"checkbox\"]): UINode<\"checkbox\"> => ({\n type: \"checkbox\",\n props,\n }),\n radioGroup: (props: UIContract[\"radioGroup\"]): UINode<\"radioGroup\"> => ({\n type: \"radioGroup\",\n props,\n }),\n label: (\n value: string,\n props?: Omit<UIContract[\"label\"], \"value\">\n ): UINode<\"label\"> => ({\n type: \"label\",\n props: { ...props, value },\n }),\n button: (props: UIContract[\"button\"]): UINode<\"button\"> => ({\n type: \"button\",\n props,\n }),\n};\n\n// ============================================\n// Events\n// ============================================\n\nexport type Role = \"user\" | \"assistant\" | \"system\";\n\nexport type Event = {\n type: string;\n data?: any;\n ui?: UINode;\n runId?: string;\n timestamp?: number;\n role?: Role;\n};\n\n// ============================================\n// Runtime & Hooks\n// ============================================\n\nexport interface Action<TParams extends z.ZodSchema = z.ZodObject<any>> {\n name: string;\n description?: string;\n paramsSchema: TParams;\n execute: (\n params: z.infer<TParams>,\n context: RuntimeContext\n ) => AsyncGenerator<Event, NextAction | void, unknown>;\n}\n\nexport interface NextAction {\n action?: string;\n params?: any;\n description?: string;\n [key: string]: any; // Allow metadata like toolCallId\n}\n\nexport interface RuntimeContext<TState = any> {\n state: TState;\n runId: string;\n stepCount: number;\n isDone: boolean;\n actions: Record<string, Action<any>>;\n ui: typeof ui;\n suspend: () => void;\n}\n\n/**\n * Standardized Hook Result for consistent DX.\n */\nexport type HookResult = Promise<Event | void>;\n\nexport interface Hooks {\n /**\n * Called when a run session begins.\n * Can return an Event to be emitted, or a NextAction to jump-start the loop.\n */\n onBeforeRun?: (\n input: { event: Event; runId: string; state: Record<string, any> },\n context: RuntimeContext\n ) => Promise<Event | NextAction | void>;\n\n /**\n * Called when a run session completes.\n */\n onAfterRun?: (context: RuntimeContext) => HookResult;\n\n /**\n * Called whenever an event is yielded by the runtime.\n */\n onEvent?: (event: Event, context: RuntimeContext) => HookResult;\n\n /**\n * Called before an action is executed.\n * Return an event to intercept/suspend the action.\n */\n onBeforeAction?: (\n call: { action: Action<any>; params: any; nextAction: NextAction },\n context: RuntimeContext\n ) => HookResult;\n\n /**\n * Called after an action completes.\n */\n onAfterAction?: (\n result: { action: Action<any>; data: NextAction | void },\n context: RuntimeContext\n ) => HookResult;\n}\n\n/**\n * A plugin is just a named set of hooks.\n */\nexport interface Plugin extends Hooks {\n name: string;\n}\n\nexport interface Config {\n actions: Record<string, Action<any>>;\n /**\n * The central brain for handling incoming events.\n */\n brain?: (\n event: Event,\n context: RuntimeContext\n ) => AsyncGenerator<Event, NextAction | void, unknown>;\n hooks?: Hooks;\n plugins?: Plugin[];\n safetyMaxSteps?: number;\n}\n","import {\n Action,\n Event,\n NextAction,\n RuntimeContext,\n Config,\n Plugin,\n ui,\n} from \"./types\";\nimport { generateId } from \"./utils/generate-id\";\nimport { z } from \"zod\";\n\n/**\n * The Slim Runtime.\n * Single Responsibility: Orchestrate Event -> Action -> Event transitions.\n */\nexport class Runtime {\n private config: Config;\n\n constructor(config: Config) {\n this.config = config;\n }\n\n public async *run(input: {\n event: Event;\n runId?: string;\n state?: Record<string, any>;\n }): AsyncGenerator<Event> {\n const runId = input.runId ?? generateId();\n\n const context: RuntimeContext = {\n state: input.state ?? {},\n runId,\n stepCount: 0,\n isDone: false,\n actions: this.config.actions,\n ui,\n suspend: () => {\n context.isDone = true;\n },\n };\n\n let nextAction: NextAction | void = undefined;\n\n // 1. Trigger Plugins: onBeforeRun\n for (const plugin of this.config.plugins || []) {\n if (plugin.onBeforeRun) {\n const result = await plugin.onBeforeRun(\n { event: input.event, runId, state: context.state },\n context\n );\n if (result) {\n if (\"type\" in result) {\n yield* this.emit(result as Event, context);\n } else {\n nextAction = result as NextAction;\n }\n }\n }\n }\n\n // 2. Trigger Hook: onBeforeRun\n if (this.config.hooks?.onBeforeRun) {\n const result = await this.config.hooks.onBeforeRun(\n { event: input.event, runId, state: context.state },\n context\n );\n if (result) {\n if (\"type\" in result) {\n yield* this.emit(result as Event, context);\n } else {\n nextAction = result as NextAction;\n }\n }\n }\n\n if (context.isDone) return;\n\n yield* this.emit(\n { type: \"run-started\", data: { inputEvent: input.event } },\n context\n );\n\n // Initial dispatch of the incoming event to the agent's brain\n // Only if onBeforeRun didn't already provide a nextAction\n if (!nextAction && this.config.brain) {\n nextAction = yield* this.dispatchToBrain(input.event, context);\n }\n\n // Agentic loop\n while (nextAction && !context.isDone) {\n if (context.stepCount++ >= (this.config.safetyMaxSteps ?? 10)) {\n yield* this.emit(\n { type: \"error\", data: { message: \"Max steps exceeded\" } },\n context\n );\n break;\n }\n\n const current: NextAction = nextAction;\n nextAction = undefined; // Reset\n\n // 1. Resolve Action\n const actionName: string =\n current.action ?? Object.keys(this.config.actions)[0];\n const action: Action<any> = this.config.actions[actionName];\n\n if (!action) {\n yield* this.emit(\n {\n type: \"error\",\n data: { message: `Action ${actionName} not found` },\n },\n context\n );\n break;\n }\n\n // 2. Execute Action\n const result = yield* this.executeAction(action, current, context);\n\n // 3. Decide Next Step\n if (this.config.brain) {\n // If we have a brain, feed the result back to it to decide what to do next.\n // This keeps the brain in the loop for multi-step reasoning.\n nextAction = yield* this.dispatchToBrain(\n {\n type: \"action-result\",\n data: {\n ...current, // Preserve all metadata (like toolCallId)\n action: actionName,\n params: current.params,\n result,\n },\n },\n context\n );\n } else {\n // Simple mode: follow the action's own suggestion for the next step.\n nextAction = result;\n }\n }\n\n // 1. Trigger Plugins: onAfterRun\n for (const plugin of this.config.plugins || []) {\n if (plugin.onAfterRun) {\n const extra = await plugin.onAfterRun(context);\n if (extra) yield* this.emit(extra, context);\n }\n }\n\n // 2. Trigger Hook: onAfterRun\n if (this.config.hooks?.onAfterRun) {\n const extra = await this.config.hooks.onAfterRun(context);\n if (extra) yield* this.emit(extra, context);\n }\n }\n\n private async *dispatchToBrain(\n event: Event,\n context: RuntimeContext\n ): AsyncGenerator<Event, NextAction | void> {\n const generator = this.config.brain!(event, context);\n while (true) {\n const { value, done } = await generator.next();\n if (done) return value as NextAction | void;\n yield* this.emit(value as Event, context);\n }\n }\n\n private async *executeAction(\n action: Action,\n nextAction: NextAction,\n context: RuntimeContext\n ): AsyncGenerator<Event, NextAction | void> {\n const params = nextAction.params;\n\n // 1. Trigger Plugins: onBeforeAction\n for (const plugin of this.config.plugins || []) {\n if (plugin.onBeforeAction) {\n const hookResult = await plugin.onBeforeAction(\n { action, params, nextAction },\n context\n );\n if (hookResult) {\n yield* this.emit(hookResult, context);\n if (context.isDone) return;\n }\n }\n }\n\n // 2. Trigger Hook: onBeforeAction\n if (this.config.hooks?.onBeforeAction) {\n const hookResult = await this.config.hooks.onBeforeAction(\n { action, params, nextAction },\n context\n );\n if (hookResult) {\n yield* this.emit(hookResult, context);\n if (context.isDone) return;\n }\n }\n\n try {\n const generator = action.execute(params, context);\n let result: NextAction | void;\n\n while (true) {\n const { value, done } = await generator.next();\n if (done) {\n result = value as NextAction | void;\n break;\n }\n yield* this.emit(value as Event, context);\n if (context.isDone) return;\n }\n\n // 3. Trigger Plugins: onAfterAction\n for (const plugin of this.config.plugins || []) {\n if (plugin.onAfterAction) {\n const extra = await plugin.onAfterAction(\n { action, data: result },\n context\n );\n if (extra) yield* this.emit(extra, context);\n }\n }\n\n // 4. Trigger Hook: onAfterAction\n if (this.config.hooks?.onAfterAction) {\n const extra = await this.config.hooks.onAfterAction(\n { action, data: result },\n context\n );\n if (extra) yield* this.emit(extra, context);\n }\n\n return result;\n } catch (error) {\n yield* this.emit(\n {\n type: \"error\",\n data: {\n action: action.name,\n error: error instanceof Error ? error.message : String(error),\n },\n },\n context\n );\n }\n }\n\n /**\n * Internal helper to yield an event and trigger the onEvent hook.\n */\n private async *emit(\n event: Event,\n context: RuntimeContext\n ): AsyncGenerator<Event> {\n const finalEvent = {\n ...event,\n runId: context.runId,\n timestamp: event.timestamp ?? Date.now(),\n role: event.role ?? \"assistant\",\n };\n\n // Yield the actual event first\n yield finalEvent;\n\n // 1. Trigger Plugins: onEvent\n for (const plugin of this.config.plugins || []) {\n if (plugin.onEvent) {\n const extra = await plugin.onEvent(finalEvent, context);\n if (extra) {\n yield { ...extra, runId: context.runId, timestamp: Date.now() };\n }\n }\n }\n\n // 2. Trigger Hook: onEvent for side-effects or extra events\n if (this.config.hooks?.onEvent) {\n const extra = await this.config.hooks.onEvent(finalEvent, context);\n if (extra) {\n // Yield extra event from hook, ensuring it has required metadata\n yield { ...extra, runId: context.runId, timestamp: Date.now() };\n }\n }\n }\n}\n\nexport const melony = (config: Config) => {\n const runtime = new Runtime(config);\n return {\n config,\n run: runtime.run.bind(runtime),\n };\n};\n\n/**\n * Helper to define an action with full type inference.\n */\nexport const action = <T extends z.ZodSchema>(\n config: Action<T>\n): Action<T> => config;\n\n/**\n * Helper to define a plugin.\n */\nexport const plugin = (config: Plugin): Plugin => config;\n"]}
|
package/dist/client.d.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import { E as Event } from './
|
|
2
|
-
export {
|
|
1
|
+
import { E as Event } from './types-BC3dKPi6.js';
|
|
2
|
+
export { g as generateId } from './generate-id-DU8kwYc2.js';
|
|
3
3
|
import 'zod';
|
|
4
4
|
|
|
5
5
|
interface ClientState {
|
|
6
6
|
events: Event[];
|
|
7
7
|
isLoading: boolean;
|
|
8
8
|
error: Error | null;
|
|
9
|
+
loadingStatus?: {
|
|
10
|
+
message: string;
|
|
11
|
+
details?: string;
|
|
12
|
+
};
|
|
9
13
|
}
|
|
10
14
|
declare class MelonyClient {
|
|
11
15
|
private transport;
|
|
@@ -20,6 +24,10 @@ declare class MelonyClient {
|
|
|
20
24
|
events: Event[];
|
|
21
25
|
isLoading: boolean;
|
|
22
26
|
error: Error | null;
|
|
27
|
+
loadingStatus?: {
|
|
28
|
+
message: string;
|
|
29
|
+
details?: string;
|
|
30
|
+
};
|
|
23
31
|
};
|
|
24
32
|
private setState;
|
|
25
33
|
sendEvent(event: Event, options?: {
|
package/dist/client.js
CHANGED
|
@@ -10,7 +10,8 @@ var MelonyClient = class {
|
|
|
10
10
|
this.state = {
|
|
11
11
|
events: options?.initialEvents ?? [],
|
|
12
12
|
isLoading: false,
|
|
13
|
-
error: null
|
|
13
|
+
error: null,
|
|
14
|
+
loadingStatus: void 0
|
|
14
15
|
};
|
|
15
16
|
}
|
|
16
17
|
subscribe(listener) {
|
|
@@ -39,6 +40,7 @@ var MelonyClient = class {
|
|
|
39
40
|
this.setState({
|
|
40
41
|
isLoading: true,
|
|
41
42
|
error: null,
|
|
43
|
+
loadingStatus: void 0,
|
|
42
44
|
events: [...this.state.events, optimisticEvent]
|
|
43
45
|
});
|
|
44
46
|
try {
|
|
@@ -66,19 +68,36 @@ var MelonyClient = class {
|
|
|
66
68
|
}
|
|
67
69
|
}
|
|
68
70
|
}
|
|
69
|
-
this.setState({ isLoading: false });
|
|
71
|
+
this.setState({ isLoading: false, loadingStatus: void 0 });
|
|
70
72
|
} catch (err) {
|
|
71
73
|
if (err instanceof Error && err.name === "AbortError") {
|
|
72
|
-
this.setState({ isLoading: false });
|
|
74
|
+
this.setState({ isLoading: false, loadingStatus: void 0 });
|
|
73
75
|
return;
|
|
74
76
|
}
|
|
75
77
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
76
|
-
this.setState({ error, isLoading: false });
|
|
78
|
+
this.setState({ error, isLoading: false, loadingStatus: void 0 });
|
|
77
79
|
throw error;
|
|
78
80
|
}
|
|
79
81
|
}
|
|
80
82
|
handleIncomingEvent(event) {
|
|
81
83
|
const events = [...this.state.events];
|
|
84
|
+
if (event.type === "loading-status") {
|
|
85
|
+
const currentStatus = this.state.loadingStatus;
|
|
86
|
+
const newMessage = event.data?.message ?? currentStatus?.message ?? "Processing...";
|
|
87
|
+
const newDelta = event.data?.delta;
|
|
88
|
+
let newDetails = currentStatus?.details ?? "";
|
|
89
|
+
if (newDelta !== void 0) {
|
|
90
|
+
newDetails += newDelta;
|
|
91
|
+
} else if (event.data?.details !== void 0) {
|
|
92
|
+
newDetails = event.data.details;
|
|
93
|
+
}
|
|
94
|
+
this.setState({
|
|
95
|
+
loadingStatus: {
|
|
96
|
+
message: newMessage,
|
|
97
|
+
details: newDetails || void 0
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
82
101
|
const lastEvent = events[events.length - 1];
|
|
83
102
|
if (event.type === "text-delta" && lastEvent?.type === "text-delta" && event.runId === lastEvent.runId && event.data?.delta) {
|
|
84
103
|
events[events.length - 1] = {
|
|
@@ -95,7 +114,7 @@ var MelonyClient = class {
|
|
|
95
114
|
}
|
|
96
115
|
reset(events = []) {
|
|
97
116
|
if (this.abortController) this.abortController.abort();
|
|
98
|
-
this.setState({ events, error: null, isLoading: false });
|
|
117
|
+
this.setState({ events, error: null, isLoading: false, loadingStatus: void 0 });
|
|
99
118
|
}
|
|
100
119
|
};
|
|
101
120
|
function createHttpTransport(api) {
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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 {\n events: Event[];\n isLoading: boolean;\n error: Error | null;\n}\n\nexport class MelonyClient {\n private transport: TransportFn;\n private state: ClientState;\n private abortController: AbortController | null = null;\n private stateListeners: Set<(state: ClientState) => void> = new Set();\n\n constructor(transport: TransportFn, options?: { initialEvents?: Event[] }) {\n this.transport = transport;\n this.state = {\n events: options?.initialEvents ?? [],\n isLoading: false,\n error: null,\n };\n }\n\n subscribe(listener: (state: ClientState) => 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 setState(updates: Partial<ClientState>) {\n this.state = { ...this.state, ...updates };\n this.stateListeners.forEach((l) => l(this.getState()));\n }\n\n async *sendEvent(\n event: Event,\n options?: { runId?: string; state?: Record<string, any> }\n ): AsyncGenerator<Event> {\n if (this.abortController) this.abortController.abort();\n this.abortController = new AbortController();\n\n const runId = options?.runId ?? generateId();\n const optimisticEvent: Event = {\n ...event,\n runId,\n role: event.role ?? \"user\",\n timestamp: event.timestamp ?? Date.now(),\n };\n\n this.setState({\n isLoading: true,\n error: null,\n events: [...this.state.events, optimisticEvent],\n });\n\n try {\n const stream = await this.transport(\n { event: optimisticEvent, ...options, runId },\n this.abortController.signal\n );\n\n const reader = stream.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: Event = 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: Event) {\n const events = [...this.state.events];\n\n // Contiguous text-delta merging for the same run\n const lastEvent = events[events.length - 1];\n if (\n event.type === \"text-delta\" &&\n lastEvent?.type === \"text-delta\" &&\n event.runId === lastEvent.runId &&\n event.data?.delta\n ) {\n events[events.length - 1] = {\n ...lastEvent,\n data: {\n ...lastEvent.data,\n delta: (lastEvent.data?.delta || \"\") + event.data.delta,\n },\n };\n } else {\n events.push(event);\n }\n\n this.setState({ events });\n }\n\n reset(events: Event[] = []) {\n if (this.abortController) this.abortController.abort();\n this.setState({ events, error: null, isLoading: false });\n }\n}\n\nexport interface TransportRequest {\n event: Event;\n runId?: string;\n state?: Record<string, any>;\n}\n\nexport type TransportFn = (\n request: TransportRequest,\n signal?: AbortSignal\n) => Promise<ReadableStream<Uint8Array>>;\n\nexport function createHttpTransport(api: string): TransportFn {\n return async (request: TransportRequest, signal?: AbortSignal) => {\n const response = await fetch(api, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(request),\n signal,\n });\n\n if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);\n if (!response.body) throw new Error(\"No response body\");\n\n return response.body;\n };\n}\n"]}
|
|
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 {\n events: Event[];\n isLoading: boolean;\n error: Error | null;\n loadingStatus?: {\n message: string;\n details?: string;\n };\n}\n\nexport class MelonyClient {\n private transport: TransportFn;\n private state: ClientState;\n private abortController: AbortController | null = null;\n private stateListeners: Set<(state: ClientState) => void> = new Set();\n\n constructor(transport: TransportFn, options?: { initialEvents?: Event[] }) {\n this.transport = transport;\n this.state = {\n events: options?.initialEvents ?? [],\n isLoading: false,\n error: null,\n loadingStatus: undefined,\n };\n }\n\n subscribe(listener: (state: ClientState) => 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 setState(updates: Partial<ClientState>) {\n this.state = { ...this.state, ...updates };\n this.stateListeners.forEach((l) => l(this.getState()));\n }\n\n async *sendEvent(\n event: Event,\n options?: { runId?: string; state?: Record<string, any> }\n ): AsyncGenerator<Event> {\n if (this.abortController) this.abortController.abort();\n this.abortController = new AbortController();\n\n const runId = options?.runId ?? generateId();\n const optimisticEvent: Event = {\n ...event,\n runId,\n role: event.role ?? \"user\",\n timestamp: event.timestamp ?? Date.now(),\n };\n\n this.setState({\n isLoading: true,\n error: null,\n loadingStatus: undefined,\n events: [...this.state.events, optimisticEvent],\n });\n\n try {\n const stream = await this.transport(\n { event: optimisticEvent, ...options, runId },\n this.abortController.signal\n );\n\n const reader = stream.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: Event = 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, loadingStatus: undefined });\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") {\n this.setState({ isLoading: false, loadingStatus: undefined });\n return;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n this.setState({ error, isLoading: false, loadingStatus: undefined });\n throw error;\n }\n }\n\n private handleIncomingEvent(event: Event) {\n const events = [...this.state.events];\n\n // Track loading-status events\n if (event.type === \"loading-status\") {\n const currentStatus = this.state.loadingStatus;\n const newMessage = event.data?.message ?? currentStatus?.message ?? \"Processing...\";\n const newDelta = event.data?.delta;\n\n let newDetails = currentStatus?.details ?? \"\";\n if (newDelta !== undefined) {\n newDetails += newDelta;\n } else if (event.data?.details !== undefined) {\n newDetails = event.data.details;\n }\n\n this.setState({\n loadingStatus: {\n message: newMessage,\n details: newDetails || undefined,\n },\n });\n }\n\n // Contiguous text-delta merging for the same run\n const lastEvent = events[events.length - 1];\n if (\n event.type === \"text-delta\" &&\n lastEvent?.type === \"text-delta\" &&\n event.runId === lastEvent.runId &&\n event.data?.delta\n ) {\n events[events.length - 1] = {\n ...lastEvent,\n data: {\n ...lastEvent.data,\n delta: (lastEvent.data?.delta || \"\") + event.data.delta,\n },\n };\n } else {\n events.push(event);\n }\n\n this.setState({ events });\n }\n\n reset(events: Event[] = []) {\n if (this.abortController) this.abortController.abort();\n this.setState({ events, error: null, isLoading: false, loadingStatus: undefined });\n }\n}\n\nexport interface TransportRequest {\n event: Event;\n runId?: string;\n state?: Record<string, any>;\n}\n\nexport type TransportFn = (\n request: TransportRequest,\n signal?: AbortSignal\n) => Promise<ReadableStream<Uint8Array>>;\n\nexport function createHttpTransport(api: string): TransportFn {\n return async (request: TransportRequest, signal?: AbortSignal) => {\n const response = await fetch(api, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(request),\n signal,\n });\n\n if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);\n if (!response.body) throw new Error(\"No response body\");\n\n return response.body;\n };\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { C as Config, E as Event, A as Action, P as Plugin } from './
|
|
2
|
-
export { H as HookResult, j as Hooks, N as NextAction, R as Role, i as RuntimeContext, a as UIAlign, e as UIColor, g as UIContract, b as UIJustify, h as UINode, d as UIOrientation, U as UISize, f as UISpacing, c as UIWrap,
|
|
1
|
+
import { C as Config, E as Event, A as Action, P as Plugin } from './types-BC3dKPi6.js';
|
|
2
|
+
export { H as HookResult, j as Hooks, N as NextAction, R as Role, i as RuntimeContext, a as UIAlign, e as UIColor, g as UIContract, b as UIJustify, h as UINode, d as UIOrientation, U as UISize, f as UISpacing, c as UIWrap, u as ui } from './types-BC3dKPi6.js';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
+
export { g as generateId } from './generate-id-DU8kwYc2.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* The Slim Runtime.
|
package/dist/index.js
CHANGED
|
@@ -1,314 +1,5 @@
|
|
|
1
|
-
import { generateId } from './chunk-WAI5H335.js';
|
|
2
|
-
export { generateId } from './chunk-WAI5H335.js';
|
|
3
1
|
export { createStreamResponse } from './chunk-CFG7FFEZ.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
var ui = {
|
|
7
|
-
card: (props) => {
|
|
8
|
-
const { children, ...rest } = props;
|
|
9
|
-
return { type: "card", props: rest, children };
|
|
10
|
-
},
|
|
11
|
-
row: (props) => {
|
|
12
|
-
const { children, ...rest } = props;
|
|
13
|
-
return { type: "row", props: rest, children };
|
|
14
|
-
},
|
|
15
|
-
col: (props) => {
|
|
16
|
-
const { children, ...rest } = props;
|
|
17
|
-
return { type: "col", props: rest, children };
|
|
18
|
-
},
|
|
19
|
-
box: (props) => {
|
|
20
|
-
const { children, ...rest } = props;
|
|
21
|
-
return { type: "box", props: rest, children };
|
|
22
|
-
},
|
|
23
|
-
spacer: (props) => ({
|
|
24
|
-
type: "spacer",
|
|
25
|
-
props
|
|
26
|
-
}),
|
|
27
|
-
divider: (props) => ({
|
|
28
|
-
type: "divider",
|
|
29
|
-
props
|
|
30
|
-
}),
|
|
31
|
-
text: (value, props) => ({
|
|
32
|
-
type: "text",
|
|
33
|
-
props: { ...props, value }
|
|
34
|
-
}),
|
|
35
|
-
heading: (value, level = 1) => ({
|
|
36
|
-
type: "heading",
|
|
37
|
-
props: { value, level }
|
|
38
|
-
}),
|
|
39
|
-
badge: (label, variant = "primary", size = "md") => ({
|
|
40
|
-
type: "badge",
|
|
41
|
-
props: { label, variant, size }
|
|
42
|
-
}),
|
|
43
|
-
image: (src, alt, size = "md") => ({
|
|
44
|
-
type: "image",
|
|
45
|
-
props: { src, alt, size }
|
|
46
|
-
}),
|
|
47
|
-
icon: (name, size = "md", color) => ({
|
|
48
|
-
type: "icon",
|
|
49
|
-
props: { name, size, color }
|
|
50
|
-
}),
|
|
51
|
-
chart: (props) => ({
|
|
52
|
-
type: "chart",
|
|
53
|
-
props
|
|
54
|
-
}),
|
|
55
|
-
list: (children) => ({
|
|
56
|
-
type: "list",
|
|
57
|
-
children
|
|
58
|
-
}),
|
|
59
|
-
listItem: (props) => {
|
|
60
|
-
const { children, ...rest } = props;
|
|
61
|
-
return { type: "listItem", props: rest, children };
|
|
62
|
-
},
|
|
63
|
-
form: (props) => {
|
|
64
|
-
const { children, ...rest } = props;
|
|
65
|
-
return { type: "form", props: rest, children };
|
|
66
|
-
},
|
|
67
|
-
input: (props) => ({
|
|
68
|
-
type: "input",
|
|
69
|
-
props
|
|
70
|
-
}),
|
|
71
|
-
textarea: (props) => ({
|
|
72
|
-
type: "textarea",
|
|
73
|
-
props
|
|
74
|
-
}),
|
|
75
|
-
select: (props) => ({
|
|
76
|
-
type: "select",
|
|
77
|
-
props
|
|
78
|
-
}),
|
|
79
|
-
checkbox: (props) => ({
|
|
80
|
-
type: "checkbox",
|
|
81
|
-
props
|
|
82
|
-
}),
|
|
83
|
-
radioGroup: (props) => ({
|
|
84
|
-
type: "radioGroup",
|
|
85
|
-
props
|
|
86
|
-
}),
|
|
87
|
-
label: (value, props) => ({
|
|
88
|
-
type: "label",
|
|
89
|
-
props: { ...props, value }
|
|
90
|
-
}),
|
|
91
|
-
button: (props) => ({
|
|
92
|
-
type: "button",
|
|
93
|
-
props
|
|
94
|
-
})
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
// src/runtime.ts
|
|
98
|
-
var Runtime = class {
|
|
99
|
-
constructor(config) {
|
|
100
|
-
this.config = config;
|
|
101
|
-
}
|
|
102
|
-
async *run(input) {
|
|
103
|
-
const runId = input.runId ?? generateId();
|
|
104
|
-
const context = {
|
|
105
|
-
state: input.state ?? {},
|
|
106
|
-
runId,
|
|
107
|
-
stepCount: 0,
|
|
108
|
-
isDone: false,
|
|
109
|
-
actions: this.config.actions,
|
|
110
|
-
ui,
|
|
111
|
-
suspend: () => {
|
|
112
|
-
context.isDone = true;
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
let nextAction = void 0;
|
|
116
|
-
for (const plugin2 of this.config.plugins || []) {
|
|
117
|
-
if (plugin2.onBeforeRun) {
|
|
118
|
-
const result = await plugin2.onBeforeRun(
|
|
119
|
-
{ event: input.event, runId, state: context.state },
|
|
120
|
-
context
|
|
121
|
-
);
|
|
122
|
-
if (result) {
|
|
123
|
-
if ("type" in result) {
|
|
124
|
-
yield* this.emit(result, context);
|
|
125
|
-
} else {
|
|
126
|
-
nextAction = result;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
if (this.config.hooks?.onBeforeRun) {
|
|
132
|
-
const result = await this.config.hooks.onBeforeRun(
|
|
133
|
-
{ event: input.event, runId, state: context.state },
|
|
134
|
-
context
|
|
135
|
-
);
|
|
136
|
-
if (result) {
|
|
137
|
-
if ("type" in result) {
|
|
138
|
-
yield* this.emit(result, context);
|
|
139
|
-
} else {
|
|
140
|
-
nextAction = result;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
if (context.isDone) return;
|
|
145
|
-
yield* this.emit(
|
|
146
|
-
{ type: "run-started", data: { inputEvent: input.event } },
|
|
147
|
-
context
|
|
148
|
-
);
|
|
149
|
-
if (!nextAction && this.config.brain) {
|
|
150
|
-
nextAction = yield* this.dispatchToBrain(input.event, context);
|
|
151
|
-
}
|
|
152
|
-
while (nextAction && !context.isDone) {
|
|
153
|
-
if (context.stepCount++ >= (this.config.safetyMaxSteps ?? 10)) {
|
|
154
|
-
yield* this.emit(
|
|
155
|
-
{ type: "error", data: { message: "Max steps exceeded" } },
|
|
156
|
-
context
|
|
157
|
-
);
|
|
158
|
-
break;
|
|
159
|
-
}
|
|
160
|
-
const current = nextAction;
|
|
161
|
-
nextAction = void 0;
|
|
162
|
-
const actionName = current.action ?? Object.keys(this.config.actions)[0];
|
|
163
|
-
const action2 = this.config.actions[actionName];
|
|
164
|
-
if (!action2) {
|
|
165
|
-
yield* this.emit(
|
|
166
|
-
{
|
|
167
|
-
type: "error",
|
|
168
|
-
data: { message: `Action ${actionName} not found` }
|
|
169
|
-
},
|
|
170
|
-
context
|
|
171
|
-
);
|
|
172
|
-
break;
|
|
173
|
-
}
|
|
174
|
-
const result = yield* this.executeAction(action2, current.params, context);
|
|
175
|
-
if (this.config.brain) {
|
|
176
|
-
nextAction = yield* this.dispatchToBrain(
|
|
177
|
-
{
|
|
178
|
-
type: "action-result",
|
|
179
|
-
data: {
|
|
180
|
-
action: actionName,
|
|
181
|
-
params: current.params,
|
|
182
|
-
result
|
|
183
|
-
}
|
|
184
|
-
},
|
|
185
|
-
context
|
|
186
|
-
);
|
|
187
|
-
} else {
|
|
188
|
-
nextAction = result;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
for (const plugin2 of this.config.plugins || []) {
|
|
192
|
-
if (plugin2.onAfterRun) {
|
|
193
|
-
const extra = await plugin2.onAfterRun(context);
|
|
194
|
-
if (extra) yield* this.emit(extra, context);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
if (this.config.hooks?.onAfterRun) {
|
|
198
|
-
const extra = await this.config.hooks.onAfterRun(context);
|
|
199
|
-
if (extra) yield* this.emit(extra, context);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
async *dispatchToBrain(event, context) {
|
|
203
|
-
const generator = this.config.brain(event, context);
|
|
204
|
-
while (true) {
|
|
205
|
-
const { value, done } = await generator.next();
|
|
206
|
-
if (done) return value;
|
|
207
|
-
yield* this.emit(value, context);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
async *executeAction(action2, params, context) {
|
|
211
|
-
for (const plugin2 of this.config.plugins || []) {
|
|
212
|
-
if (plugin2.onBeforeAction) {
|
|
213
|
-
const hookResult = await plugin2.onBeforeAction(
|
|
214
|
-
{ action: action2, params },
|
|
215
|
-
context
|
|
216
|
-
);
|
|
217
|
-
if (hookResult) {
|
|
218
|
-
yield* this.emit(hookResult, context);
|
|
219
|
-
if (context.isDone) return;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
if (this.config.hooks?.onBeforeAction) {
|
|
224
|
-
const hookResult = await this.config.hooks.onBeforeAction(
|
|
225
|
-
{ action: action2, params },
|
|
226
|
-
context
|
|
227
|
-
);
|
|
228
|
-
if (hookResult) {
|
|
229
|
-
yield* this.emit(hookResult, context);
|
|
230
|
-
if (context.isDone) return;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
try {
|
|
234
|
-
const generator = action2.execute(params, context);
|
|
235
|
-
let result;
|
|
236
|
-
while (true) {
|
|
237
|
-
const { value, done } = await generator.next();
|
|
238
|
-
if (done) {
|
|
239
|
-
result = value;
|
|
240
|
-
break;
|
|
241
|
-
}
|
|
242
|
-
yield* this.emit(value, context);
|
|
243
|
-
if (context.isDone) return;
|
|
244
|
-
}
|
|
245
|
-
for (const plugin2 of this.config.plugins || []) {
|
|
246
|
-
if (plugin2.onAfterAction) {
|
|
247
|
-
const extra = await plugin2.onAfterAction(
|
|
248
|
-
{ action: action2, data: result },
|
|
249
|
-
context
|
|
250
|
-
);
|
|
251
|
-
if (extra) yield* this.emit(extra, context);
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
if (this.config.hooks?.onAfterAction) {
|
|
255
|
-
const extra = await this.config.hooks.onAfterAction(
|
|
256
|
-
{ action: action2, data: result },
|
|
257
|
-
context
|
|
258
|
-
);
|
|
259
|
-
if (extra) yield* this.emit(extra, context);
|
|
260
|
-
}
|
|
261
|
-
return result;
|
|
262
|
-
} catch (error) {
|
|
263
|
-
yield* this.emit(
|
|
264
|
-
{
|
|
265
|
-
type: "error",
|
|
266
|
-
data: {
|
|
267
|
-
action: action2.name,
|
|
268
|
-
error: error instanceof Error ? error.message : String(error)
|
|
269
|
-
}
|
|
270
|
-
},
|
|
271
|
-
context
|
|
272
|
-
);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
/**
|
|
276
|
-
* Internal helper to yield an event and trigger the onEvent hook.
|
|
277
|
-
*/
|
|
278
|
-
async *emit(event, context) {
|
|
279
|
-
const finalEvent = {
|
|
280
|
-
...event,
|
|
281
|
-
runId: context.runId,
|
|
282
|
-
timestamp: event.timestamp ?? Date.now(),
|
|
283
|
-
role: event.role ?? "assistant"
|
|
284
|
-
};
|
|
285
|
-
yield finalEvent;
|
|
286
|
-
for (const plugin2 of this.config.plugins || []) {
|
|
287
|
-
if (plugin2.onEvent) {
|
|
288
|
-
const extra = await plugin2.onEvent(finalEvent, context);
|
|
289
|
-
if (extra) {
|
|
290
|
-
yield { ...extra, runId: context.runId, timestamp: Date.now() };
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
if (this.config.hooks?.onEvent) {
|
|
295
|
-
const extra = await this.config.hooks.onEvent(finalEvent, context);
|
|
296
|
-
if (extra) {
|
|
297
|
-
yield { ...extra, runId: context.runId, timestamp: Date.now() };
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
};
|
|
302
|
-
var melony = (config) => {
|
|
303
|
-
const runtime = new Runtime(config);
|
|
304
|
-
return {
|
|
305
|
-
config,
|
|
306
|
-
run: runtime.run.bind(runtime)
|
|
307
|
-
};
|
|
308
|
-
};
|
|
309
|
-
var action = (config) => config;
|
|
310
|
-
var plugin = (config) => config;
|
|
311
|
-
|
|
312
|
-
export { Runtime, action, melony, plugin, ui };
|
|
2
|
+
export { Runtime, action, melony, plugin, ui } from './chunk-WCI7WEZW.js';
|
|
3
|
+
export { generateId } from './chunk-WAI5H335.js';
|
|
313
4
|
//# sourceMappingURL=index.js.map
|
|
314
5
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/runtime.ts"],"names":["plugin","action"],"mappings":"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","file":"index.js","sourcesContent":["import z from \"zod\";\n\n// ============================================\n// UI Protocol & Contracts\n// ============================================\n\nexport type UISize = \"sm\" | \"md\" | \"lg\";\nexport type UIAlign = \"start\" | \"center\" | \"end\" | \"stretch\";\nexport type UIJustify = \"start\" | \"center\" | \"end\" | \"between\" | \"around\";\nexport type UIWrap = \"nowrap\" | \"wrap\" | \"wrap-reverse\";\nexport type UIOrientation = \"horizontal\" | \"vertical\";\n\nexport type UIColor =\n | \"primary\"\n | \"secondary\"\n | \"success\"\n | \"danger\"\n | \"warning\"\n | \"info\"\n | \"background\"\n | \"foreground\"\n | \"muted\"\n | \"mutedForeground\"\n | \"border\";\n\nexport type UISpacing = \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\" | \"xxl\";\n\n/**\n * UI Component Contracts\n * This acts as the source of truth for the SDUI protocol.\n */\nexport interface UIContract {\n card: {\n title?: string;\n subtitle?: string;\n background?: string;\n isLoading?: boolean;\n };\n row: {\n align?: UIAlign;\n justify?: UIJustify;\n wrap?: UIWrap;\n gap?: UISpacing;\n };\n col: {\n align?: UIAlign;\n justify?: UIJustify;\n gap?: UISpacing;\n width?: string | number;\n height?: string | number;\n padding?: UISpacing;\n };\n box: {\n padding?: UISpacing;\n margin?: string | number;\n background?: string;\n border?: boolean;\n borderRadius?: UISpacing;\n width?: string | number;\n height?: string | number;\n };\n spacer: {\n size?: UISpacing;\n direction?: UIOrientation;\n };\n divider: {\n orientation?: UIOrientation;\n color?: UIColor;\n };\n text: {\n value: string;\n size?: UISpacing;\n weight?: \"normal\" | \"medium\" | \"semibold\" | \"bold\";\n color?: UIColor;\n align?: UIAlign;\n };\n heading: {\n value: string;\n level?: 1 | 2 | 3 | 4 | 5 | 6;\n };\n badge: {\n label: string;\n variant?: \"primary\" | \"secondary\" | \"success\" | \"danger\" | \"warning\";\n size?: UISize;\n };\n image: {\n src: string;\n alt?: string;\n size?: UISize;\n };\n icon: {\n name: string;\n size?: UISize;\n color?: UIColor;\n };\n chart: {\n data: Array<{ label: string; value: number; color?: string }>;\n chartType?: \"bar\" | \"line\" | \"area\" | \"pie\";\n title?: string;\n };\n list: {};\n listItem: {\n onClickAction?: Event;\n gap?: UISpacing;\n };\n form: {\n onSubmitAction?: Event;\n };\n input: {\n name: string;\n label?: string;\n placeholder?: string;\n defaultValue?: string;\n inputType?: string;\n onChangeAction?: Event;\n };\n textarea: {\n name: string;\n label?: string;\n placeholder?: string;\n defaultValue?: string;\n rows?: number;\n onChangeAction?: Event;\n };\n select: {\n name: string;\n label?: string;\n options: Array<{ label: string; value: string }>;\n defaultValue?: string;\n placeholder?: string;\n onChangeAction?: Event;\n };\n checkbox: {\n name: string;\n label?: string;\n checked?: boolean;\n onChangeAction?: Event;\n };\n radioGroup: {\n name: string;\n options: Array<{ label: string; value: string; disabled?: boolean }>;\n label?: string;\n defaultValue?: string;\n orientation?: UIOrientation;\n onChangeAction?: Event;\n };\n label: {\n value: string;\n htmlFor?: string;\n required?: boolean;\n };\n button: {\n label: string;\n variant?: \"primary\" | \"secondary\" | \"success\" | \"danger\" | \"outline\" | \"ghost\" | \"link\";\n size?: UISize;\n disabled?: boolean;\n onClickAction?: Event;\n };\n}\n\nexport type UINode<T extends keyof UIContract = keyof UIContract> = {\n type: T;\n props?: UIContract[T];\n children?: UINode<any>[];\n};\n\n/**\n * UI Builder for SDUI.\n * Typed using the UIContract source of truth.\n */\nexport const ui = {\n card: (props: UIContract[\"card\"] & { children?: UINode<any>[] }): UINode<\"card\"> => {\n const { children, ...rest } = props;\n return { type: \"card\", props: rest, children };\n },\n row: (props: UIContract[\"row\"] & { children?: UINode<any>[] }): UINode<\"row\"> => {\n const { children, ...rest } = props;\n return { type: \"row\", props: rest, children };\n },\n col: (props: UIContract[\"col\"] & { children?: UINode<any>[] }): UINode<\"col\"> => {\n const { children, ...rest } = props;\n return { type: \"col\", props: rest, children };\n },\n box: (props: UIContract[\"box\"] & { children?: UINode<any>[] }): UINode<\"box\"> => {\n const { children, ...rest } = props;\n return { type: \"box\", props: rest, children };\n },\n spacer: (props: UIContract[\"spacer\"]): UINode<\"spacer\"> => ({\n type: \"spacer\",\n props,\n }),\n divider: (props: UIContract[\"divider\"]): UINode<\"divider\"> => ({\n type: \"divider\",\n props,\n }),\n text: (\n value: string,\n props?: Omit<UIContract[\"text\"], \"value\">\n ): UINode<\"text\"> => ({\n type: \"text\",\n props: { ...props, value },\n }),\n heading: (\n value: string,\n level: UIContract[\"heading\"][\"level\"] = 1\n ): UINode<\"heading\"> => ({\n type: \"heading\",\n props: { value, level },\n }),\n badge: (\n label: string,\n variant: UIContract[\"badge\"][\"variant\"] = \"primary\",\n size: UISize = \"md\"\n ): UINode<\"badge\"> => ({\n type: \"badge\",\n props: { label, variant, size },\n }),\n image: (\n src: string,\n alt?: string,\n size: UISize = \"md\"\n ): UINode<\"image\"> => ({\n type: \"image\",\n props: { src, alt, size },\n }),\n icon: (\n name: string,\n size: UISize = \"md\",\n color?: UIColor\n ): UINode<\"icon\"> => ({\n type: \"icon\",\n props: { name, size, color },\n }),\n chart: (props: UIContract[\"chart\"]): UINode<\"chart\"> => ({\n type: \"chart\",\n props,\n }),\n list: (children: UINode<any>[]): UINode<\"list\"> => ({\n type: \"list\",\n children,\n }),\n listItem: (\n props: UIContract[\"listItem\"] & { children: UINode<any>[] }\n ): UINode<\"listItem\"> => {\n const { children, ...rest } = props;\n return { type: \"listItem\", props: rest, children };\n },\n form: (props: UIContract[\"form\"] & { children?: UINode<any>[] }): UINode<\"form\"> => {\n const { children, ...rest } = props;\n return { type: \"form\", props: rest, children };\n },\n input: (props: UIContract[\"input\"]): UINode<\"input\"> => ({\n type: \"input\",\n props,\n }),\n textarea: (props: UIContract[\"textarea\"]): UINode<\"textarea\"> => ({\n type: \"textarea\",\n props,\n }),\n select: (props: UIContract[\"select\"]): UINode<\"select\"> => ({\n type: \"select\",\n props,\n }),\n checkbox: (props: UIContract[\"checkbox\"]): UINode<\"checkbox\"> => ({\n type: \"checkbox\",\n props,\n }),\n radioGroup: (props: UIContract[\"radioGroup\"]): UINode<\"radioGroup\"> => ({\n type: \"radioGroup\",\n props,\n }),\n label: (\n value: string,\n props?: Omit<UIContract[\"label\"], \"value\">\n ): UINode<\"label\"> => ({\n type: \"label\",\n props: { ...props, value },\n }),\n button: (props: UIContract[\"button\"]): UINode<\"button\"> => ({\n type: \"button\",\n props,\n }),\n};\n\n// ============================================\n// Events\n// ============================================\n\nexport type Role = \"user\" | \"assistant\" | \"system\";\n\nexport type Event = {\n type: string;\n data?: any;\n ui?: UINode;\n runId?: string;\n timestamp?: number;\n role?: Role;\n};\n\n// ============================================\n// Runtime & Hooks\n// ============================================\n\nexport interface Action<TParams extends z.ZodSchema = z.ZodObject<any>> {\n name: string;\n description?: string;\n paramsSchema: TParams;\n execute: (\n params: z.infer<TParams>,\n context: RuntimeContext\n ) => AsyncGenerator<Event, NextAction | void, unknown>;\n}\n\nexport interface NextAction {\n action?: string;\n params?: any;\n description?: string;\n}\n\nexport interface RuntimeContext<TState = any> {\n state: TState;\n runId: string;\n stepCount: number;\n isDone: boolean;\n actions: Record<string, Action<any>>;\n ui: typeof ui;\n suspend: () => void;\n}\n\n/**\n * Standardized Hook Result for consistent DX.\n */\nexport type HookResult = Promise<Event | void>;\n\nexport interface Hooks {\n /**\n * Called when a run session begins.\n * Can return an Event to be emitted, or a NextAction to jump-start the loop.\n */\n onBeforeRun?: (\n input: { event: Event; runId: string; state: Record<string, any> },\n context: RuntimeContext\n ) => Promise<Event | NextAction | void>;\n\n /**\n * Called when a run session completes.\n */\n onAfterRun?: (context: RuntimeContext) => HookResult;\n\n /**\n * Called whenever an event is yielded by the runtime.\n */\n onEvent?: (event: Event, context: RuntimeContext) => HookResult;\n\n /**\n * Called before an action is executed.\n * Return an event to intercept/suspend the action.\n */\n onBeforeAction?: (\n call: { action: Action<any>; params: any },\n context: RuntimeContext\n ) => HookResult;\n\n /**\n * Called after an action completes.\n */\n onAfterAction?: (\n result: { action: Action<any>; data: NextAction | void },\n context: RuntimeContext\n ) => HookResult;\n}\n\n/**\n * A plugin is just a named set of hooks.\n */\nexport interface Plugin extends Hooks {\n name: string;\n}\n\nexport interface Config {\n actions: Record<string, Action<any>>;\n /**\n * The central brain for handling incoming events.\n */\n brain?: (\n event: Event,\n context: RuntimeContext\n ) => AsyncGenerator<Event, NextAction | void, unknown>;\n hooks?: Hooks;\n plugins?: Plugin[];\n safetyMaxSteps?: number;\n}\n","import {\n Action,\n Event,\n NextAction,\n RuntimeContext,\n Config,\n Plugin,\n ui,\n} from \"./types\";\nimport { generateId } from \"./utils/generate-id\";\nimport { z } from \"zod\";\n\n/**\n * The Slim Runtime.\n * Single Responsibility: Orchestrate Event -> Action -> Event transitions.\n */\nexport class Runtime {\n private config: Config;\n\n constructor(config: Config) {\n this.config = config;\n }\n\n public async *run(input: {\n event: Event;\n runId?: string;\n state?: Record<string, any>;\n }): AsyncGenerator<Event> {\n const runId = input.runId ?? generateId();\n\n const context: RuntimeContext = {\n state: input.state ?? {},\n runId,\n stepCount: 0,\n isDone: false,\n actions: this.config.actions,\n ui,\n suspend: () => {\n context.isDone = true;\n },\n };\n\n let nextAction: NextAction | void = undefined;\n\n // 1. Trigger Plugins: onBeforeRun\n for (const plugin of this.config.plugins || []) {\n if (plugin.onBeforeRun) {\n const result = await plugin.onBeforeRun(\n { event: input.event, runId, state: context.state },\n context\n );\n if (result) {\n if (\"type\" in result) {\n yield* this.emit(result, context);\n } else {\n nextAction = result;\n }\n }\n }\n }\n\n // 2. Trigger Hook: onBeforeRun\n if (this.config.hooks?.onBeforeRun) {\n const result = await this.config.hooks.onBeforeRun(\n { event: input.event, runId, state: context.state },\n context\n );\n if (result) {\n if (\"type\" in result) {\n yield* this.emit(result, context);\n } else {\n nextAction = result;\n }\n }\n }\n\n if (context.isDone) return;\n\n yield* this.emit(\n { type: \"run-started\", data: { inputEvent: input.event } },\n context\n );\n\n // Initial dispatch of the incoming event to the agent's brain\n // Only if onBeforeRun didn't already provide a nextAction\n if (!nextAction && this.config.brain) {\n nextAction = yield* this.dispatchToBrain(input.event, context);\n }\n\n // Agentic loop\n while (nextAction && !context.isDone) {\n if (context.stepCount++ >= (this.config.safetyMaxSteps ?? 10)) {\n yield* this.emit(\n { type: \"error\", data: { message: \"Max steps exceeded\" } },\n context\n );\n break;\n }\n\n const current: NextAction = nextAction;\n nextAction = undefined; // Reset\n\n // 1. Resolve Action\n const actionName: string =\n current.action ?? Object.keys(this.config.actions)[0];\n const action: Action<any> = this.config.actions[actionName];\n\n if (!action) {\n yield* this.emit(\n {\n type: \"error\",\n data: { message: `Action ${actionName} not found` },\n },\n context\n );\n break;\n }\n\n // 2. Execute Action\n const result = yield* this.executeAction(action, current.params, context);\n\n // 3. Decide Next Step\n if (this.config.brain) {\n // If we have a brain, feed the result back to it to decide what to do next.\n // This keeps the brain in the loop for multi-step reasoning.\n nextAction = yield* this.dispatchToBrain(\n {\n type: \"action-result\",\n data: {\n action: actionName,\n params: current.params,\n result,\n },\n },\n context\n );\n } else {\n // Simple mode: follow the action's own suggestion for the next step.\n nextAction = result;\n }\n }\n\n // 1. Trigger Plugins: onAfterRun\n for (const plugin of this.config.plugins || []) {\n if (plugin.onAfterRun) {\n const extra = await plugin.onAfterRun(context);\n if (extra) yield* this.emit(extra, context);\n }\n }\n\n // 2. Trigger Hook: onAfterRun\n if (this.config.hooks?.onAfterRun) {\n const extra = await this.config.hooks.onAfterRun(context);\n if (extra) yield* this.emit(extra, context);\n }\n }\n\n private async *dispatchToBrain(\n event: Event,\n context: RuntimeContext\n ): AsyncGenerator<Event, NextAction | void> {\n const generator = this.config.brain!(event, context);\n while (true) {\n const { value, done } = await generator.next();\n if (done) return value as NextAction | void;\n yield* this.emit(value as Event, context);\n }\n }\n\n private async *executeAction(\n action: Action,\n params: any,\n context: RuntimeContext\n ): AsyncGenerator<Event, NextAction | void> {\n // 1. Trigger Plugins: onBeforeAction\n for (const plugin of this.config.plugins || []) {\n if (plugin.onBeforeAction) {\n const hookResult = await plugin.onBeforeAction(\n { action, params },\n context\n );\n if (hookResult) {\n yield* this.emit(hookResult, context);\n if (context.isDone) return;\n }\n }\n }\n\n // 2. Trigger Hook: onBeforeAction\n if (this.config.hooks?.onBeforeAction) {\n const hookResult = await this.config.hooks.onBeforeAction(\n { action, params },\n context\n );\n if (hookResult) {\n yield* this.emit(hookResult, context);\n if (context.isDone) return;\n }\n }\n\n try {\n const generator = action.execute(params, context);\n let result: NextAction | void;\n\n while (true) {\n const { value, done } = await generator.next();\n if (done) {\n result = value as NextAction | void;\n break;\n }\n yield* this.emit(value as Event, context);\n if (context.isDone) return;\n }\n\n // 3. Trigger Plugins: onAfterAction\n for (const plugin of this.config.plugins || []) {\n if (plugin.onAfterAction) {\n const extra = await plugin.onAfterAction(\n { action, data: result },\n context\n );\n if (extra) yield* this.emit(extra, context);\n }\n }\n\n // 4. Trigger Hook: onAfterAction\n if (this.config.hooks?.onAfterAction) {\n const extra = await this.config.hooks.onAfterAction(\n { action, data: result },\n context\n );\n if (extra) yield* this.emit(extra, context);\n }\n\n return result;\n } catch (error) {\n yield* this.emit(\n {\n type: \"error\",\n data: {\n action: action.name,\n error: error instanceof Error ? error.message : String(error),\n },\n },\n context\n );\n }\n }\n\n /**\n * Internal helper to yield an event and trigger the onEvent hook.\n */\n private async *emit(\n event: Event,\n context: RuntimeContext\n ): AsyncGenerator<Event> {\n const finalEvent = {\n ...event,\n runId: context.runId,\n timestamp: event.timestamp ?? Date.now(),\n role: event.role ?? \"assistant\",\n };\n\n // Yield the actual event first\n yield finalEvent;\n\n // 1. Trigger Plugins: onEvent\n for (const plugin of this.config.plugins || []) {\n if (plugin.onEvent) {\n const extra = await plugin.onEvent(finalEvent, context);\n if (extra) {\n yield { ...extra, runId: context.runId, timestamp: Date.now() };\n }\n }\n }\n\n // 2. Trigger Hook: onEvent for side-effects or extra events\n if (this.config.hooks?.onEvent) {\n const extra = await this.config.hooks.onEvent(finalEvent, context);\n if (extra) {\n // Yield extra event from hook, ensuring it has required metadata\n yield { ...extra, runId: context.runId, timestamp: Date.now() };\n }\n }\n }\n}\n\nexport const melony = (config: Config) => {\n const runtime = new Runtime(config);\n return {\n config,\n run: runtime.run.bind(runtime),\n };\n};\n\n/**\n * Helper to define an action with full type inference.\n */\nexport const action = <T extends z.ZodSchema>(\n config: Action<T>\n): Action<T> => config;\n\n/**\n * Helper to define a plugin.\n */\nexport const plugin = (config: Plugin): Plugin => config;\n"]}
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { A as Action, i as RuntimeContext, P as Plugin } from '../types-BC3dKPi6.js';
|
|
2
|
+
import 'zod';
|
|
3
|
+
|
|
4
|
+
interface RequireApprovalOptions {
|
|
5
|
+
/**
|
|
6
|
+
* List of action names that require explicit approval.
|
|
7
|
+
* If not provided, all actions will require approval.
|
|
8
|
+
*/
|
|
9
|
+
actions?: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Optional secret to sign the approval payload.
|
|
12
|
+
* If provided, the plugin will verify that the parameters haven't been
|
|
13
|
+
* tampered with between the request and the approval.
|
|
14
|
+
*/
|
|
15
|
+
secret?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Custom message to show in the approval card.
|
|
18
|
+
*/
|
|
19
|
+
message?: string | ((action: string, params: any) => string);
|
|
20
|
+
/**
|
|
21
|
+
* Optional condition to check if approval is needed dynamically.
|
|
22
|
+
*/
|
|
23
|
+
shouldApprove?: (action: Action<any>, params: any, context: RuntimeContext) => boolean | Promise<boolean>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* A plugin that intercepts actions and requires human approval before execution.
|
|
27
|
+
* It uses SDUI to prompt the user and handles the resumption of the agentic loop.
|
|
28
|
+
*/
|
|
29
|
+
declare const requireApproval: (options?: RequireApprovalOptions) => Plugin;
|
|
30
|
+
|
|
31
|
+
export { type RequireApprovalOptions, requireApproval };
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { plugin, ui } from '../chunk-WCI7WEZW.js';
|
|
2
|
+
import '../chunk-WAI5H335.js';
|
|
3
|
+
|
|
4
|
+
// src/plugins/require-approval.ts
|
|
5
|
+
var requireApproval = (options = {}) => {
|
|
6
|
+
return plugin({
|
|
7
|
+
name: "require-approval",
|
|
8
|
+
/**
|
|
9
|
+
* Step 1: Handle the resumption when the user clicks "Approve".
|
|
10
|
+
*/
|
|
11
|
+
onBeforeRun: async ({ event }, context) => {
|
|
12
|
+
if (event.type === "action-approved") {
|
|
13
|
+
const { action, params, token, ...rest } = event.data;
|
|
14
|
+
if (options.secret) {
|
|
15
|
+
const expectedToken = await signPayload({ action, params }, options.secret);
|
|
16
|
+
if (token !== expectedToken) {
|
|
17
|
+
return {
|
|
18
|
+
type: "error",
|
|
19
|
+
data: { message: "Security Warning: Approval token mismatch. Execution blocked." }
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
context.state.__approved_action = { action, params };
|
|
24
|
+
return { action, params, ...rest };
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
/**
|
|
28
|
+
* Step 2: Intercept actions that require approval.
|
|
29
|
+
*/
|
|
30
|
+
onBeforeAction: async ({ action, params, nextAction }, context) => {
|
|
31
|
+
const isTargetAction = !options.actions || options.actions.includes(action.name);
|
|
32
|
+
if (!isTargetAction) return;
|
|
33
|
+
if (options.shouldApprove) {
|
|
34
|
+
const needsApproval = await options.shouldApprove(action, params, context);
|
|
35
|
+
if (!needsApproval) return;
|
|
36
|
+
}
|
|
37
|
+
const approval = context.state.__approved_action;
|
|
38
|
+
if (approval && approval.action === action.name && JSON.stringify(approval.params) === JSON.stringify(params)) {
|
|
39
|
+
delete context.state.__approved_action;
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
context.suspend();
|
|
43
|
+
const token = options.secret ? await signPayload({ action: action.name, params }, options.secret) : void 0;
|
|
44
|
+
const message = typeof options.message === "function" ? options.message(action.name, params) : options.message || `The agent wants to execute **${action.name}**. Do you approve?`;
|
|
45
|
+
return {
|
|
46
|
+
type: "hitl-required",
|
|
47
|
+
data: { ...nextAction, token },
|
|
48
|
+
ui: ui.card({
|
|
49
|
+
title: "Approval Required",
|
|
50
|
+
children: [
|
|
51
|
+
ui.text(message),
|
|
52
|
+
ui.box({
|
|
53
|
+
padding: "md",
|
|
54
|
+
background: "muted",
|
|
55
|
+
children: [
|
|
56
|
+
ui.text(JSON.stringify(params, null, 2), { size: "xs" })
|
|
57
|
+
]
|
|
58
|
+
}),
|
|
59
|
+
ui.row({
|
|
60
|
+
gap: "md",
|
|
61
|
+
children: [
|
|
62
|
+
ui.button({
|
|
63
|
+
label: "Approve",
|
|
64
|
+
variant: "success",
|
|
65
|
+
onClickAction: {
|
|
66
|
+
type: "action-approved",
|
|
67
|
+
data: { ...nextAction, token }
|
|
68
|
+
}
|
|
69
|
+
}),
|
|
70
|
+
ui.button({
|
|
71
|
+
label: "Cancel",
|
|
72
|
+
variant: "outline",
|
|
73
|
+
onClickAction: {
|
|
74
|
+
type: "action-rejected",
|
|
75
|
+
data: { action: action.name }
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
]
|
|
79
|
+
})
|
|
80
|
+
]
|
|
81
|
+
})
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
async function signPayload(data, secret) {
|
|
87
|
+
const msg = JSON.stringify(data);
|
|
88
|
+
const encoder = new TextEncoder();
|
|
89
|
+
const keyData = encoder.encode(secret);
|
|
90
|
+
const dataToSign = encoder.encode(msg);
|
|
91
|
+
const key = await crypto.subtle.importKey(
|
|
92
|
+
"raw",
|
|
93
|
+
keyData,
|
|
94
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
95
|
+
false,
|
|
96
|
+
["sign"]
|
|
97
|
+
);
|
|
98
|
+
const signature = await crypto.subtle.sign("HMAC", key, dataToSign);
|
|
99
|
+
return btoa(String.fromCharCode(...new Uint8Array(signature)));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export { requireApproval };
|
|
103
|
+
//# sourceMappingURL=require-approval.js.map
|
|
104
|
+
//# sourceMappingURL=require-approval.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/plugins/require-approval.ts"],"names":[],"mappings":"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","file":"require-approval.js","sourcesContent":["import { plugin } from \"../runtime\";\nimport { ui } from \"../types\";\nimport type { Action, RuntimeContext } from \"../types\";\n\nexport interface RequireApprovalOptions {\n /**\n * List of action names that require explicit approval.\n * If not provided, all actions will require approval.\n */\n actions?: string[];\n\n /**\n * Optional secret to sign the approval payload.\n * If provided, the plugin will verify that the parameters haven't been \n * tampered with between the request and the approval.\n */\n secret?: string;\n\n /**\n * Custom message to show in the approval card.\n */\n message?: string | ((action: string, params: any) => string);\n\n /**\n * Optional condition to check if approval is needed dynamically.\n */\n shouldApprove?: (action: Action<any>, params: any, context: RuntimeContext) => boolean | Promise<boolean>;\n}\n\n/**\n * A plugin that intercepts actions and requires human approval before execution.\n * It uses SDUI to prompt the user and handles the resumption of the agentic loop.\n */\nexport const requireApproval = (options: RequireApprovalOptions = {}) => {\n return plugin({\n name: \"require-approval\",\n\n /**\n * Step 1: Handle the resumption when the user clicks \"Approve\".\n */\n onBeforeRun: async ({ event }, context) => {\n if (event.type === \"action-approved\") {\n const { action, params, token, ...rest } = event.data;\n\n // Security: Verify the token if a secret was provided\n if (options.secret) {\n const expectedToken = await signPayload({ action, params }, options.secret);\n if (token !== expectedToken) {\n return {\n type: \"error\",\n data: { message: \"Security Warning: Approval token mismatch. Execution blocked.\" },\n };\n }\n }\n\n // Store approval in ephemeral state for the upcoming action execution\n context.state.__approved_action = { action, params };\n\n // Return the action to jump-start the loop exactly where we left off\n return { action, params, ...rest };\n }\n },\n\n /**\n * Step 2: Intercept actions that require approval.\n */\n onBeforeAction: async ({ action, params, nextAction }, context) => {\n // 1. Check if this action needs approval\n const isTargetAction = !options.actions || options.actions.includes(action.name);\n if (!isTargetAction) return;\n\n if (options.shouldApprove) {\n const needsApproval = await options.shouldApprove(action, params, context);\n if (!needsApproval) return;\n }\n\n // 2. Check if it was ALREADY approved in this run\n const approval = context.state.__approved_action;\n if (\n approval &&\n approval.action === action.name &&\n JSON.stringify(approval.params) === JSON.stringify(params)\n ) {\n delete context.state.__approved_action;\n return; // Proceed to execution\n }\n\n // 3. Suspend and request approval\n context.suspend();\n\n const token = options.secret \n ? await signPayload({ action: action.name, params }, options.secret)\n : undefined;\n\n const message = typeof options.message === \"function\"\n ? options.message(action.name, params)\n : options.message || `The agent wants to execute **${action.name}**. Do you approve?`;\n\n return {\n type: \"hitl-required\",\n data: { ...nextAction, token },\n ui: ui.card({\n title: \"Approval Required\",\n children: [\n ui.text(message),\n ui.box({\n padding: \"md\",\n background: \"muted\",\n children: [\n ui.text(JSON.stringify(params, null, 2), { size: \"xs\" }),\n ],\n }),\n ui.row({\n gap: \"md\",\n children: [\n ui.button({\n label: \"Approve\",\n variant: \"success\",\n onClickAction: {\n type: \"action-approved\",\n data: { ...nextAction, token },\n },\n }),\n ui.button({\n label: \"Cancel\",\n variant: \"outline\",\n onClickAction: {\n type: \"action-rejected\",\n data: { action: action.name },\n },\n }),\n ],\n }),\n ],\n }),\n };\n },\n });\n};\n\n/**\n * Simple HMAC signing using the Web Crypto API (supported in Node 16+ and Browsers).\n */\nasync function signPayload(data: any, secret: string): Promise<string> {\n const msg = JSON.stringify(data);\n const encoder = new TextEncoder();\n const keyData = encoder.encode(secret);\n const dataToSign = encoder.encode(msg);\n\n const key = await crypto.subtle.importKey(\n \"raw\",\n keyData,\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"]\n );\n\n const signature = await crypto.subtle.sign(\"HMAC\", key, dataToSign);\n return btoa(String.fromCharCode(...new Uint8Array(signature)));\n}\n\n"]}
|
|
@@ -214,6 +214,7 @@ interface NextAction {
|
|
|
214
214
|
action?: string;
|
|
215
215
|
params?: any;
|
|
216
216
|
description?: string;
|
|
217
|
+
[key: string]: any;
|
|
217
218
|
}
|
|
218
219
|
interface RuntimeContext<TState = any> {
|
|
219
220
|
state: TState;
|
|
@@ -253,6 +254,7 @@ interface Hooks {
|
|
|
253
254
|
onBeforeAction?: (call: {
|
|
254
255
|
action: Action<any>;
|
|
255
256
|
params: any;
|
|
257
|
+
nextAction: NextAction;
|
|
256
258
|
}, context: RuntimeContext) => HookResult;
|
|
257
259
|
/**
|
|
258
260
|
* Called after an action completes.
|
|
@@ -279,6 +281,4 @@ interface Config {
|
|
|
279
281
|
safetyMaxSteps?: number;
|
|
280
282
|
}
|
|
281
283
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
export { type Action as A, type Config as C, type Event as E, type HookResult as H, type NextAction as N, type Plugin as P, type Role as R, type UISize as U, type UIAlign as a, type UIJustify as b, type UIWrap as c, type UIOrientation as d, type UIColor as e, type UISpacing as f, type UIContract as g, type UINode as h, type RuntimeContext as i, type Hooks as j, generateId as k, ui as u };
|
|
284
|
+
export { type Action as A, type Config as C, type Event as E, type HookResult as H, type NextAction as N, type Plugin as P, type Role as R, type UISize as U, type UIAlign as a, type UIJustify as b, type UIWrap as c, type UIOrientation as d, type UIColor as e, type UISpacing as f, type UIContract as g, type UINode as h, type RuntimeContext as i, type Hooks as j, ui as u };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "melony",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -33,6 +33,11 @@
|
|
|
33
33
|
"import": "./dist/adapters/*.js",
|
|
34
34
|
"default": "./dist/adapters/*.js"
|
|
35
35
|
},
|
|
36
|
+
"./plugins/*": {
|
|
37
|
+
"types": "./dist/plugins/*.d.ts",
|
|
38
|
+
"import": "./dist/plugins/*.js",
|
|
39
|
+
"default": "./dist/plugins/*.js"
|
|
40
|
+
},
|
|
36
41
|
"./package.json": "./package.json"
|
|
37
42
|
},
|
|
38
43
|
"module": "dist/index.js",
|