cognitive-modules-cli 2.2.1 → 2.2.7

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.
Files changed (101) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +21 -0
  3. package/README.md +35 -29
  4. package/dist/cli.js +519 -23
  5. package/dist/commands/add.d.ts +33 -14
  6. package/dist/commands/add.js +383 -16
  7. package/dist/commands/compose.js +60 -23
  8. package/dist/commands/index.d.ts +4 -0
  9. package/dist/commands/index.js +4 -0
  10. package/dist/commands/init.js +23 -1
  11. package/dist/commands/migrate.d.ts +30 -0
  12. package/dist/commands/migrate.js +650 -0
  13. package/dist/commands/pipe.d.ts +1 -0
  14. package/dist/commands/pipe.js +31 -11
  15. package/dist/commands/remove.js +33 -2
  16. package/dist/commands/run.d.ts +2 -0
  17. package/dist/commands/run.js +61 -28
  18. package/dist/commands/search.d.ts +28 -0
  19. package/dist/commands/search.js +143 -0
  20. package/dist/commands/test.d.ts +65 -0
  21. package/dist/commands/test.js +454 -0
  22. package/dist/commands/update.d.ts +1 -0
  23. package/dist/commands/update.js +106 -14
  24. package/dist/commands/validate.d.ts +36 -0
  25. package/dist/commands/validate.js +97 -0
  26. package/dist/errors/index.d.ts +225 -0
  27. package/dist/errors/index.js +420 -0
  28. package/dist/mcp/server.js +84 -79
  29. package/dist/modules/composition.js +97 -32
  30. package/dist/modules/loader.js +4 -2
  31. package/dist/modules/runner.d.ts +72 -5
  32. package/dist/modules/runner.js +306 -59
  33. package/dist/modules/subagent.d.ts +6 -1
  34. package/dist/modules/subagent.js +18 -13
  35. package/dist/modules/validator.js +14 -6
  36. package/dist/providers/anthropic.d.ts +15 -0
  37. package/dist/providers/anthropic.js +147 -5
  38. package/dist/providers/base.d.ts +11 -0
  39. package/dist/providers/base.js +18 -0
  40. package/dist/providers/gemini.d.ts +15 -0
  41. package/dist/providers/gemini.js +122 -5
  42. package/dist/providers/ollama.d.ts +15 -0
  43. package/dist/providers/ollama.js +111 -3
  44. package/dist/providers/openai.d.ts +11 -0
  45. package/dist/providers/openai.js +133 -0
  46. package/dist/registry/client.d.ts +212 -0
  47. package/dist/registry/client.js +359 -0
  48. package/dist/registry/index.d.ts +4 -0
  49. package/dist/registry/index.js +4 -0
  50. package/dist/registry/tar.d.ts +8 -0
  51. package/dist/registry/tar.js +353 -0
  52. package/dist/server/http.js +301 -45
  53. package/dist/server/index.d.ts +2 -0
  54. package/dist/server/index.js +1 -0
  55. package/dist/server/sse.d.ts +13 -0
  56. package/dist/server/sse.js +22 -0
  57. package/dist/types.d.ts +32 -1
  58. package/dist/types.js +4 -1
  59. package/dist/version.d.ts +1 -0
  60. package/dist/version.js +4 -0
  61. package/package.json +31 -7
  62. package/dist/modules/composition.test.d.ts +0 -11
  63. package/dist/modules/composition.test.js +0 -450
  64. package/dist/modules/policy.test.d.ts +0 -10
  65. package/dist/modules/policy.test.js +0 -369
  66. package/src/cli.ts +0 -471
  67. package/src/commands/add.ts +0 -315
  68. package/src/commands/compose.ts +0 -185
  69. package/src/commands/index.ts +0 -13
  70. package/src/commands/init.ts +0 -94
  71. package/src/commands/list.ts +0 -33
  72. package/src/commands/pipe.ts +0 -76
  73. package/src/commands/remove.ts +0 -57
  74. package/src/commands/run.ts +0 -80
  75. package/src/commands/update.ts +0 -130
  76. package/src/commands/versions.ts +0 -79
  77. package/src/index.ts +0 -90
  78. package/src/mcp/index.ts +0 -5
  79. package/src/mcp/server.ts +0 -403
  80. package/src/modules/composition.test.ts +0 -558
  81. package/src/modules/composition.ts +0 -1674
  82. package/src/modules/index.ts +0 -9
  83. package/src/modules/loader.ts +0 -508
  84. package/src/modules/policy.test.ts +0 -455
  85. package/src/modules/runner.ts +0 -1983
  86. package/src/modules/subagent.ts +0 -277
  87. package/src/modules/validator.ts +0 -700
  88. package/src/providers/anthropic.ts +0 -89
  89. package/src/providers/base.ts +0 -29
  90. package/src/providers/deepseek.ts +0 -83
  91. package/src/providers/gemini.ts +0 -117
  92. package/src/providers/index.ts +0 -78
  93. package/src/providers/minimax.ts +0 -81
  94. package/src/providers/moonshot.ts +0 -82
  95. package/src/providers/ollama.ts +0 -83
  96. package/src/providers/openai.ts +0 -84
  97. package/src/providers/qwen.ts +0 -82
  98. package/src/server/http.ts +0 -316
  99. package/src/server/index.ts +0 -6
  100. package/src/types.ts +0 -599
  101. package/tsconfig.json +0 -17
