simple-agents-wasm 0.3.2 → 0.3.4

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/index.d.ts CHANGED
@@ -7,9 +7,23 @@ export interface CompleteOptions {
7
7
  schema?: unknown;
8
8
  }
9
9
 
10
+ /**
11
+ * Simplified multimodal segment (normalized to OpenAI wire format before send).
12
+ * You may also pass native OpenAI parts (e.g. `{ type: "image_url", image_url: { url } }`).
13
+ */
14
+ export interface ContentPartInput {
15
+ type: "text" | "image" | "audio" | "video";
16
+ text?: string;
17
+ /** Base64 payload without data: prefix */
18
+ data?: string;
19
+ /** MIME type, e.g. image/png (also accepts camelCase `mediaType`) */
20
+ media_type?: string;
21
+ mediaType?: string;
22
+ }
23
+
10
24
  export interface MessageInput {
11
25
  role: "system" | "user" | "assistant" | "tool";
12
- content: string;
26
+ content: string | ContentPartInput[];
13
27
  name?: string;
14
28
  toolCallId?: string;
15
29
  toolCalls?: Array<JsToolCall>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "simple-agents-wasm",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "Browser-compatible SimpleAgents client for OpenAI-compatible providers",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -8,6 +8,17 @@ export class WasmClient {
8
8
  constructor(provider: string, config: any);
9
9
  runWorkflowYaml(workflow_path: string, _workflow_input: any): any;
10
10
  runWorkflowYamlString(yaml_text: string, workflow_input: any, workflow_options?: any | null): Promise<any>;
11
+ /**
12
+ * Run a YAML workflow from a YAML text string (new unified API alias).
13
+ *
14
+ * This is an alias for `runWorkflowYamlString` using the new naming convention.
15
+ * WASM cannot use file paths; pass the YAML document text directly.
16
+ *
17
+ * ```js
18
+ * const result = await client.runYamlString(yamlText, messages);
19
+ * ```
20
+ */
21
+ runYamlString(yaml_text: string, messages: any, options?: any | null): Promise<any>;
11
22
  streamEvents(model: string, prompt_or_messages: any, on_event: Function, options?: any | null): Promise<any>;
12
23
  }
13
24
 
@@ -26,6 +37,7 @@ export interface InitOutput {
26
37
  readonly wasmclient_new: (a: number, b: number, c: any) => [number, number, number];
27
38
  readonly wasmclient_runWorkflowYaml: (a: number, b: number, c: number, d: any) => [number, number, number];
28
39
  readonly wasmclient_runWorkflowYamlString: (a: number, b: number, c: number, d: any, e: number) => any;
40
+ readonly wasmclient_runYamlString: (a: number, b: number, c: number, d: any, e: number) => any;
29
41
  readonly wasmclient_streamEvents: (a: number, b: number, c: number, d: any, e: any, f: number) => any;
30
42
  readonly wasm_bindgen__convert__closures_____invoke__h9f53f643b01d7c8e: (a: number, b: number, c: any) => [number, number];
31
43
  readonly wasm_bindgen__convert__closures_____invoke__h05acb8c479b21d4b: (a: number, b: number, c: any, d: any) => void;
@@ -64,6 +64,26 @@ export class WasmClient {
64
64
  const ret = wasm.wasmclient_runWorkflowYamlString(this.__wbg_ptr, ptr0, len0, workflow_input, isLikeNone(workflow_options) ? 0 : addToExternrefTable0(workflow_options));
65
65
  return ret;
66
66
  }
67
+ /**
68
+ * Run a YAML workflow from a YAML text string (new unified API alias).
69
+ *
70
+ * This is an alias for `runWorkflowYamlString` using the new naming convention.
71
+ * WASM cannot use file paths; pass the YAML document text directly.
72
+ *
73
+ * ```js
74
+ * const result = await client.runYamlString(yamlText, messages);
75
+ * ```
76
+ * @param {string} yaml_text
77
+ * @param {any} messages
78
+ * @param {any | null} [options]
79
+ * @returns {Promise<any>}
80
+ */
81
+ runYamlString(yaml_text, messages, options) {
82
+ const ptr0 = passStringToWasm0(yaml_text, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
83
+ const len0 = WASM_VECTOR_LEN;
84
+ const ret = wasm.wasmclient_runYamlString(this.__wbg_ptr, ptr0, len0, messages, isLikeNone(options) ? 0 : addToExternrefTable0(options));
85
+ return ret;
86
+ }
67
87
  /**
68
88
  * @param {string} model
69
89
  * @param {any} prompt_or_messages
@@ -267,6 +287,10 @@ function __wbg_get_imports() {
267
287
  const ret = result;
268
288
  return ret;
269
289
  },
290
+ __wbg_isArray_4daec0bfe3d60230: function(arg0) {
291
+ const ret = Array.isArray(arg0);
292
+ return ret;
293
+ },
270
294
  __wbg_isArray_db61795ad004c139: function(arg0) {
271
295
  const ret = Array.isArray(arg0);
272
296
  return ret;
@@ -394,7 +418,7 @@ function __wbg_get_imports() {
394
418
  return ret;
395
419
  },
396
420
  __wbindgen_cast_0000000000000001: function(arg0, arg1) {
397
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 146, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
421
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 152, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
398
422
  const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h9f53f643b01d7c8e);
399
423
  return ret;
400
424
  },
Binary file
@@ -8,6 +8,7 @@ export const wasmclient_complete: (a: number, b: number, c: number, d: any, e: n
8
8
  export const wasmclient_new: (a: number, b: number, c: any) => [number, number, number];
9
9
  export const wasmclient_runWorkflowYaml: (a: number, b: number, c: number, d: any) => [number, number, number];
10
10
  export const wasmclient_runWorkflowYamlString: (a: number, b: number, c: number, d: any, e: number) => any;
11
+ export const wasmclient_runYamlString: (a: number, b: number, c: number, d: any, e: number) => any;
11
12
  export const wasmclient_streamEvents: (a: number, b: number, c: number, d: any, e: any, f: number) => any;
12
13
  export const wasm_bindgen__convert__closures_____invoke__h9f53f643b01d7c8e: (a: number, b: number, c: any) => [number, number];
13
14
  export const wasm_bindgen__convert__closures_____invoke__h05acb8c479b21d4b: (a: number, b: number, c: any, d: any) => void;
package/rust/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "simple-agents-wasm-rust"
3
- version = "0.3.2"
3
+ version = "0.3.4"
4
4
  edition = "2021"
5
5
  license = "MIT OR Apache-2.0"
6
6
 
package/rust/src/lib.rs CHANGED
@@ -18,7 +18,8 @@ struct ClientConfig {
18
18
  #[serde(rename_all = "camelCase")]
19
19
  struct MessageInput {
20
20
  role: String,
21
- content: String,
21
+ /// Plain string or multimodal parts array (OpenAI-compatible JSON).
22
+ content: JsonValue,
22
23
  name: Option<String>,
23
24
  #[serde(alias = "tool_call_id")]
24
25
  tool_call_id: Option<String>,
@@ -44,7 +45,8 @@ struct JsToolCallFunction {
44
45
  #[derive(Serialize, Clone)]
45
46
  struct OpenAiMessageInput {
46
47
  role: String,
47
- content: String,
48
+ /// Plain string or multimodal parts array.
49
+ content: JsonValue,
48
50
  #[serde(skip_serializing_if = "Option::is_none")]
49
51
  name: Option<String>,
50
52
  #[serde(skip_serializing_if = "Option::is_none")]
@@ -310,7 +312,7 @@ fn to_messages(prompt_or_messages: JsValue) -> Result<Vec<MessageInput>, JsValue
310
312
  }
311
313
  return Ok(vec![MessageInput {
312
314
  role: "user".to_string(),
313
- content: trimmed.to_string(),
315
+ content: JsonValue::String(trimmed.to_string()),
314
316
  name: None,
315
317
  tool_call_id: None,
316
318
  tool_calls: None,
@@ -325,12 +327,64 @@ fn to_messages(prompt_or_messages: JsValue) -> Result<Vec<MessageInput>, JsValue
325
327
  Ok(messages)
326
328
  }
327
329
 
330
+ /// Reads `media_type` or `mediaType` from a JSON object (JS often uses camelCase).
331
+ fn media_type_field(obj: &JsonMap<String, JsonValue>) -> Option<&str> {
332
+ obj.get("media_type")
333
+ .or_else(|| obj.get("mediaType"))
334
+ .and_then(|v| v.as_str())
335
+ }
336
+
337
+ /// Converts simplified multimodal parts (`type`: image|audio|video + data) to OpenAI chat
338
+ /// wire format. Passes through strings, native OpenAI parts, and unknown objects unchanged.
339
+ fn normalize_message_content(content: JsonValue) -> JsonValue {
340
+ match content {
341
+ JsonValue::Array(parts) => JsonValue::Array(
342
+ parts.into_iter().map(normalize_content_part).collect(),
343
+ ),
344
+ other => other,
345
+ }
346
+ }
347
+
348
+ fn normalize_content_part(part: JsonValue) -> JsonValue {
349
+ let Some(obj) = part.as_object() else {
350
+ return part;
351
+ };
352
+ let ty = obj.get("type").and_then(|v| v.as_str());
353
+ match ty {
354
+ Some("image") => {
355
+ let mt = media_type_field(obj).unwrap_or("");
356
+ let data = obj.get("data").and_then(|v| v.as_str()).unwrap_or("");
357
+ json!({
358
+ "type": "image_url",
359
+ "image_url": { "url": format!("data:{mt};base64,{data}") }
360
+ })
361
+ }
362
+ Some("audio") => {
363
+ let mt = media_type_field(obj).unwrap_or("");
364
+ let data = obj.get("data").and_then(|v| v.as_str()).unwrap_or("");
365
+ json!({
366
+ "type": "input_audio",
367
+ "input_audio": { "media_type": mt, "data": data }
368
+ })
369
+ }
370
+ Some("video") => {
371
+ let mt = media_type_field(obj).unwrap_or("");
372
+ let data = obj.get("data").and_then(|v| v.as_str()).unwrap_or("");
373
+ json!({
374
+ "type": "video",
375
+ "video": { "media_type": mt, "data": data }
376
+ })
377
+ }
378
+ _ => part,
379
+ }
380
+ }
381
+
328
382
  fn to_openai_messages(messages: Vec<MessageInput>) -> Vec<OpenAiMessageInput> {
329
383
  messages
330
384
  .into_iter()
331
385
  .map(|message| OpenAiMessageInput {
332
386
  role: message.role,
333
- content: message.content,
387
+ content: normalize_message_content(message.content),
334
388
  name: message.name,
335
389
  tool_call_id: message.tool_call_id,
336
390
  tool_calls: message.tool_calls.map(|tool_calls| {
@@ -1459,7 +1513,7 @@ impl WasmClient {
1459
1513
  if llm.append_prompt_as_user.unwrap_or(true) {
1460
1514
  history.push(MessageInput {
1461
1515
  role: "user".to_string(),
1462
- content: prompt,
1516
+ content: JsonValue::String(prompt),
1463
1517
  name: None,
1464
1518
  tool_call_id: None,
1465
1519
  tool_calls: None,
@@ -2000,6 +2054,37 @@ impl WasmClient {
2000
2054
  "workflow file paths are not supported in browser runtime: {workflow_path}"
2001
2055
  )))
2002
2056
  }
2057
+
2058
+ /// Run a YAML workflow from a YAML text string (new unified API alias).
2059
+ ///
2060
+ /// This is an alias for `runWorkflowYamlString` using the new naming convention.
2061
+ /// WASM cannot use file paths; pass the YAML document text directly.
2062
+ ///
2063
+ /// ```js
2064
+ /// const result = await client.runYamlString(yamlText, messages);
2065
+ /// ```
2066
+ #[wasm_bindgen(js_name = runYamlString)]
2067
+ pub async fn run_yaml_string(
2068
+ &self,
2069
+ yaml_text: String,
2070
+ messages: JsValue,
2071
+ options: Option<JsValue>,
2072
+ ) -> Result<JsValue, JsValue> {
2073
+ // Build workflow input envelope from the messages arg
2074
+ let messages_value: serde_json::Value = if messages.is_array() || messages.is_object() {
2075
+ serde_wasm_bindgen::from_value(messages)
2076
+ .unwrap_or(serde_json::json!([]))
2077
+ } else if let Some(prompt) = messages.as_string() {
2078
+ serde_json::json!([{"role": "user", "content": prompt}])
2079
+ } else {
2080
+ serde_json::json!([])
2081
+ };
2082
+
2083
+ let input_js = serde_wasm_bindgen::to_value(&serde_json::json!({ "messages": messages_value }))
2084
+ .map_err(|_| js_error("failed to serialize messages input"))?;
2085
+
2086
+ self.run_workflow_yaml_string(yaml_text, input_js, options).await
2087
+ }
2003
2088
  }
2004
2089
 
2005
2090
  #[wasm_bindgen(js_name = supportsRustWasm)]