simple-agents-wasm 0.2.36 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts CHANGED
@@ -100,9 +100,43 @@ export interface ClientConfig {
100
100
  headers?: Record<string, string>;
101
101
  }
102
102
 
103
+ /** Matches Rust `YamlWorkflowTelemetryConfig` JSON (snake_case). */
104
+ export interface WorkflowTelemetryConfig {
105
+ enabled?: boolean;
106
+ nerdstats?: boolean;
107
+ sample_rate?: number;
108
+ payload_mode?: "full_payload" | "redacted_payload";
109
+ retention_days?: number;
110
+ multi_tenant?: boolean;
111
+ tool_trace_mode?: "full" | "redacted" | "off";
112
+ }
113
+
114
+ export interface WorkflowTraceContext {
115
+ trace_id?: string;
116
+ span_id?: string;
117
+ parent_span_id?: string;
118
+ traceparent?: string;
119
+ tracestate?: string;
120
+ baggage?: Record<string, string>;
121
+ }
122
+
123
+ export interface WorkflowTraceTenant {
124
+ workspace_id?: string;
125
+ user_id?: string;
126
+ conversation_id?: string;
127
+ request_id?: string;
128
+ run_id?: string;
129
+ }
130
+
131
+ export interface WorkflowTraceConfig {
132
+ context?: WorkflowTraceContext;
133
+ tenant?: WorkflowTraceTenant;
134
+ }
135
+
103
136
  export interface WorkflowRunOptions {
104
- telemetry?: Record<string, unknown>;
105
- trace?: Record<string, unknown>;
137
+ model?: string;
138
+ telemetry?: WorkflowTelemetryConfig;
139
+ trace?: WorkflowTraceConfig;
106
140
  onEvent?: (event: Record<string, unknown>) => void;
107
141
  functions?: Record<
108
142
  string,
@@ -113,6 +147,12 @@ export interface WorkflowRunOptions {
113
147
  >;
114
148
  }
115
149
 
150
+ /** Common workflow `input` fields; extra keys are allowed for workflow-specific payloads. */
151
+ export interface WorkflowInputFields {
152
+ email_text?: string;
153
+ [key: string]: unknown;
154
+ }
155
+
116
156
  export interface WorkflowRunEvent {
117
157
  stepId: string;
118
158
  stepType: string;
@@ -126,6 +166,24 @@ export interface WorkflowRunResult {
126
166
  events: WorkflowRunEvent[];
127
167
  }
128
168
 
169
+ export interface WorkflowExecutionFlags {
170
+ model?: string;
171
+ healing?: boolean;
172
+ workflow_streaming?: boolean;
173
+ node_llm_streaming?: boolean;
174
+ split_stream_deltas?: boolean;
175
+ }
176
+
177
+ export interface WorkflowExecutionRequest {
178
+ workflow_yaml: string;
179
+ messages: MessageInput[];
180
+ context?: Record<string, unknown>;
181
+ media?: Record<string, unknown>;
182
+ input?: WorkflowInputFields;
183
+ execution?: WorkflowExecutionFlags;
184
+ workflow_options?: WorkflowRunOptions;
185
+ }
186
+
129
187
  export declare class Client {
130
188
  constructor(provider: string, config: ClientConfig);
131
189
  complete(
@@ -154,6 +212,12 @@ export declare class Client {
154
212
  workflowPath: string,
155
213
  workflowInput: Record<string, unknown>
156
214
  ): Promise<never>;
215
+ run(request: WorkflowExecutionRequest): Promise<WorkflowRunResult>;
216
+ runAsync(request: WorkflowExecutionRequest): Promise<WorkflowRunResult>;
217
+ streamWorkflow(
218
+ request: WorkflowExecutionRequest,
219
+ onEvent?: (event: Record<string, unknown>) => void
220
+ ): Promise<WorkflowRunResult>;
157
221
  }
158
222
 
159
223
  export declare function hasRustBackend(): Promise<boolean>;
package/index.js CHANGED
@@ -30,6 +30,43 @@ function toMessages(promptOrMessages) {
30
30
  return promptOrMessages;
31
31
  }
32
32
 
33
+ function buildWorkflowInputFromExecutionRequest(request) {
34
+ if (!request || typeof request !== "object") {
35
+ throw configError("workflow request must be an object");
36
+ }
37
+ if (typeof request.workflow_yaml !== "string" || request.workflow_yaml.trim().length === 0) {
38
+ throw configError("workflow_yaml must be a non-empty string");
39
+ }
40
+ if (!Array.isArray(request.messages) || request.messages.length === 0) {
41
+ throw configError("messages must be a non-empty array");
42
+ }
43
+ const input = request.input && typeof request.input === "object" ? { ...request.input } : {};
44
+ input.messages = request.messages;
45
+ if (request.context && typeof request.context === "object") {
46
+ input.context = request.context;
47
+ }
48
+ if (request.media && typeof request.media === "object") {
49
+ input.media = request.media;
50
+ }
51
+ return input;
52
+ }
53
+
54
+ function buildWorkflowOptionsFromExecutionRequest(request, onEvent) {
55
+ const execution = request.execution && typeof request.execution === "object"
56
+ ? request.execution
57
+ : {};
58
+ const options = request.workflow_options && typeof request.workflow_options === "object"
59
+ ? { ...request.workflow_options }
60
+ : {};
61
+ if (typeof execution.model === "string" && execution.model.trim().length > 0) {
62
+ options.model = execution.model;
63
+ }
64
+ if (typeof onEvent === "function") {
65
+ options.onEvent = onEvent;
66
+ }
67
+ return options;
68
+ }
69
+
33
70
  function toUsage(usage) {
34
71
  if (!usage || typeof usage !== "object") {
35
72
  return {
@@ -1272,6 +1309,23 @@ export class Client {
1272
1309
  const result = await this.fallbackClient.runWorkflowYaml(workflowPath, workflowInput);
1273
1310
  return assertWorkflowResultShape(normalizeWorkflowResult(result));
1274
1311
  }
1312
+
1313
+ async run(request) {
1314
+ const workflowInput = buildWorkflowInputFromExecutionRequest(request);
1315
+ const workflowOptions = buildWorkflowOptionsFromExecutionRequest(request, undefined);
1316
+ return this.runWorkflowYamlString(request.workflow_yaml, workflowInput, workflowOptions);
1317
+ }
1318
+
1319
+ async runAsync(request) {
1320
+ return this.run(request);
1321
+ }
1322
+
1323
+ // Workflow-streaming surface (completion streaming already uses `stream`).
1324
+ async streamWorkflow(request, onEvent) {
1325
+ const workflowInput = buildWorkflowInputFromExecutionRequest(request);
1326
+ const workflowOptions = buildWorkflowOptionsFromExecutionRequest(request, onEvent);
1327
+ return this.runWorkflowYamlString(request.workflow_yaml, workflowInput, workflowOptions);
1328
+ }
1275
1329
  }
1276
1330
 
1277
1331
  export async function hasRustBackend() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "simple-agents-wasm",
3
- "version": "0.2.36",
3
+ "version": "0.3.2",
4
4
  "description": "Browser-compatible SimpleAgents client for OpenAI-compatible providers",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -16,12 +16,26 @@
16
16
  "files": [
17
17
  "index.js",
18
18
  "index.d.ts",
19
+ "workflow_stream_printer.mjs",
20
+ "workflow_stream_printer.d.ts",
19
21
  "runtime",
20
22
  "README.md",
21
23
  "pkg",
22
24
  "rust/Cargo.toml",
23
25
  "rust/src"
24
26
  ],
27
+ "exports": {
28
+ ".": {
29
+ "types": "./index.d.ts",
30
+ "import": "./index.js",
31
+ "default": "./index.js"
32
+ },
33
+ "./workflow_stream_printer": {
34
+ "types": "./workflow_stream_printer.d.ts",
35
+ "import": "./workflow_stream_printer.mjs",
36
+ "default": "./workflow_stream_printer.mjs"
37
+ }
38
+ },
25
39
  "engines": {
26
40
  "node": ">=18"
27
41
  },
Binary file
package/rust/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "simple-agents-wasm-rust"
3
- version = "0.2.36"
3
+ version = "0.3.2"
4
4
  edition = "2021"
5
5
  license = "MIT OR Apache-2.0"
6
6
 
@@ -0,0 +1,12 @@
1
+ export interface WorkflowStreamPrinterOptions {
2
+ /** When true, print thinking vs output deltas instead of merged `node_stream_delta`. */
3
+ splitThinking?: boolean;
4
+ }
5
+
6
+ /**
7
+ * Build a default `onEvent` callback for {@link Client.streamWorkflow} (Node-friendly streaming;
8
+ * in browsers without `process.stdout`, falls back to `console.log` per chunk).
9
+ */
10
+ export function createWorkflowStreamPrinter(
11
+ options?: WorkflowStreamPrinterOptions,
12
+ ): (event: Record<string, unknown>) => void;
@@ -0,0 +1,87 @@
1
+ /**
2
+ * @typedef {Object} WorkflowStreamPrinterOptions
3
+ * @property {boolean} [splitThinking] When true, print `node_stream_thinking_delta` and
4
+ * `node_stream_output_delta`; otherwise print `node_stream_delta`.
5
+ */
6
+
7
+ /**
8
+ * Default `onEvent` handler for {@link Client.streamWorkflow} that prints stream tokens to stdout.
9
+ * @param {WorkflowStreamPrinterOptions} [options]
10
+ * @returns {(event: Record<string, unknown>) => void}
11
+ */
12
+ function writeChunk(chunk) {
13
+ if (typeof process !== "undefined" && process.stdout?.write) {
14
+ process.stdout.write(chunk);
15
+ } else if (typeof chunk === "string" && chunk.length > 0) {
16
+ console.log(chunk);
17
+ }
18
+ }
19
+
20
+ function writeLine() {
21
+ if (typeof process !== "undefined" && process.stdout?.write) {
22
+ process.stdout.write("\n");
23
+ } else {
24
+ console.log();
25
+ }
26
+ }
27
+
28
+ export function createWorkflowStreamPrinter(options = {}) {
29
+ const splitThinking = options.splitThinking === true;
30
+ /** @type {{ currentNode: string | null, lineOpen: boolean, lastTokenLabel: string | null }} */
31
+ const state = { currentNode: null, lineOpen: false, lastTokenLabel: null };
32
+
33
+ return (event) => {
34
+ const eventType = event?.event_type;
35
+ if (typeof eventType !== "string") return;
36
+
37
+ let isStream = eventType === "node_stream_delta";
38
+ if (splitThinking) {
39
+ isStream =
40
+ eventType === "node_stream_thinking_delta" ||
41
+ eventType === "node_stream_output_delta";
42
+ }
43
+
44
+ const delta = typeof event.delta === "string" ? event.delta : "";
45
+ if (isStream && delta !== "") {
46
+ let displayId =
47
+ typeof event.node_id === "string"
48
+ ? event.node_id
49
+ : typeof event.step_id === "string"
50
+ ? event.step_id
51
+ : "?";
52
+
53
+ if (state.currentNode !== displayId) {
54
+ if (state.lineOpen) writeLine();
55
+ writeChunk(`\nStep: ${displayId}\nStreaming: `);
56
+ state.currentNode = displayId;
57
+ state.lineOpen = true;
58
+ state.lastTokenLabel = null;
59
+ }
60
+
61
+ if (splitThinking) {
62
+ const parts = [];
63
+ if (typeof event.token_kind === "string" && event.token_kind.trim()) {
64
+ parts.push(event.token_kind.trim());
65
+ }
66
+ if (event.is_terminal_node_token === true) {
67
+ parts.push("terminal");
68
+ }
69
+ const tokenLabel = parts.length ? `[${parts.join(" ")}] ` : "";
70
+ if (tokenLabel && tokenLabel !== state.lastTokenLabel) {
71
+ if (state.lineOpen) writeLine();
72
+ writeChunk(`${tokenLabel}${displayId}: `);
73
+ state.lastTokenLabel = tokenLabel;
74
+ state.lineOpen = true;
75
+ }
76
+ writeChunk(delta);
77
+ } else {
78
+ writeChunk(delta);
79
+ }
80
+ return;
81
+ }
82
+
83
+ if (eventType === "workflow_started" || eventType === "workflow_completed") {
84
+ return;
85
+ }
86
+ };
87
+ }