@@ -447,8 +447,8 @@ export function validateEnumStrategy(data, module) {
447
447
  }
448
448
  else if (typeof obj === 'object') {
449
449
  const record = obj;
450
- // Check if this is a custom enum object
451
- if ('custom' in record && 'reason' in record && Object.keys(record).length === 2) {
450
+ // Check if this is a custom enum object (any presence of 'custom' is disallowed in strict mode)
451
+ if ('custom' in record) {
452
452
  errors.push(`Custom enum not allowed in strict mode at ${path}: { custom: "${record.custom}" }`);
453
453
  return;
454
454
  }
@@ -610,11 +610,124 @@ function _invokeErrorHooks(moduleName, error, partialResult) {
610
610
  // =============================================================================
611
611
  // Error Response Builder
612
612
  // =============================================================================
613
+ /**
614
+ * Error code taxonomy following CONFORMANCE.md E1xxx-E4xxx structure.
615
+ *
616
+ * E1xxx: Input errors (caller errors, fixable by modifying input)
617
+ * E2xxx: Processing errors (module understood input but couldn't complete)
618
+ * E3xxx: Output errors (generated output doesn't meet requirements)
619
+ * E4xxx: Runtime errors (infrastructure/system-level failures)
620
+ */
621
+ /** Standard error codes with E-format (as per ERROR-CODES.md) */
622
+ export const ERROR_CODES = {
623
+ // E1xxx: Input errors
624
+ E1000: 'PARSE_ERROR',
625
+ E1001: 'INVALID_INPUT',
626
+ E1002: 'MISSING_REQUIRED_FIELD',
627
+ E1003: 'TYPE_MISMATCH',
628
+ E1004: 'UNSUPPORTED_VALUE',
629
+ E1005: 'INPUT_TOO_LARGE',
630
+ E1006: 'INVALID_REFERENCE',
631
+ // E2xxx: Processing errors
632
+ E2001: 'LOW_CONFIDENCE',
633
+ E2002: 'TIMEOUT',
634
+ E2003: 'TOKEN_LIMIT',
635
+ E2004: 'NO_ACTION_POSSIBLE',
636
+ E2005: 'SEMANTIC_CONFLICT',
637
+ E2006: 'AMBIGUOUS_INPUT',
638
+ E2007: 'INSUFFICIENT_CONTEXT',
639
+ // E3xxx: Output errors
640
+ E3001: 'OUTPUT_SCHEMA_VIOLATION',
641
+ E3002: 'PARTIAL_RESULT',
642
+ E3003: 'MISSING_RATIONALE',
643
+ E3004: 'OVERFLOW_LIMIT',
644
+ E3005: 'INVALID_ENUM',
645
+ E3006: 'CONSTRAINT_VIOLATION',
646
+ // E4xxx: Runtime errors
647
+ E4000: 'INTERNAL_ERROR',
648
+ E4001: 'PROVIDER_UNAVAILABLE',
649
+ E4002: 'RATE_LIMITED',
650
+ E4003: 'CONTEXT_OVERFLOW',
651
+ E4004: 'CIRCULAR_DEPENDENCY',
652
+ E4005: 'MAX_DEPTH_EXCEEDED',
653
+ E4006: 'MODULE_NOT_FOUND',
654
+ E4007: 'PERMISSION_DENIED',
655
+ };
656
+ /** Reverse mapping: legacy code -> E-format code */
657
+ export const LEGACY_TO_E_CODE = {
658
+ PARSE_ERROR: 'E1000',
659
+ INVALID_INPUT: 'E1001',
660
+ MISSING_REQUIRED_FIELD: 'E1002',
661
+ TYPE_MISMATCH: 'E1003',
662
+ UNSUPPORTED_VALUE: 'E1004',
663
+ INPUT_TOO_LARGE: 'E1005',
664
+ INVALID_REFERENCE: 'E1006',
665
+ LOW_CONFIDENCE: 'E2001',
666
+ TIMEOUT: 'E2002',
667
+ TOKEN_LIMIT: 'E2003',
668
+ NO_ACTION_POSSIBLE: 'E2004',
669
+ SEMANTIC_CONFLICT: 'E2005',
670
+ AMBIGUOUS_INPUT: 'E2006',
671
+ INSUFFICIENT_CONTEXT: 'E2007',
672
+ OUTPUT_SCHEMA_VIOLATION: 'E3001',
673
+ SCHEMA_VALIDATION_FAILED: 'E3001', // Alias
674
+ PARTIAL_RESULT: 'E3002',
675
+ MISSING_RATIONALE: 'E3003',
676
+ OVERFLOW_LIMIT: 'E3004',
677
+ INVALID_ENUM: 'E3005',
678
+ CONSTRAINT_VIOLATION: 'E3006',
679
+ META_VALIDATION_FAILED: 'E3001', // Alias (output validation)
680
+ INTERNAL_ERROR: 'E4000',
681
+ PROVIDER_UNAVAILABLE: 'E4001',
682
+ LLM_ERROR: 'E4001', // Alias
683
+ RATE_LIMITED: 'E4002',
684
+ CONTEXT_OVERFLOW: 'E4003',
685
+ CIRCULAR_DEPENDENCY: 'E4004',
686
+ MAX_DEPTH_EXCEEDED: 'E4005',
687
+ MODULE_NOT_FOUND: 'E4006',
688
+ PERMISSION_DENIED: 'E4007',
689
+ POLICY_VIOLATION: 'E4007', // Alias
690
+ TOOL_NOT_ALLOWED: 'E4007', // Alias
691
+ UNKNOWN: 'E4000', // Fallback to internal error
692
+ };
613
693
  /** Error codes and their default properties */
614
694
  export const ERROR_PROPERTIES = {
615
- MODULE_NOT_FOUND: { recoverable: false, retry_after_ms: null },
616
- INVALID_INPUT: { recoverable: false, retry_after_ms: null },
617
- PARSE_ERROR: { recoverable: true, retry_after_ms: 1000 },
695
+ // E1xxx: Input errors (mostly recoverable by fixing input)
696
+ E1000: { recoverable: false, retry_after_ms: null }, // PARSE_ERROR
697
+ E1001: { recoverable: true, retry_after_ms: null }, // INVALID_INPUT
698
+ E1002: { recoverable: true, retry_after_ms: null }, // MISSING_REQUIRED_FIELD
699
+ E1003: { recoverable: true, retry_after_ms: null }, // TYPE_MISMATCH
700
+ E1004: { recoverable: false, retry_after_ms: null }, // UNSUPPORTED_VALUE
701
+ E1005: { recoverable: true, retry_after_ms: null }, // INPUT_TOO_LARGE
702
+ E1006: { recoverable: true, retry_after_ms: null }, // INVALID_REFERENCE
703
+ // E2xxx: Processing errors (may have partial results)
704
+ E2001: { recoverable: true, retry_after_ms: null }, // LOW_CONFIDENCE
705
+ E2002: { recoverable: true, retry_after_ms: 5000 }, // TIMEOUT
706
+ E2003: { recoverable: true, retry_after_ms: null }, // TOKEN_LIMIT
707
+ E2004: { recoverable: false, retry_after_ms: null }, // NO_ACTION_POSSIBLE
708
+ E2005: { recoverable: false, retry_after_ms: null }, // SEMANTIC_CONFLICT
709
+ E2006: { recoverable: true, retry_after_ms: null }, // AMBIGUOUS_INPUT
710
+ E2007: { recoverable: true, retry_after_ms: null }, // INSUFFICIENT_CONTEXT
711
+ // E3xxx: Output errors (schema violations)
712
+ E3001: { recoverable: true, retry_after_ms: 1000 }, // OUTPUT_SCHEMA_VIOLATION
713
+ E3002: { recoverable: true, retry_after_ms: null }, // PARTIAL_RESULT
714
+ E3003: { recoverable: false, retry_after_ms: null }, // MISSING_RATIONALE
715
+ E3004: { recoverable: false, retry_after_ms: null }, // OVERFLOW_LIMIT
716
+ E3005: { recoverable: false, retry_after_ms: null }, // INVALID_ENUM
717
+ E3006: { recoverable: false, retry_after_ms: null }, // CONSTRAINT_VIOLATION
718
+ // E4xxx: Runtime errors (infrastructure failures)
719
+ E4000: { recoverable: false, retry_after_ms: null }, // INTERNAL_ERROR
720
+ E4001: { recoverable: true, retry_after_ms: 5000 }, // PROVIDER_UNAVAILABLE
721
+ E4002: { recoverable: true, retry_after_ms: 10000 }, // RATE_LIMITED
722
+ E4003: { recoverable: false, retry_after_ms: null }, // CONTEXT_OVERFLOW
723
+ E4004: { recoverable: false, retry_after_ms: null }, // CIRCULAR_DEPENDENCY
724
+ E4005: { recoverable: false, retry_after_ms: null }, // MAX_DEPTH_EXCEEDED
725
+ E4006: { recoverable: true, retry_after_ms: null }, // MODULE_NOT_FOUND
726
+ E4007: { recoverable: false, retry_after_ms: null }, // PERMISSION_DENIED
727
+ // Legacy codes (for backward compatibility)
728
+ MODULE_NOT_FOUND: { recoverable: true, retry_after_ms: null },
729
+ INVALID_INPUT: { recoverable: true, retry_after_ms: null },
730
+ PARSE_ERROR: { recoverable: false, retry_after_ms: null },
618
731
  SCHEMA_VALIDATION_FAILED: { recoverable: true, retry_after_ms: 1000 },
619
732
  META_VALIDATION_FAILED: { recoverable: true, retry_after_ms: 1000 },
620
733
  POLICY_VIOLATION: { recoverable: false, retry_after_ms: null },
@@ -624,15 +737,54 @@ export const ERROR_PROPERTIES = {
624
737
  TIMEOUT: { recoverable: true, retry_after_ms: 5000 },
625
738
  UNKNOWN: { recoverable: false, retry_after_ms: null },
626
739
  };
740
+ /**
741
+ * Normalize error code to E-format.
742
+ * Accepts both E-format (E1001) and legacy format (INVALID_INPUT).
743
+ *
744
+ * @param code Error code in any format
745
+ * @returns E-format code (e.g., "E1001")
746
+ */
747
+ export function normalizeErrorCode(code) {
748
+ // Already E-format
749
+ if (/^E\d{4}$/.test(code)) {
750
+ return code;
751
+ }
752
+ // Map legacy to E-format
753
+ const eCode = LEGACY_TO_E_CODE[code];
754
+ return eCode || 'E4000'; // Default to INTERNAL_ERROR
755
+ }
756
+ /**
757
+ * Get error category from E-format code.
758
+ *
759
+ * @param code E-format error code (e.g., "E1001")
760
+ * @returns Category: 'input' | 'processing' | 'output' | 'runtime'
761
+ */
762
+ export function getErrorCategory(code) {
763
+ const normalized = normalizeErrorCode(code);
764
+ const category = normalized.charAt(1);
765
+ switch (category) {
766
+ case '1': return 'input';
767
+ case '2': return 'processing';
768
+ case '3': return 'output';
769
+ case '4': return 'runtime';
770
+ default: return 'runtime';
771
+ }
772
+ }
627
773
  /**
628
774
  * Build a standardized error response with enhanced taxonomy.
775
+ * Supports both E-format (E1001) and legacy format (INVALID_INPUT) error codes.
776
+ *
777
+ * @param options Error response options
778
+ * @returns Standardized error envelope
629
779
  */
630
780
  export function makeErrorResponse(options) {
631
- const { code, message, explain, partialData, details, recoverable, retryAfterMs, confidence = 0.0, risk = 'high', } = options;
632
- // Get default properties from error code
633
- const defaults = ERROR_PROPERTIES[code] || ERROR_PROPERTIES.UNKNOWN;
781
+ const { code, message, explain, partialData, details, recoverable, retryAfterMs, confidence = 0.0, risk = 'high', suggestion, useEFormat = true, } = options;
782
+ // Normalize error code to E-format if requested
783
+ const normalizedCode = useEFormat ? normalizeErrorCode(code) : code;
784
+ // Get default properties from error code (try normalized first, then original)
785
+ const defaults = ERROR_PROPERTIES[normalizedCode] || ERROR_PROPERTIES[code] || ERROR_PROPERTIES.UNKNOWN || { recoverable: false, retry_after_ms: null };
634
786
  const errorObj = {
635
- code,
787
+ code: normalizedCode,
636
788
  message,
637
789
  };
638
790
  // Add recoverable flag
@@ -642,18 +794,31 @@ export function makeErrorResponse(options) {
642
794
  }
643
795
  // Add retry suggestion
644
796
  const retryMs = retryAfterMs ?? defaults.retry_after_ms;
645
- if (retryMs !== null) {
797
+ if (retryMs !== null && retryMs !== undefined) {
646
798
  errorObj.retry_after_ms = retryMs;
647
799
  }
800
+ // Add suggestion if provided
801
+ if (suggestion) {
802
+ errorObj.suggestion = suggestion;
803
+ }
648
804
  // Add details if provided
649
805
  if (details) {
650
806
  errorObj.details = details;
651
807
  }
808
+ // Determine confidence based on error category (if not explicitly provided)
809
+ let finalConfidence = confidence;
810
+ if (confidence === 0.0 && partialData) {
811
+ // If we have partial data, may have some confidence
812
+ const category = getErrorCategory(normalizedCode);
813
+ if (category === 'processing') {
814
+ finalConfidence = 0.3; // Some partial understanding
815
+ }
816
+ }
652
817
  return {
653
818
  ok: false,
654
819
  version: ENVELOPE_VERSION,
655
820
  meta: {
656
- confidence,
821
+ confidence: finalConfidence,
657
822
  risk,
658
823
  explain: (explain || message).slice(0, 280),
659
824
  },
@@ -722,14 +887,13 @@ function repairEnvelope(response, riskRule = 'max_changes_risk', maxExplainLengt
722
887
  if (!meta.risk) {
723
888
  meta.risk = aggregateRisk(data, riskRule);
724
889
  }
725
- // Trim whitespace only (lossless), validate is valid RiskLevel
890
+ // Trim whitespace only (lossless). Do NOT repair invalid enum values.
726
891
  if (typeof meta.risk === 'string') {
727
892
  const trimmedRisk = meta.risk.trim().toLowerCase();
728
893
  const validRisks = ['none', 'low', 'medium', 'high'];
729
- meta.risk = validRisks.includes(trimmedRisk) ? trimmedRisk : 'medium';
730
- }
731
- else {
732
- meta.risk = 'medium'; // Default for invalid type
894
+ if (validRisks.includes(trimmedRisk)) {
895
+ meta.risk = trimmedRisk;
896
+ }
733
897
  }
734
898
  // Repair explain
735
899
  if (typeof meta.explain !== 'string') {
@@ -752,7 +916,8 @@ function repairEnvelope(response, riskRule = 'max_changes_risk', maxExplainLengt
752
916
  ok: false,
753
917
  version: ENVELOPE_VERSION,
754
918
  meta: builtMeta,
755
- error: repaired.error ?? { code: 'UNKNOWN', message: 'Unknown error' },
919
+ // E4000 is an internal/runtime error fallback (should rarely happen after repair).
920
+ error: repaired.error ?? { code: 'E4000', message: 'Unknown error' },
756
921
  partial_data: repaired.partial_data
757
922
  } : {
758
923
  ok: true,
@@ -794,7 +959,8 @@ function repairErrorEnvelope(data, maxExplainLength = 280) {
794
959
  risk: meta.risk,
795
960
  explain: meta.explain,
796
961
  },
797
- error: repaired.error ?? { code: 'UNKNOWN', message: 'Unknown error' },
962
+ // E4000 is an internal/runtime error fallback (should rarely happen after repair).
963
+ error: repaired.error ?? { code: 'E4000', message: 'Unknown error' },
798
964
  partial_data: repaired.partial_data,
799
965
  };
800
966
  }
@@ -834,7 +1000,7 @@ function wrapV21ToV22(response, riskRule = 'max_changes_risk') {
834
1000
  risk: 'high',
835
1001
  explain: errorMsg.slice(0, 280)
836
1002
  },
837
- error: response.error ?? { code: 'UNKNOWN', message: errorMsg },
1003
+ error: response.error ?? { code: 'E4000', message: errorMsg }, // INTERNAL_ERROR fallback
838
1004
  partial_data: response.partial_data
839
1005
  };
840
1006
  }
@@ -843,8 +1009,10 @@ function wrapV21ToV22(response, riskRule = 'max_changes_risk') {
843
1009
  * Convert legacy format (no envelope) to v2.2 envelope.
844
1010
  */
845
1011
  function convertLegacyToEnvelope(data, isError = false) {
846
- if (isError || 'error' in data) {
847
- const error = (data.error ?? {});
1012
+ const isPlainObject = typeof data === 'object' && data !== null && !Array.isArray(data);
1013
+ const dataObj = isPlainObject ? data : { result: data };
1014
+ if (isError || (isPlainObject && 'error' in dataObj)) {
1015
+ const error = (dataObj.error ?? {});
848
1016
  const errorMsg = typeof error === 'object'
849
1017
  ? (error.message ?? String(error))
850
1018
  : String(error);
@@ -864,17 +1032,17 @@ function convertLegacyToEnvelope(data, isError = false) {
864
1032
  };
865
1033
  }
866
1034
  else {
867
- const confidence = data.confidence ?? 0.5;
868
- const rationale = data.rationale ?? '';
1035
+ const confidence = dataObj.confidence ?? 0.5;
1036
+ const rationale = dataObj.rationale ?? '';
869
1037
  return {
870
1038
  ok: true,
871
1039
  version: ENVELOPE_VERSION,
872
1040
  meta: {
873
1041
  confidence,
874
- risk: aggregateRisk(data),
1042
+ risk: aggregateRisk(dataObj),
875
1043
  explain: rationale.slice(0, 280) || 'No explanation provided',
876
1044
  },
877
- data,
1045
+ data: dataObj,
878
1046
  };
879
1047
  }
880
1048
  }
@@ -910,12 +1078,13 @@ export async function runModule(module, provider, options = {}) {
910
1078
  const inputErrors = validateData(inputData, module.inputSchema, 'Input');
911
1079
  if (inputErrors.length > 0) {
912
1080
  const errorResult = makeErrorResponse({
913
- code: 'INVALID_INPUT',
1081
+ code: 'E1001', // INVALID_INPUT
914
1082
  message: inputErrors.join('; '),
915
1083
  explain: 'Input validation failed.',
916
1084
  confidence: 1.0,
917
1085
  risk: 'none',
918
1086
  details: { validation_errors: inputErrors },
1087
+ suggestion: 'Check input against the module schema and fix validation errors.',
919
1088
  });
920
1089
  _invokeErrorHooks(module.name, new Error(inputErrors.join('; ')), null);
921
1090
  return errorResult;
@@ -1018,10 +1187,11 @@ export async function runModule(module, provider, options = {}) {
1018
1187
  }
1019
1188
  catch (e) {
1020
1189
  const errorResult = makeErrorResponse({
1021
- code: 'PARSE_ERROR',
1190
+ code: 'E1000', // PARSE_ERROR
1022
1191
  message: `Failed to parse JSON response: ${e.message}`,
1023
1192
  explain: 'Failed to parse LLM response as JSON.',
1024
1193
  details: { raw_response: result.content.substring(0, 500) },
1194
+ suggestion: 'The LLM response was not valid JSON. Try again or adjust the prompt.',
1025
1195
  });
1026
1196
  _invokeErrorHooks(module.name, e, null);
1027
1197
  return errorResult;
@@ -1066,7 +1236,7 @@ export async function runModule(module, provider, options = {}) {
1066
1236
  }
1067
1237
  if (dataErrors.length > 0) {
1068
1238
  const errorResult = makeErrorResponse({
1069
- code: 'SCHEMA_VALIDATION_FAILED',
1239
+ code: 'E3001', // OUTPUT_SCHEMA_VIOLATION
1070
1240
  message: dataErrors.join('; '),
1071
1241
  explain: 'Schema validation failed after repair attempt.',
1072
1242
  partialData: response.data,
@@ -1080,7 +1250,7 @@ export async function runModule(module, provider, options = {}) {
1080
1250
  const overflowErrors = validateOverflowLimits(dataToValidate, module);
1081
1251
  if (overflowErrors.length > 0) {
1082
1252
  const errorResult = makeErrorResponse({
1083
- code: 'SCHEMA_VALIDATION_FAILED',
1253
+ code: 'E3001', // OUTPUT_SCHEMA_VIOLATION
1084
1254
  message: overflowErrors.join('; '),
1085
1255
  explain: 'Overflow validation failed.',
1086
1256
  partialData: dataToValidate,
@@ -1093,7 +1263,7 @@ export async function runModule(module, provider, options = {}) {
1093
1263
  const enumErrors = validateEnumStrategy(dataToValidate, module);
1094
1264
  if (enumErrors.length > 0) {
1095
1265
  const errorResult = makeErrorResponse({
1096
- code: 'SCHEMA_VALIDATION_FAILED',
1266
+ code: 'E3001', // OUTPUT_SCHEMA_VIOLATION
1097
1267
  message: enumErrors.join('; '),
1098
1268
  explain: 'Enum strategy validation failed.',
1099
1269
  partialData: dataToValidate,
@@ -1112,7 +1282,7 @@ export async function runModule(module, provider, options = {}) {
1112
1282
  metaErrors = validateData(response.meta ?? {}, metaSchema, 'Meta');
1113
1283
  if (metaErrors.length > 0) {
1114
1284
  const errorResult = makeErrorResponse({
1115
- code: 'META_VALIDATION_FAILED',
1285
+ code: 'E3001', // META_VALIDATION_FAILED (maps to OUTPUT_SCHEMA_VIOLATION)
1116
1286
  message: metaErrors.join('; '),
1117
1287
  explain: 'Meta schema validation failed after repair attempt.',
1118
1288
  partialData: response.data,
@@ -1137,7 +1307,7 @@ export async function runModule(module, provider, options = {}) {
1137
1307
  catch (e) {
1138
1308
  const latencyMs = Date.now() - startTime;
1139
1309
  const errorResult = makeErrorResponse({
1140
- code: 'UNKNOWN',
1310
+ code: 'E4000', // INTERNAL_ERROR
1141
1311
  message: e.message,
1142
1312
  explain: `Unexpected error: ${e.name}`,
1143
1313
  details: { exception_type: e.name },
@@ -1154,9 +1324,9 @@ export async function runModule(module, provider, options = {}) {
1154
1324
  *
1155
1325
  * Yields StreamEvent objects as the module executes:
1156
1326
  * - type="start": Module execution started
1157
- * - type="chunk": Incremental data chunk (if LLM supports streaming)
1327
+ * - type="delta": Incremental output delta (provider streaming chunk)
1158
1328
  * - type="meta": Meta information available early
1159
- * - type="complete": Final complete result
1329
+ * - type="end": Final result envelope (always emitted)
1160
1330
  * - type="error": Error occurred
1161
1331
  *
1162
1332
  * @example
@@ -1172,11 +1342,14 @@ export async function* runModuleStream(module, provider, options = {}) {
1172
1342
  const { input, args, validateInput = true, validateOutput = true, useV22 = true, enableRepair = true, traceId, model } = options;
1173
1343
  const startTime = Date.now();
1174
1344
  const moduleName = module.name;
1345
+ const providerName = provider?.name;
1175
1346
  function makeEvent(type, extra = {}) {
1176
1347
  return {
1177
1348
  type,
1349
+ version: ENVELOPE_VERSION,
1178
1350
  timestamp_ms: Date.now() - startTime,
1179
- module_name: moduleName,
1351
+ module: moduleName,
1352
+ ...(providerName ? { provider: providerName } : {}),
1180
1353
  ...extra,
1181
1354
  };
1182
1355
  }
@@ -1193,19 +1366,22 @@ export async function* runModuleStream(module, provider, options = {}) {
1193
1366
  inputData.query = args;
1194
1367
  }
1195
1368
  }
1369
+ _invokeBeforeHooks(module.name, inputData, module);
1196
1370
  // Validate input if enabled
1197
1371
  if (validateInput && module.inputSchema && Object.keys(module.inputSchema).length > 0) {
1198
1372
  const inputErrors = validateData(inputData, module.inputSchema, 'Input');
1199
1373
  if (inputErrors.length > 0) {
1200
1374
  const errorResult = makeErrorResponse({
1201
- code: 'INVALID_INPUT',
1375
+ code: 'E1001', // INVALID_INPUT
1202
1376
  message: inputErrors.join('; '),
1203
1377
  confidence: 1.0,
1204
1378
  risk: 'none',
1379
+ suggestion: 'Check input against the module schema and fix validation errors.',
1205
1380
  });
1381
+ _invokeErrorHooks(module.name, new Error(inputErrors.join('; ')), null);
1206
1382
  const errorObj = errorResult.error;
1207
1383
  yield makeEvent('error', { error: errorObj });
1208
- yield makeEvent('complete', { result: errorResult });
1384
+ yield makeEvent('end', { result: errorResult });
1209
1385
  return;
1210
1386
  }
1211
1387
  }
@@ -1229,30 +1405,53 @@ export async function* runModuleStream(module, provider, options = {}) {
1229
1405
  { role: 'system', content: systemParts.join('\n') },
1230
1406
  { role: 'user', content: prompt },
1231
1407
  ];
1232
- // Invoke provider (streaming not yet supported in provider interface, so we fallback)
1233
- const result = await provider.invoke({
1234
- messages,
1235
- jsonSchema: module.outputSchema,
1236
- temperature: 0.3,
1237
- });
1238
- // Emit chunk event with full response
1239
- yield makeEvent('chunk', { chunk: result.content });
1408
+ // Invoke provider with streaming if supported
1409
+ let fullContent;
1410
+ if (provider.supportsStreaming?.() && provider.invokeStream) {
1411
+ // Use true streaming
1412
+ const stream = provider.invokeStream({
1413
+ messages,
1414
+ jsonSchema: module.outputSchema,
1415
+ temperature: 0.3,
1416
+ });
1417
+ // Iterate through the async generator, yielding chunks as they arrive
1418
+ let streamResult;
1419
+ while (!(streamResult = await stream.next()).done) {
1420
+ const chunk = streamResult.value;
1421
+ yield makeEvent('delta', { delta: chunk });
1422
+ }
1423
+ // Get the final result (returned from the generator)
1424
+ fullContent = streamResult.value.content;
1425
+ }
1426
+ else {
1427
+ // Fallback to non-streaming invoke
1428
+ const result = await provider.invoke({
1429
+ messages,
1430
+ jsonSchema: module.outputSchema,
1431
+ temperature: 0.3,
1432
+ });
1433
+ fullContent = result.content;
1434
+ // Emit chunk event with full response
1435
+ yield makeEvent('delta', { delta: result.content });
1436
+ }
1240
1437
  // Parse response
1241
1438
  let parsed;
1242
1439
  try {
1243
- const jsonMatch = result.content.match(/```(?:json)?\s*([\s\S]*?)\s*```/);
1244
- const jsonStr = jsonMatch ? jsonMatch[1] : result.content;
1440
+ const jsonMatch = fullContent.match(/```(?:json)?\s*([\s\S]*?)\s*```/);
1441
+ const jsonStr = jsonMatch ? jsonMatch[1] : fullContent;
1245
1442
  parsed = JSON.parse(jsonStr.trim());
1246
1443
  }
1247
1444
  catch (e) {
1248
1445
  const errorResult = makeErrorResponse({
1249
- code: 'PARSE_ERROR',
1446
+ code: 'E1000', // PARSE_ERROR
1250
1447
  message: `Failed to parse JSON: ${e.message}`,
1448
+ suggestion: 'The LLM response was not valid JSON. Try again or adjust the prompt.',
1251
1449
  });
1450
+ _invokeErrorHooks(module.name, e, null);
1252
1451
  // errorResult is always an error response from makeErrorResponse
1253
1452
  const errorObj = errorResult.error;
1254
1453
  yield makeEvent('error', { error: errorObj });
1255
- yield makeEvent('complete', { result: errorResult });
1454
+ yield makeEvent('end', { result: errorResult });
1256
1455
  return;
1257
1456
  }
1258
1457
  // Convert to v2.2 envelope
@@ -1285,26 +1484,58 @@ export async function* runModuleStream(module, provider, options = {}) {
1285
1484
  const dataSchema = module.dataSchema || module.outputSchema;
1286
1485
  const metaSchema = module.metaSchema;
1287
1486
  if (dataSchema && Object.keys(dataSchema).length > 0) {
1288
- const dataToValidate = response.data ?? {};
1487
+ let dataToValidate = response.data ?? {};
1289
1488
  let dataErrors = validateData(dataToValidate, dataSchema, 'Data');
1290
1489
  if (dataErrors.length > 0 && enableRepair) {
1291
1490
  response = repairEnvelope(response, riskRule);
1292
1491
  response.version = ENVELOPE_VERSION;
1293
1492
  // Re-validate after repair
1294
1493
  const repairedData = response.data ?? {};
1494
+ dataToValidate = repairedData;
1295
1495
  dataErrors = validateData(repairedData, dataSchema, 'Data');
1296
1496
  }
1297
1497
  if (dataErrors.length > 0) {
1298
1498
  const errorResult = makeErrorResponse({
1299
- code: 'SCHEMA_VALIDATION_FAILED',
1499
+ code: 'E3001', // OUTPUT_SCHEMA_VIOLATION
1300
1500
  message: dataErrors.join('; '),
1301
1501
  explain: 'Schema validation failed after repair attempt.',
1302
1502
  partialData: response.data,
1303
1503
  details: { validation_errors: dataErrors },
1304
1504
  });
1505
+ _invokeErrorHooks(module.name, new Error(dataErrors.join('; ')), response.data);
1506
+ const errorObj = errorResult.error;
1507
+ yield makeEvent('error', { error: errorObj });
1508
+ yield makeEvent('end', { result: errorResult });
1509
+ return;
1510
+ }
1511
+ const overflowErrors = validateOverflowLimits(dataToValidate, module);
1512
+ if (overflowErrors.length > 0) {
1513
+ const errorResult = makeErrorResponse({
1514
+ code: 'E3001', // OUTPUT_SCHEMA_VIOLATION
1515
+ message: overflowErrors.join('; '),
1516
+ explain: 'Overflow validation failed.',
1517
+ partialData: dataToValidate,
1518
+ details: { overflow_errors: overflowErrors },
1519
+ });
1520
+ _invokeErrorHooks(module.name, new Error(overflowErrors.join('; ')), dataToValidate);
1305
1521
  const errorObj = errorResult.error;
1306
1522
  yield makeEvent('error', { error: errorObj });
1307
- yield makeEvent('complete', { result: errorResult });
1523
+ yield makeEvent('end', { result: errorResult });
1524
+ return;
1525
+ }
1526
+ const enumErrors = validateEnumStrategy(dataToValidate, module);
1527
+ if (enumErrors.length > 0) {
1528
+ const errorResult = makeErrorResponse({
1529
+ code: 'E3001', // OUTPUT_SCHEMA_VIOLATION
1530
+ message: enumErrors.join('; '),
1531
+ explain: 'Enum strategy validation failed.',
1532
+ partialData: dataToValidate,
1533
+ details: { enum_errors: enumErrors },
1534
+ });
1535
+ _invokeErrorHooks(module.name, new Error(enumErrors.join('; ')), dataToValidate);
1536
+ const errorObj = errorResult.error;
1537
+ yield makeEvent('error', { error: errorObj });
1538
+ yield makeEvent('end', { result: errorResult });
1308
1539
  return;
1309
1540
  }
1310
1541
  }
@@ -1317,15 +1548,16 @@ export async function* runModuleStream(module, provider, options = {}) {
1317
1548
  metaErrors = validateData(response.meta ?? {}, metaSchema, 'Meta');
1318
1549
  if (metaErrors.length > 0) {
1319
1550
  const errorResult = makeErrorResponse({
1320
- code: 'META_VALIDATION_FAILED',
1551
+ code: 'E3001', // META_VALIDATION_FAILED (maps to OUTPUT_SCHEMA_VIOLATION)
1321
1552
  message: metaErrors.join('; '),
1322
1553
  explain: 'Meta validation failed after repair attempt.',
1323
1554
  partialData: response.data,
1324
1555
  details: { validation_errors: metaErrors },
1325
1556
  });
1557
+ _invokeErrorHooks(module.name, new Error(metaErrors.join('; ')), response.data);
1326
1558
  const errorObj = errorResult.error;
1327
1559
  yield makeEvent('error', { error: errorObj });
1328
- yield makeEvent('complete', { result: errorResult });
1560
+ yield makeEvent('end', { result: errorResult });
1329
1561
  return;
1330
1562
  }
1331
1563
  }
@@ -1335,19 +1567,22 @@ export async function* runModuleStream(module, provider, options = {}) {
1335
1567
  response = repairErrorEnvelope(response);
1336
1568
  response.version = ENVELOPE_VERSION;
1337
1569
  }
1338
- // Emit complete event
1339
- yield makeEvent('complete', { result: response });
1570
+ const finalLatencyMs = Date.now() - startTime;
1571
+ _invokeAfterHooks(module.name, response, finalLatencyMs);
1572
+ // Emit end event
1573
+ yield makeEvent('end', { result: response });
1340
1574
  }
1341
1575
  catch (e) {
1576
+ _invokeErrorHooks(module.name, e, null);
1342
1577
  const errorResult = makeErrorResponse({
1343
- code: 'UNKNOWN',
1578
+ code: 'E4000', // INTERNAL_ERROR
1344
1579
  message: e.message,
1345
1580
  explain: `Unexpected error: ${e.name}`,
1346
1581
  });
1347
1582
  // errorResult is always an error response from makeErrorResponse
1348
1583
  const errorObj = errorResult.error;
1349
1584
  yield makeEvent('error', { error: errorObj });
1350
- yield makeEvent('complete', { result: errorResult });
1585
+ yield makeEvent('end', { result: errorResult });
1351
1586
  }
1352
1587
  }
1353
1588
  // =============================================================================
@@ -1413,6 +1648,18 @@ function parseEnvelopeResponse(response, raw) {
1413
1648
  * Parse legacy (non-envelope) format response
1414
1649
  */
1415
1650
  function parseLegacyResponse(output, raw) {
1651
+ const isPlainObject = typeof output === 'object' && output !== null && !Array.isArray(output);
1652
+ if (!isPlainObject) {
1653
+ return {
1654
+ ok: true,
1655
+ data: {
1656
+ result: output,
1657
+ confidence: 0.5,
1658
+ rationale: '',
1659
+ },
1660
+ raw,
1661
+ };
1662
+ }
1416
1663
  const outputObj = output;
1417
1664
  const confidence = typeof outputObj.confidence === 'number' ? outputObj.confidence : 0.5;
1418
1665
  const rationale = typeof outputObj.rationale === 'string' ? outputObj.rationale : '';
@@ -1522,7 +1769,7 @@ export async function runModuleLegacy(module, provider, input, options = {}) {
1522
1769
  return result.data;
1523
1770
  }
1524
1771
  else {
1525
- const error = 'error' in result ? result.error : { code: 'UNKNOWN', message: 'Unknown error' };
1772
+ const error = 'error' in result ? result.error : { code: 'E4000', message: 'Unknown error' }; // INTERNAL_ERROR fallback
1526
1773
  throw new Error(`${error?.code ?? 'UNKNOWN'}: ${error?.message ?? 'Unknown error'}`);
1527
1774
  }
1528
1775
  }
@@ -22,6 +22,7 @@ export interface CallDirective {
22
22
  }
23
23
  export interface SubagentRunOptions {
24
24
  input?: ModuleInput;
25
+ args?: string;
25
26
  validateInput?: boolean;
26
27
  validateOutput?: boolean;
27
28
  maxDepth?: number;
@@ -45,7 +46,11 @@ export declare function parseCalls(text: string): CallDirective[];
45
46
  /**
46
47
  * Replace @call directives with their results
47
48
  */
48
- export declare function substituteCallResults(text: string, callResults: Record<string, unknown>): string;
49
+ export declare function substituteCallResults(text: string, callResults: Array<{
50
+ match: string;
51
+ module: string;
52
+ result: unknown;
53
+ }>): string;
49
54
  export declare class SubagentOrchestrator {
50
55
  private provider;
51
56
  private running;