melony 0.1.31 → 0.1.33

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.
@@ -105,13 +105,9 @@ var ui = {
105
105
  };
106
106
 
107
107
  // src/runtime.ts
108
- var RuntimeInterruption = class extends Error {
109
- constructor(event) {
110
- super("Runtime interrupted");
111
- this.event = event;
112
- this.name = "RuntimeInterruption";
113
- }
114
- };
108
+ function isEvent(val) {
109
+ return val && typeof val === "object" && typeof val.type === "string";
110
+ }
115
111
  var Runtime = class {
116
112
  constructor(config) {
117
113
  this.config = config;
@@ -125,37 +121,29 @@ var Runtime = class {
125
121
  actions: this.config.actions,
126
122
  ui,
127
123
  suspend: (event) => {
128
- throw new RuntimeInterruption(event);
124
+ throw event || { type: "run-suspended" };
129
125
  }
130
126
  };
131
127
  try {
132
128
  let nextAction = void 0;
133
129
  for (const plugin2 of this.config.plugins || []) {
134
130
  if (plugin2.onBeforeRun) {
135
- const result = await plugin2.onBeforeRun(
136
- { event: input.event },
131
+ const result = yield* this.callHook(
132
+ plugin2.onBeforeRun({ event: input.event }, context),
137
133
  context
138
134
  );
139
135
  if (result) {
140
- if ("type" in result) {
141
- yield* this.emit(result, context);
142
- } else {
143
- nextAction = result;
144
- }
136
+ nextAction = result;
145
137
  }
146
138
  }
147
139
  }
148
140
  if (this.config.hooks?.onBeforeRun) {
149
- const result = await this.config.hooks.onBeforeRun(
150
- { event: input.event },
141
+ const result = yield* this.callHook(
142
+ this.config.hooks.onBeforeRun({ event: input.event }, context),
151
143
  context
152
144
  );
153
145
  if (result) {
154
- if ("type" in result) {
155
- yield* this.emit(result, context);
156
- } else {
157
- nextAction = result;
158
- }
146
+ nextAction = result;
159
147
  }
160
148
  }
161
149
  yield* this.emit(
@@ -208,22 +196,29 @@ var Runtime = class {
208
196
  }
209
197
  for (const plugin2 of this.config.plugins || []) {
210
198
  if (plugin2.onAfterRun) {
211
- const extra = await plugin2.onAfterRun(context);
212
- if (extra) yield* this.emit(extra, context);
199
+ yield* this.callHook(plugin2.onAfterRun(context), context);
213
200
  }
214
201
  }
215
202
  if (this.config.hooks?.onAfterRun) {
216
- const extra = await this.config.hooks.onAfterRun(context);
217
- if (extra) yield* this.emit(extra, context);
203
+ yield* this.callHook(this.config.hooks.onAfterRun(context), context);
218
204
  }
219
205
  } catch (error) {
220
- if (error instanceof RuntimeInterruption) {
221
- if (error.event) {
222
- yield* this.emit(error.event, context);
223
- }
224
- return;
206
+ let eventToEmit;
207
+ if (isEvent(error)) {
208
+ eventToEmit = error;
209
+ } else {
210
+ eventToEmit = {
211
+ type: "error",
212
+ data: {
213
+ message: error instanceof Error ? error.message : String(error),
214
+ stack: error instanceof Error ? error.stack : void 0
215
+ }
216
+ };
217
+ }
218
+ if (eventToEmit) {
219
+ yield* this.emit(eventToEmit, context);
225
220
  }
226
- throw error;
221
+ return;
227
222
  }
228
223
  }
229
224
  async *dispatchToBrain(event, context) {
@@ -238,30 +233,22 @@ var Runtime = class {
238
233
  const params = nextAction.params;
239
234
  for (const plugin2 of this.config.plugins || []) {
240
235
  if (plugin2.onBeforeAction) {
241
- const hookResult = await plugin2.onBeforeAction(
242
- { action: action2, params, nextAction },
236
+ const hookResult = yield* this.callHook(
237
+ plugin2.onBeforeAction({ action: action2, params, nextAction }, context),
243
238
  context
244
239
  );
245
240
  if (hookResult) {
246
- if ("type" in hookResult) {
247
- yield* this.emit(hookResult, context);
248
- } else {
249
- nextAction = hookResult;
250
- }
241
+ nextAction = hookResult;
251
242
  }
252
243
  }
253
244
  }
254
245
  if (this.config.hooks?.onBeforeAction) {
255
- const hookResult = await this.config.hooks.onBeforeAction(
256
- { action: action2, params, nextAction },
246
+ const hookResult = yield* this.callHook(
247
+ this.config.hooks.onBeforeAction({ action: action2, params, nextAction }, context),
257
248
  context
258
249
  );
259
250
  if (hookResult) {
260
- if ("type" in hookResult) {
261
- yield* this.emit(hookResult, context);
262
- } else {
263
- nextAction = hookResult;
264
- }
251
+ nextAction = hookResult;
265
252
  }
266
253
  }
267
254
  try {
@@ -277,45 +264,46 @@ var Runtime = class {
277
264
  }
278
265
  for (const plugin2 of this.config.plugins || []) {
279
266
  if (plugin2.onAfterAction) {
280
- const extra = await plugin2.onAfterAction(
281
- { action: action2, data: result },
267
+ const extra = yield* this.callHook(
268
+ plugin2.onAfterAction({ action: action2, data: result }, context),
282
269
  context
283
270
  );
284
271
  if (extra) {
285
- if ("type" in extra) {
286
- yield* this.emit(extra, context);
287
- } else {
288
- nextAction = extra;
289
- }
272
+ nextAction = extra;
290
273
  }
291
274
  }
292
275
  }
293
276
  if (this.config.hooks?.onAfterAction) {
294
- const extra = await this.config.hooks.onAfterAction(
295
- { action: action2, data: result },
277
+ const extra = yield* this.callHook(
278
+ this.config.hooks.onAfterAction({ action: action2, data: result }, context),
296
279
  context
297
280
  );
298
281
  if (extra) {
299
- if ("type" in extra) {
300
- yield* this.emit(extra, context);
301
- } else {
302
- nextAction = extra;
303
- }
282
+ nextAction = extra;
304
283
  }
305
284
  }
306
285
  return result;
307
286
  } catch (error) {
308
- if (error instanceof RuntimeInterruption) throw error;
309
- yield* this.emit(
310
- {
311
- type: "error",
312
- data: {
313
- action: action2.name,
314
- error: error instanceof Error ? error.message : String(error)
315
- }
316
- },
317
- context
318
- );
287
+ if (isEvent(error)) throw error;
288
+ throw {
289
+ type: "error",
290
+ data: {
291
+ action: action2.name,
292
+ message: error instanceof Error ? error.message : String(error),
293
+ stack: error instanceof Error ? error.stack : void 0
294
+ }
295
+ };
296
+ }
297
+ }
298
+ /**
299
+ * Internal helper to call a hook (generator) and yield its events.
300
+ */
301
+ async *callHook(generator, context) {
302
+ if (!generator) return;
303
+ while (true) {
304
+ const { value, done } = await generator.next();
305
+ if (done) return value;
306
+ yield* this.emit(value, context);
319
307
  }
320
308
  }
321
309
  /**
@@ -332,15 +320,15 @@ var Runtime = class {
332
320
  yield finalEvent;
333
321
  for (const plugin2 of this.config.plugins || []) {
334
322
  if (plugin2.onEvent) {
335
- const extra = await plugin2.onEvent(finalEvent, context);
336
- if (extra) {
323
+ const generator = plugin2.onEvent(finalEvent, context);
324
+ for await (const extra of generator) {
337
325
  yield { ...extra, runId: context.runId, timestamp: Date.now() };
338
326
  }
339
327
  }
340
328
  }
341
329
  if (this.config.hooks?.onEvent) {
342
- const extra = await this.config.hooks.onEvent(finalEvent, context);
343
- if (extra) {
330
+ const generator = this.config.hooks.onEvent(finalEvent, context);
331
+ for await (const extra of generator) {
344
332
  yield { ...extra, runId: context.runId, timestamp: Date.now() };
345
333
  }
346
334
  }
@@ -356,6 +344,6 @@ var melony = (config) => {
356
344
  var action = (config) => config;
357
345
  var plugin = (config) => config;
358
346
 
359
- export { Runtime, RuntimeInterruption, action, melony, plugin, ui };
360
- //# sourceMappingURL=chunk-7NUZEGKK.js.map
361
- //# sourceMappingURL=chunk-7NUZEGKK.js.map
347
+ export { Runtime, action, melony, plugin, ui };
348
+ //# sourceMappingURL=chunk-NQ2SOCUO.js.map
349
+ //# sourceMappingURL=chunk-NQ2SOCUO.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-NQ2SOCUO.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?:\n | \"primary\"\n | \"secondary\"\n | \"success\"\n | \"danger\"\n | \"outline\"\n | \"ghost\"\n | \"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: (\n props: UIContract[\"card\"] & { children?: UINode<any>[] }\n ): UINode<\"card\"> => {\n const { children, ...rest } = props;\n return { type: \"card\", props: rest, children };\n },\n row: (\n props: UIContract[\"row\"] & { children?: UINode<any>[] }\n ): UINode<\"row\"> => {\n const { children, ...rest } = props;\n return { type: \"row\", props: rest, children };\n },\n col: (\n props: UIContract[\"col\"] & { children?: UINode<any>[] }\n ): UINode<\"col\"> => {\n const { children, ...rest } = props;\n return { type: \"col\", props: rest, children };\n },\n box: (\n props: UIContract[\"box\"] & { children?: UINode<any>[] }\n ): 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: (src: string, alt?: string, size: UISize = \"md\"): 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: (\n props: UIContract[\"form\"] & { children?: UINode<any>[] }\n ): 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 actions: {\n navigate: (url: string): Event => ({\n type: \"client:navigate\",\n data: { url },\n }),\n openUrl: (url: string, target = \"_blank\"): Event => ({\n type: \"client:open-url\",\n data: { url, target },\n }),\n copy: (text: string): Event => ({ type: \"client:copy\", data: { text } }),\n reset: (): Event => ({ type: \"client:reset\" }),\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 slot?: string;\n runId?: string;\n threadId?: string;\n timestamp?: number;\n role?: Role;\n state?: any;\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 actions: Record<string, Action<any>>;\n ui: typeof ui;\n /**\n * Immediately interrupts the runtime execution.\n * If an event is provided, it will be emitted before the runtime stops.\n */\n suspend: (event?: Event) => never;\n}\n\n/**\n * Standardized Hook Result.\n * Now a generator to allow yielding multiple events and returning a result.\n */\nexport type HookGenerator<TReturn = void> = AsyncGenerator<\n Event,\n TReturn | void,\n unknown\n>;\n\nexport interface Hooks {\n /**\n * Called when a run session begins.\n * Can yield Events to be emitted, and return a NextAction to jump-start the loop.\n */\n onBeforeRun?: (\n input: { event: Event },\n context: RuntimeContext\n ) => HookGenerator<NextAction>;\n\n /**\n * Called when a run session completes.\n */\n onAfterRun?: (context: RuntimeContext) => HookGenerator;\n\n /**\n * Called whenever an event is yielded by the runtime.\n */\n onEvent?: (event: Event, context: RuntimeContext) => HookGenerator;\n\n /**\n * Called before an action is executed.\n * Yield events to intercept, and return a NextAction to redirect/suspend.\n */\n onBeforeAction?: (\n call: { action: Action<any>; params: any; nextAction: NextAction },\n context: RuntimeContext\n ) => HookGenerator<NextAction>;\n\n /**\n * Called after an action completes.\n */\n onAfterAction?: (\n result: { action: Action<any>; data: NextAction | void },\n context: RuntimeContext\n ) => HookGenerator<NextAction>;\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 starterPrompts?: Array<{\n label: string;\n prompt: string;\n icon?: string;\n }>;\n options?: Array<{\n id: string;\n label: string;\n options: Array<{ id: string; label: string; value: any }>;\n type?: \"single\" | \"multiple\";\n defaultSelectedIds?: string[];\n }>;\n fileAttachments?: {\n enabled?: boolean;\n accept?: string; // e.g., \"image/*,.pdf\" for file input accept attribute\n maxFiles?: number; // Maximum number of files allowed\n maxFileSize?: number; // Maximum file size in bytes\n };\n}\n","import {\n Action,\n Event,\n NextAction,\n RuntimeContext,\n Config,\n Plugin,\n ui,\n HookGenerator,\n} from \"./types\";\nimport { generateId } from \"./utils/generate-id\";\nimport { z } from \"zod\";\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 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 }): AsyncGenerator<Event> {\n const runId = input.event.runId ?? generateId();\n\n const context: RuntimeContext = {\n state: input.event.state ?? {},\n runId,\n stepCount: 0,\n actions: this.config.actions,\n ui,\n suspend: (event?: Event) => {\n throw event || { type: \"run-suspended\" };\n },\n };\n\n try {\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 = yield* this.callHook(\n plugin.onBeforeRun({ event: input.event }, context),\n context\n );\n if (result) {\n nextAction = result as NextAction;\n }\n }\n }\n\n // 2. Trigger Hook: onBeforeRun\n if (this.config.hooks?.onBeforeRun) {\n const result = yield* this.callHook(\n this.config.hooks.onBeforeRun({ event: input.event }, context),\n context\n );\n if (result) {\n nextAction = result as NextAction;\n }\n }\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) {\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 yield* this.callHook(plugin.onAfterRun(context), context);\n }\n }\n\n // 2. Trigger Hook: onAfterRun\n if (this.config.hooks?.onAfterRun) {\n yield* this.callHook(this.config.hooks.onAfterRun(context), context);\n }\n } catch (error) {\n let eventToEmit: Event | undefined;\n\n if (isEvent(error)) {\n eventToEmit = error;\n } else {\n // Wrap unexpected errors into an Event\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 };\n }\n\n if (eventToEmit) {\n yield* this.emit(eventToEmit, context);\n }\n\n return; // Gracefully stop the runtime\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 = yield* this.callHook(\n plugin.onBeforeAction({ action, params, nextAction }, context),\n context\n );\n if (hookResult) {\n nextAction = hookResult as NextAction;\n }\n }\n }\n\n // 2. Trigger Hook: onBeforeAction\n if (this.config.hooks?.onBeforeAction) {\n const hookResult = yield* this.callHook(\n this.config.hooks.onBeforeAction({ action, params, nextAction }, context),\n context\n );\n if (hookResult) {\n nextAction = hookResult as NextAction;\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 }\n\n // 3. Trigger Plugins: onAfterAction\n for (const plugin of this.config.plugins || []) {\n if (plugin.onAfterAction) {\n const extra = yield* this.callHook(\n plugin.onAfterAction({ action, data: result }, context),\n context\n );\n if (extra) {\n nextAction = extra as NextAction;\n }\n }\n }\n\n // 4. Trigger Hook: onAfterAction\n if (this.config.hooks?.onAfterAction) {\n const extra = yield* this.callHook(\n this.config.hooks.onAfterAction({ action, data: result }, context),\n context\n );\n if (extra) {\n nextAction = extra as NextAction;\n }\n }\n\n return result;\n } catch (error) {\n if (isEvent(error)) throw error;\n\n throw {\n type: \"error\",\n data: {\n action: action.name,\n message: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n },\n };\n }\n }\n\n /**\n * Internal helper to call a hook (generator) and yield its events.\n */\n private async *callHook<T>(\n generator: HookGenerator<T> | undefined,\n context: RuntimeContext\n ): AsyncGenerator<Event, T | void> {\n if (!generator) return;\n\n while (true) {\n const { value, done } = await generator.next();\n if (done) return value as T | void;\n yield* this.emit(value as Event, context);\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 state: context.state,\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 generator = plugin.onEvent(finalEvent, context);\n for await (const extra of generator) {\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 generator = this.config.hooks.onEvent(finalEvent, context);\n for await (const extra of generator) {\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>(config: Action<T>): Action<T> =>\n 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,4 +1,4 @@
1
- import { E as Event, C as Config } from './types-DfZDQoND.js';
1
+ import { E as Event, C as Config } from './types-D8iQuUwX.js';
2
2
  export { g as generateId } from './generate-id-DU8kwYc2.js';
3
3
  import 'zod';
4
4
 
package/dist/index.d.ts CHANGED
@@ -1,16 +1,8 @@
1
- import { E as Event, C as Config, A as Action, P as Plugin } from './types-DfZDQoND.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-DfZDQoND.js';
1
+ import { C as Config, E as Event, A as Action, P as Plugin } from './types-D8iQuUwX.js';
2
+ export { H as HookGenerator, 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-D8iQuUwX.js';
3
3
  import { z } from 'zod';
4
4
  export { g as generateId } from './generate-id-DU8kwYc2.js';
5
5
 
6
- /**
7
- * Special error to immediately interrupt the runtime.
8
- * This is used for Human-In-The-Loop (HITL) or other suspension cases.
9
- */
10
- declare class RuntimeInterruption extends Error {
11
- event?: Event | undefined;
12
- constructor(event?: Event | undefined);
13
- }
14
6
  /**
15
7
  * The Slim Runtime.
16
8
  * Single Responsibility: Orchestrate Event -> Action -> Event transitions.
@@ -23,6 +15,10 @@ declare class Runtime {
23
15
  }): AsyncGenerator<Event>;
24
16
  private dispatchToBrain;
25
17
  private executeAction;
18
+ /**
19
+ * Internal helper to call a hook (generator) and yield its events.
20
+ */
21
+ private callHook;
26
22
  /**
27
23
  * Internal helper to yield an event and trigger the onEvent hook.
28
24
  */
@@ -49,4 +45,4 @@ declare const plugin: (config: Plugin) => Plugin;
49
45
  */
50
46
  declare function createStreamResponse(generator: AsyncGenerator<Event>): Response;
51
47
 
52
- export { Action, Config, Event, Plugin, Runtime, RuntimeInterruption, action, createStreamResponse, melony, plugin };
48
+ export { Action, Config, Event, Plugin, Runtime, action, createStreamResponse, melony, plugin };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export { createStreamResponse } from './chunk-CFG7FFEZ.js';
2
- export { Runtime, RuntimeInterruption, action, melony, plugin, ui } from './chunk-7NUZEGKK.js';
2
+ export { Runtime, action, melony, plugin, ui } from './chunk-NQ2SOCUO.js';
3
3
  export { generateId } from './chunk-WAI5H335.js';
4
4
  //# sourceMappingURL=index.js.map
5
5
  //# sourceMappingURL=index.js.map
@@ -1,4 +1,4 @@
1
- import { A as Action, i as RuntimeContext, P as Plugin } from '../types-DfZDQoND.js';
1
+ import { A as Action, i as RuntimeContext, P as Plugin } from '../types-D8iQuUwX.js';
2
2
  import 'zod';
3
3
 
4
4
  interface RequireApprovalOptions {
@@ -1,4 +1,4 @@
1
- import { plugin, ui } from '../chunk-7NUZEGKK.js';
1
+ import { plugin, ui } from '../chunk-NQ2SOCUO.js';
2
2
  import '../chunk-WAI5H335.js';
3
3
 
4
4
  // src/plugins/require-approval.ts
@@ -9,7 +9,7 @@ var requireApproval = (options = {}) => {
9
9
  * Step 1: Handle the resumption when the user clicks "Approve" or "Cancel".
10
10
  * We verify the one-time-use approvalId to prevent replay attacks or double-clicks.
11
11
  */
12
- onBeforeRun: async ({ event }, context) => {
12
+ onBeforeRun: async function* ({ event }, context) {
13
13
  if (event.type === "action-approved" || event.type === "action-rejected") {
14
14
  const { action, params, token, approvalId, ...rest } = event.data;
15
15
  const pending = context.state.__pending_approvals?.[approvalId];
@@ -38,12 +38,13 @@ var requireApproval = (options = {}) => {
38
38
  options.secret
39
39
  );
40
40
  if (token !== expectedToken) {
41
- return {
41
+ yield {
42
42
  type: "error",
43
43
  data: {
44
44
  message: "Security Warning: Approval token mismatch. Execution blocked."
45
45
  }
46
46
  };
47
+ return;
47
48
  }
48
49
  }
49
50
  context.state.__approved_action = { action, params };
@@ -60,7 +61,7 @@ var requireApproval = (options = {}) => {
60
61
  /**
61
62
  * Step 2: Intercept actions that require approval.
62
63
  */
63
- onBeforeAction: async ({ action, params, nextAction }, context) => {
64
+ onBeforeAction: async function* ({ action, params, nextAction }, context) {
64
65
  const isTargetAction = !options.actions || options.actions.includes(action.name);
65
66
  if (!isTargetAction) return;
66
67
  if (options.shouldApprove) {
@@ -1 +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?: (\n action: Action<any>,\n params: any,\n context: RuntimeContext\n ) => 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\" or \"Cancel\".\n * We verify the one-time-use approvalId to prevent replay attacks or double-clicks.\n */\n onBeforeRun: async ({ event }, context) => {\n if (\n event.type === \"action-approved\" ||\n event.type === \"action-rejected\"\n ) {\n const { action, params, token, approvalId, ...rest } = event.data;\n\n // 1. Check if this specific request exists and hasn't been used\n const pending = context.state.__pending_approvals?.[approvalId];\n if (!pending) {\n context.suspend({\n role: \"assistant\",\n type: \"error\",\n data: {\n message:\n \"Security Error: This approval request is invalid or has already been used.\",\n },\n ui: ui.card({\n title: \"Security Error\",\n children: [\n ui.text(\n \"This approval request is invalid or has already been used.\"\n ),\n ],\n }),\n });\n }\n\n // 2. Consume the token immediately (Destroy after usage)\n delete context.state.__pending_approvals[approvalId];\n\n if (event.type === \"action-approved\") {\n // 3. Security: Verify the token if a secret was provided\n if (options.secret) {\n const expectedToken = await signPayload(\n { action, params, approvalId },\n options.secret\n );\n if (token !== expectedToken) {\n return {\n type: \"error\",\n data: {\n message:\n \"Security Warning: Approval token mismatch. Execution blocked.\",\n },\n };\n }\n }\n\n // 4. 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 // Handle Rejection\n context.suspend({\n type: \"error\",\n data: {\n message: `Action '${action}' was rejected by the user.`,\n },\n });\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 =\n !options.actions || options.actions.includes(action.name);\n if (!isTargetAction) return;\n\n if (options.shouldApprove) {\n const needsApproval = await options.shouldApprove(\n action,\n params,\n context\n );\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 with a one-time-use nonce\n const approvalId = Math.random().toString(36).substring(2, 15);\n context.state.__pending_approvals =\n context.state.__pending_approvals || {};\n context.state.__pending_approvals[approvalId] = true;\n\n const token = options.secret\n ? await signPayload(\n { action: action.name, params, approvalId },\n options.secret\n )\n : undefined;\n\n const message =\n typeof options.message === \"function\"\n ? options.message(action.name, params)\n : options.message ||\n `The agent wants to execute **${action.name}**. Do you approve?`;\n\n context.suspend({\n type: \"hitl-required\",\n data: { ...nextAction, token, approvalId },\n slot: \"approval\",\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 role: \"user\",\n type: \"action-approved\",\n data: { ...nextAction, token, approvalId },\n ui: ui.text(\"Approval granted\"),\n },\n }),\n ui.button({\n label: \"Cancel\",\n variant: \"outline\",\n onClickAction: {\n type: \"action-rejected\",\n data: { action: action.name, approvalId },\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"]}
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?: (\n action: Action<any>,\n params: any,\n context: RuntimeContext\n ) => 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\" or \"Cancel\".\n * We verify the one-time-use approvalId to prevent replay attacks or double-clicks.\n */\n onBeforeRun: async function* ({ event }, context) {\n if (\n event.type === \"action-approved\" ||\n event.type === \"action-rejected\"\n ) {\n const { action, params, token, approvalId, ...rest } = event.data;\n\n // 1. Check if this specific request exists and hasn't been used\n const pending = context.state.__pending_approvals?.[approvalId];\n if (!pending) {\n context.suspend({\n role: \"assistant\",\n type: \"error\",\n data: {\n message:\n \"Security Error: This approval request is invalid or has already been used.\",\n },\n ui: ui.card({\n title: \"Security Error\",\n children: [\n ui.text(\n \"This approval request is invalid or has already been used.\"\n ),\n ],\n }),\n });\n }\n\n // 2. Consume the token immediately (Destroy after usage)\n delete context.state.__pending_approvals[approvalId];\n\n if (event.type === \"action-approved\") {\n // 3. Security: Verify the token if a secret was provided\n if (options.secret) {\n const expectedToken = await signPayload(\n { action, params, approvalId },\n options.secret\n );\n if (token !== expectedToken) {\n yield {\n type: \"error\",\n data: {\n message:\n \"Security Warning: Approval token mismatch. Execution blocked.\",\n },\n };\n return;\n }\n }\n\n // 4. 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 // Handle Rejection\n context.suspend({\n type: \"error\",\n data: {\n message: `Action '${action}' was rejected by the user.`,\n },\n });\n }\n },\n\n /**\n * Step 2: Intercept actions that require approval.\n */\n onBeforeAction: async function* ({ action, params, nextAction }, context) {\n // 1. Check if this action needs approval\n const isTargetAction =\n !options.actions || options.actions.includes(action.name);\n if (!isTargetAction) return;\n\n if (options.shouldApprove) {\n const needsApproval = await options.shouldApprove(\n action,\n params,\n context\n );\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 with a one-time-use nonce\n const approvalId = Math.random().toString(36).substring(2, 15);\n context.state.__pending_approvals =\n context.state.__pending_approvals || {};\n context.state.__pending_approvals[approvalId] = true;\n\n const token = options.secret\n ? await signPayload(\n { action: action.name, params, approvalId },\n options.secret\n )\n : undefined;\n\n const message =\n typeof options.message === \"function\"\n ? options.message(action.name, params)\n : options.message ||\n `The agent wants to execute **${action.name}**. Do you approve?`;\n\n context.suspend({\n type: \"hitl-required\",\n data: { ...nextAction, token, approvalId },\n slot: \"approval\",\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 role: \"user\",\n type: \"action-approved\",\n data: { ...nextAction, token, approvalId },\n ui: ui.text(\"Approval granted\"),\n },\n }),\n ui.button({\n label: \"Cancel\",\n variant: \"outline\",\n onClickAction: {\n type: \"action-rejected\",\n data: { action: action.name, approvalId },\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"]}
@@ -238,41 +238,42 @@ interface RuntimeContext<TState = any> {
238
238
  suspend: (event?: Event) => never;
239
239
  }
240
240
  /**
241
- * Standardized Hook Result for consistent DX.
241
+ * Standardized Hook Result.
242
+ * Now a generator to allow yielding multiple events and returning a result.
242
243
  */
243
- type HookResult = Promise<Event | void>;
244
+ type HookGenerator<TReturn = void> = AsyncGenerator<Event, TReturn | void, unknown>;
244
245
  interface Hooks {
245
246
  /**
246
247
  * Called when a run session begins.
247
- * Can return an Event to be emitted, or a NextAction to jump-start the loop.
248
+ * Can yield Events to be emitted, and return a NextAction to jump-start the loop.
248
249
  */
249
250
  onBeforeRun?: (input: {
250
251
  event: Event;
251
- }, context: RuntimeContext) => HookResult | NextAction;
252
+ }, context: RuntimeContext) => HookGenerator<NextAction>;
252
253
  /**
253
254
  * Called when a run session completes.
254
255
  */
255
- onAfterRun?: (context: RuntimeContext) => HookResult;
256
+ onAfterRun?: (context: RuntimeContext) => HookGenerator;
256
257
  /**
257
258
  * Called whenever an event is yielded by the runtime.
258
259
  */
259
- onEvent?: (event: Event, context: RuntimeContext) => HookResult;
260
+ onEvent?: (event: Event, context: RuntimeContext) => HookGenerator;
260
261
  /**
261
262
  * Called before an action is executed.
262
- * Return an event to intercept/suspend the action.
263
+ * Yield events to intercept, and return a NextAction to redirect/suspend.
263
264
  */
264
265
  onBeforeAction?: (call: {
265
266
  action: Action<any>;
266
267
  params: any;
267
268
  nextAction: NextAction;
268
- }, context: RuntimeContext) => HookResult | NextAction;
269
+ }, context: RuntimeContext) => HookGenerator<NextAction>;
269
270
  /**
270
271
  * Called after an action completes.
271
272
  */
272
273
  onAfterAction?: (result: {
273
274
  action: Action<any>;
274
275
  data: NextAction | void;
275
- }, context: RuntimeContext) => HookResult | NextAction;
276
+ }, context: RuntimeContext) => HookGenerator<NextAction>;
276
277
  }
277
278
  /**
278
279
  * A plugin is just a named set of hooks.
@@ -313,4 +314,4 @@ interface Config {
313
314
  };
314
315
  }
315
316
 
316
- 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 };
317
+ export { type Action as A, type Config as C, type Event as E, type HookGenerator 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.31",
3
+ "version": "0.1.33",
4
4
  "main": "dist/index.js",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/types.ts","../src/runtime.ts"],"names":["plugin","action"],"mappings":"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","file":"chunk-7NUZEGKK.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?:\n | \"primary\"\n | \"secondary\"\n | \"success\"\n | \"danger\"\n | \"outline\"\n | \"ghost\"\n | \"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: (\n props: UIContract[\"card\"] & { children?: UINode<any>[] }\n ): UINode<\"card\"> => {\n const { children, ...rest } = props;\n return { type: \"card\", props: rest, children };\n },\n row: (\n props: UIContract[\"row\"] & { children?: UINode<any>[] }\n ): UINode<\"row\"> => {\n const { children, ...rest } = props;\n return { type: \"row\", props: rest, children };\n },\n col: (\n props: UIContract[\"col\"] & { children?: UINode<any>[] }\n ): UINode<\"col\"> => {\n const { children, ...rest } = props;\n return { type: \"col\", props: rest, children };\n },\n box: (\n props: UIContract[\"box\"] & { children?: UINode<any>[] }\n ): 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: (src: string, alt?: string, size: UISize = \"md\"): 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: (\n props: UIContract[\"form\"] & { children?: UINode<any>[] }\n ): 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 actions: {\n navigate: (url: string): Event => ({\n type: \"client:navigate\",\n data: { url },\n }),\n openUrl: (url: string, target = \"_blank\"): Event => ({\n type: \"client:open-url\",\n data: { url, target },\n }),\n copy: (text: string): Event => ({ type: \"client:copy\", data: { text } }),\n reset: (): Event => ({ type: \"client:reset\" }),\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 slot?: string;\n runId?: string;\n threadId?: string;\n timestamp?: number;\n role?: Role;\n state?: any;\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 actions: Record<string, Action<any>>;\n ui: typeof ui;\n /**\n * Immediately interrupts the runtime execution.\n * If an event is provided, it will be emitted before the runtime stops.\n */\n suspend: (event?: Event) => never;\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 },\n context: RuntimeContext\n ) => HookResult | NextAction;\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 | NextAction;\n\n /**\n * Called after an action completes.\n */\n onAfterAction?: (\n result: { action: Action<any>; data: NextAction | void },\n context: RuntimeContext\n ) => HookResult | NextAction;\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 starterPrompts?: Array<{\n label: string;\n prompt: string;\n icon?: string;\n }>;\n options?: Array<{\n id: string;\n label: string;\n options: Array<{ id: string; label: string; value: any }>;\n type?: \"single\" | \"multiple\";\n defaultSelectedIds?: string[];\n }>;\n fileAttachments?: {\n enabled?: boolean;\n accept?: string; // e.g., \"image/*,.pdf\" for file input accept attribute\n maxFiles?: number; // Maximum number of files allowed\n maxFileSize?: number; // Maximum file size in bytes\n };\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 * Special error to immediately interrupt the runtime.\n * This is used for Human-In-The-Loop (HITL) or other suspension cases.\n */\nexport class RuntimeInterruption extends Error {\n constructor(public event?: Event) {\n super(\"Runtime interrupted\");\n this.name = \"RuntimeInterruption\";\n }\n}\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 }): AsyncGenerator<Event> {\n const runId = input.event.runId ?? generateId();\n\n const context: RuntimeContext = {\n state: input.event.state ?? {},\n runId,\n stepCount: 0,\n actions: this.config.actions,\n ui,\n suspend: (event?: Event) => {\n throw new RuntimeInterruption(event);\n },\n };\n\n try {\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 },\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 },\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 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) {\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 } catch (error) {\n if (error instanceof RuntimeInterruption) {\n // If the suspension carried an event, emit it before finishing\n if (error.event) {\n yield* this.emit(error.event, context);\n }\n return;\n }\n throw error;\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 if (\"type\" in hookResult) {\n yield* this.emit(hookResult as Event, context);\n } else {\n nextAction = hookResult as NextAction;\n }\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 if (\"type\" in hookResult) {\n yield* this.emit(hookResult as Event, context);\n } else {\n nextAction = hookResult as NextAction;\n }\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 }\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) {\n if (\"type\" in extra) {\n yield* this.emit(extra as Event, context);\n } else {\n nextAction = extra as NextAction;\n }\n }\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) {\n if (\"type\" in extra) {\n yield* this.emit(extra as Event, context);\n } else {\n nextAction = extra as NextAction;\n }\n }\n }\n\n return result;\n } catch (error) {\n if (error instanceof RuntimeInterruption) throw error;\n\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 state: context.state,\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>(config: Action<T>): Action<T> =>\n config;\n\n/**\n * Helper to define a plugin.\n */\nexport const plugin = (config: Plugin): Plugin => config;\n"]}