@compilr-dev/sdk 0.10.34 → 0.10.36

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.
@@ -489,6 +489,8 @@ function buildCompactSchema(tool) {
489
489
  * Handles common LLM mistakes when calling tools without guided decoding:
490
490
  * - Single object where array expected → wraps in array
491
491
  * - JSON string where array expected → parses it
492
+ * - JSON string where object expected → parses it (covers e.g. Gemini Flash
493
+ * stringifying complex nested objects like build_interactive_flow.flow)
492
494
  */
493
495
  function coerceArgs(schema, args) {
494
496
  const properties = schema.properties;
@@ -497,27 +499,43 @@ function coerceArgs(schema, args) {
497
499
  let changed = false;
498
500
  const coerced = { ...args };
499
501
  for (const [name, prop] of Object.entries(properties)) {
500
- if (prop.type === 'array' && name in coerced && !Array.isArray(coerced[name])) {
501
- const value = coerced[name];
502
- if (value !== null && value !== undefined) {
503
- if (typeof value === 'object') {
504
- // Single object → wrap in array
505
- coerced[name] = [value];
506
- changed = true;
507
- }
508
- else if (typeof value === 'string') {
509
- // JSON string → try parsing
510
- try {
511
- const parsed = JSON.parse(value);
512
- if (Array.isArray(parsed)) {
513
- coerced[name] = parsed;
514
- changed = true;
515
- }
516
- }
517
- catch {
518
- // Leave as-is, will fail validation
502
+ if (!(name in coerced))
503
+ continue;
504
+ const value = coerced[name];
505
+ if (value === null || value === undefined)
506
+ continue;
507
+ if (prop.type === 'array' && !Array.isArray(value)) {
508
+ if (typeof value === 'object') {
509
+ // Single object → wrap in array
510
+ coerced[name] = [value];
511
+ changed = true;
512
+ }
513
+ else if (typeof value === 'string') {
514
+ // JSON string → try parsing
515
+ try {
516
+ const parsed = JSON.parse(value);
517
+ if (Array.isArray(parsed)) {
518
+ coerced[name] = parsed;
519
+ changed = true;
519
520
  }
520
521
  }
522
+ catch {
523
+ // Leave as-is, will fail validation
524
+ }
525
+ }
526
+ }
527
+ else if (prop.type === 'object' && typeof value === 'string') {
528
+ // JSON-stringified object → try parsing. Some providers (Gemini Flash
529
+ // via OpenAI compat, etc.) ship deeply-nested object args as strings.
530
+ try {
531
+ const parsed = JSON.parse(value);
532
+ if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {
533
+ coerced[name] = parsed;
534
+ changed = true;
535
+ }
536
+ }
537
+ catch {
538
+ // Leave as-is, will fail validation
521
539
  }
522
540
  }
523
541
  }
@@ -706,29 +706,7 @@ export function createInteractiveFlowTool(handler) {
706
706
  inputSchema: INTERACTIVE_FLOW_INPUT_SCHEMA,
707
707
  execute: async (input) => {
708
708
  try {
709
- // Defensive some providers (Gemini Flash via OpenAI compat,
710
- // etc.) ship complex object arguments as JSON-stringified strings
711
- // rather than parsed objects. The agents library does the outer
712
- // parse but doesn't recurse into nested values. Parse here so the
713
- // validator sees the proper object shape. Same quirk hit by
714
- // ask_user.questions and propose_alternatives.alternatives —
715
- // fixed at the CLI display layer for those, but here it must
716
- // happen pre-validation since the validator rejects strings.
717
- let flow = input.flow;
718
- if (typeof flow === 'string') {
719
- try {
720
- flow = JSON.parse(flow);
721
- }
722
- catch {
723
- return {
724
- success: false,
725
- error: 'Interactive flow validation failed:\n' +
726
- "[INVALID_NODE_TYPE] Flow must be an object — received a string that wasn't valid JSON. " +
727
- 'Pass the flow as a parsed object, not as a JSON-stringified string.',
728
- };
729
- }
730
- }
731
- const validation = validateFlow(flow);
709
+ const validation = validateFlow(input.flow);
732
710
  if (!validation.ok) {
733
711
  const summary = validation.errors
734
712
  .map((e) => `[${e.code}]${e.nodeId ? ` (node '${e.nodeId}')` : ''} ${e.message}`)
@@ -738,11 +716,7 @@ export function createInteractiveFlowTool(handler) {
738
716
  error: `Interactive flow validation failed:\n${summary}`,
739
717
  };
740
718
  }
741
- // Validation passed flow is a well-formed Flow. Hand it to the
742
- // handler with the (possibly-parsed) value so the host gets an
743
- // object too.
744
- const normalisedInput = { flow: flow };
745
- const result = await handler(normalisedInput);
719
+ const result = await handler(input);
746
720
  if (validation.warnings.length > 0) {
747
721
  result.warnings = [...(result.warnings ?? []), ...validation.warnings];
748
722
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@compilr-dev/sdk",
3
- "version": "0.10.34",
3
+ "version": "0.10.36",
4
4
  "description": "Universal agent runtime for building AI-powered applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -13,6 +13,10 @@
13
13
  "./team/role-aliases": {
14
14
  "types": "./dist/team/role-aliases.d.ts",
15
15
  "import": "./dist/team/role-aliases.js"
16
+ },
17
+ "./flow-runner": {
18
+ "types": "./dist/flow-runner/index.d.ts",
19
+ "import": "./dist/flow-runner/index.js"
16
20
  }
17
21
  },
18
22
  "files": [