cognitive-modules-cli 2.2.1 → 2.2.5

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 (95) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +21 -0
  3. package/README.md +35 -29
  4. package/dist/cli.js +513 -22
  5. package/dist/commands/add.d.ts +33 -14
  6. package/dist/commands/add.js +222 -13
  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 +1 -0
  17. package/dist/commands/run.js +37 -27
  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 +218 -0
  27. package/dist/errors/index.js +412 -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 +65 -0
  32. package/dist/modules/runner.js +293 -49
  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 +204 -0
  47. package/dist/registry/client.js +356 -0
  48. package/dist/registry/index.d.ts +4 -0
  49. package/dist/registry/index.js +4 -0
  50. package/dist/server/http.js +173 -42
  51. package/dist/types.d.ts +32 -1
  52. package/dist/types.js +4 -1
  53. package/dist/version.d.ts +1 -0
  54. package/dist/version.js +4 -0
  55. package/package.json +31 -7
  56. package/dist/modules/composition.test.d.ts +0 -11
  57. package/dist/modules/composition.test.js +0 -450
  58. package/dist/modules/policy.test.d.ts +0 -10
  59. package/dist/modules/policy.test.js +0 -369
  60. package/src/cli.ts +0 -471
  61. package/src/commands/add.ts +0 -315
  62. package/src/commands/compose.ts +0 -185
  63. package/src/commands/index.ts +0 -13
  64. package/src/commands/init.ts +0 -94
  65. package/src/commands/list.ts +0 -33
  66. package/src/commands/pipe.ts +0 -76
  67. package/src/commands/remove.ts +0 -57
  68. package/src/commands/run.ts +0 -80
  69. package/src/commands/update.ts +0 -130
  70. package/src/commands/versions.ts +0 -79
  71. package/src/index.ts +0 -90
  72. package/src/mcp/index.ts +0 -5
  73. package/src/mcp/server.ts +0 -403
  74. package/src/modules/composition.test.ts +0 -558
  75. package/src/modules/composition.ts +0 -1674
  76. package/src/modules/index.ts +0 -9
  77. package/src/modules/loader.ts +0 -508
  78. package/src/modules/policy.test.ts +0 -455
  79. package/src/modules/runner.ts +0 -1983
  80. package/src/modules/subagent.ts +0 -277
  81. package/src/modules/validator.ts +0 -700
  82. package/src/providers/anthropic.ts +0 -89
  83. package/src/providers/base.ts +0 -29
  84. package/src/providers/deepseek.ts +0 -83
  85. package/src/providers/gemini.ts +0 -117
  86. package/src/providers/index.ts +0 -78
  87. package/src/providers/minimax.ts +0 -81
  88. package/src/providers/moonshot.ts +0 -82
  89. package/src/providers/ollama.ts +0 -83
  90. package/src/providers/openai.ts +0 -84
  91. package/src/providers/qwen.ts +0 -82
  92. package/src/server/http.ts +0 -316
  93. package/src/server/index.ts +0 -6
  94. package/src/types.ts +0 -599
  95. 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 },
@@ -1193,16 +1363,19 @@ export async function* runModuleStream(module, provider, options = {}) {
1193
1363
  inputData.query = args;
1194
1364
  }
1195
1365
  }
1366
+ _invokeBeforeHooks(module.name, inputData, module);
1196
1367
  // Validate input if enabled
1197
1368
  if (validateInput && module.inputSchema && Object.keys(module.inputSchema).length > 0) {
1198
1369
  const inputErrors = validateData(inputData, module.inputSchema, 'Input');
1199
1370
  if (inputErrors.length > 0) {
1200
1371
  const errorResult = makeErrorResponse({
1201
- code: 'INVALID_INPUT',
1372
+ code: 'E1001', // INVALID_INPUT
1202
1373
  message: inputErrors.join('; '),
1203
1374
  confidence: 1.0,
1204
1375
  risk: 'none',
1376
+ suggestion: 'Check input against the module schema and fix validation errors.',
1205
1377
  });
1378
+ _invokeErrorHooks(module.name, new Error(inputErrors.join('; ')), null);
1206
1379
  const errorObj = errorResult.error;
1207
1380
  yield makeEvent('error', { error: errorObj });
1208
1381
  yield makeEvent('complete', { result: errorResult });
@@ -1229,26 +1402,49 @@ export async function* runModuleStream(module, provider, options = {}) {
1229
1402
  { role: 'system', content: systemParts.join('\n') },
1230
1403
  { role: 'user', content: prompt },
1231
1404
  ];
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 });
1405
+ // Invoke provider with streaming if supported
1406
+ let fullContent;
1407
+ if (provider.supportsStreaming?.() && provider.invokeStream) {
1408
+ // Use true streaming
1409
+ const stream = provider.invokeStream({
1410
+ messages,
1411
+ jsonSchema: module.outputSchema,
1412
+ temperature: 0.3,
1413
+ });
1414
+ // Iterate through the async generator, yielding chunks as they arrive
1415
+ let streamResult;
1416
+ while (!(streamResult = await stream.next()).done) {
1417
+ const chunk = streamResult.value;
1418
+ yield makeEvent('chunk', { chunk });
1419
+ }
1420
+ // Get the final result (returned from the generator)
1421
+ fullContent = streamResult.value.content;
1422
+ }
1423
+ else {
1424
+ // Fallback to non-streaming invoke
1425
+ const result = await provider.invoke({
1426
+ messages,
1427
+ jsonSchema: module.outputSchema,
1428
+ temperature: 0.3,
1429
+ });
1430
+ fullContent = result.content;
1431
+ // Emit chunk event with full response
1432
+ yield makeEvent('chunk', { chunk: result.content });
1433
+ }
1240
1434
  // Parse response
1241
1435
  let parsed;
1242
1436
  try {
1243
- const jsonMatch = result.content.match(/```(?:json)?\s*([\s\S]*?)\s*```/);
1244
- const jsonStr = jsonMatch ? jsonMatch[1] : result.content;
1437
+ const jsonMatch = fullContent.match(/```(?:json)?\s*([\s\S]*?)\s*```/);
1438
+ const jsonStr = jsonMatch ? jsonMatch[1] : fullContent;
1245
1439
  parsed = JSON.parse(jsonStr.trim());
1246
1440
  }
1247
1441
  catch (e) {
1248
1442
  const errorResult = makeErrorResponse({
1249
- code: 'PARSE_ERROR',
1443
+ code: 'E1000', // PARSE_ERROR
1250
1444
  message: `Failed to parse JSON: ${e.message}`,
1445
+ suggestion: 'The LLM response was not valid JSON. Try again or adjust the prompt.',
1251
1446
  });
1447
+ _invokeErrorHooks(module.name, e, null);
1252
1448
  // errorResult is always an error response from makeErrorResponse
1253
1449
  const errorObj = errorResult.error;
1254
1450
  yield makeEvent('error', { error: errorObj });
@@ -1285,23 +1481,55 @@ export async function* runModuleStream(module, provider, options = {}) {
1285
1481
  const dataSchema = module.dataSchema || module.outputSchema;
1286
1482
  const metaSchema = module.metaSchema;
1287
1483
  if (dataSchema && Object.keys(dataSchema).length > 0) {
1288
- const dataToValidate = response.data ?? {};
1484
+ let dataToValidate = response.data ?? {};
1289
1485
  let dataErrors = validateData(dataToValidate, dataSchema, 'Data');
1290
1486
  if (dataErrors.length > 0 && enableRepair) {
1291
1487
  response = repairEnvelope(response, riskRule);
1292
1488
  response.version = ENVELOPE_VERSION;
1293
1489
  // Re-validate after repair
1294
1490
  const repairedData = response.data ?? {};
1491
+ dataToValidate = repairedData;
1295
1492
  dataErrors = validateData(repairedData, dataSchema, 'Data');
1296
1493
  }
1297
1494
  if (dataErrors.length > 0) {
1298
1495
  const errorResult = makeErrorResponse({
1299
- code: 'SCHEMA_VALIDATION_FAILED',
1496
+ code: 'E3001', // OUTPUT_SCHEMA_VIOLATION
1300
1497
  message: dataErrors.join('; '),
1301
1498
  explain: 'Schema validation failed after repair attempt.',
1302
1499
  partialData: response.data,
1303
1500
  details: { validation_errors: dataErrors },
1304
1501
  });
1502
+ _invokeErrorHooks(module.name, new Error(dataErrors.join('; ')), response.data);
1503
+ const errorObj = errorResult.error;
1504
+ yield makeEvent('error', { error: errorObj });
1505
+ yield makeEvent('complete', { result: errorResult });
1506
+ return;
1507
+ }
1508
+ const overflowErrors = validateOverflowLimits(dataToValidate, module);
1509
+ if (overflowErrors.length > 0) {
1510
+ const errorResult = makeErrorResponse({
1511
+ code: 'E3001', // OUTPUT_SCHEMA_VIOLATION
1512
+ message: overflowErrors.join('; '),
1513
+ explain: 'Overflow validation failed.',
1514
+ partialData: dataToValidate,
1515
+ details: { overflow_errors: overflowErrors },
1516
+ });
1517
+ _invokeErrorHooks(module.name, new Error(overflowErrors.join('; ')), dataToValidate);
1518
+ const errorObj = errorResult.error;
1519
+ yield makeEvent('error', { error: errorObj });
1520
+ yield makeEvent('complete', { result: errorResult });
1521
+ return;
1522
+ }
1523
+ const enumErrors = validateEnumStrategy(dataToValidate, module);
1524
+ if (enumErrors.length > 0) {
1525
+ const errorResult = makeErrorResponse({
1526
+ code: 'E3001', // OUTPUT_SCHEMA_VIOLATION
1527
+ message: enumErrors.join('; '),
1528
+ explain: 'Enum strategy validation failed.',
1529
+ partialData: dataToValidate,
1530
+ details: { enum_errors: enumErrors },
1531
+ });
1532
+ _invokeErrorHooks(module.name, new Error(enumErrors.join('; ')), dataToValidate);
1305
1533
  const errorObj = errorResult.error;
1306
1534
  yield makeEvent('error', { error: errorObj });
1307
1535
  yield makeEvent('complete', { result: errorResult });
@@ -1317,12 +1545,13 @@ export async function* runModuleStream(module, provider, options = {}) {
1317
1545
  metaErrors = validateData(response.meta ?? {}, metaSchema, 'Meta');
1318
1546
  if (metaErrors.length > 0) {
1319
1547
  const errorResult = makeErrorResponse({
1320
- code: 'META_VALIDATION_FAILED',
1548
+ code: 'E3001', // META_VALIDATION_FAILED (maps to OUTPUT_SCHEMA_VIOLATION)
1321
1549
  message: metaErrors.join('; '),
1322
1550
  explain: 'Meta validation failed after repair attempt.',
1323
1551
  partialData: response.data,
1324
1552
  details: { validation_errors: metaErrors },
1325
1553
  });
1554
+ _invokeErrorHooks(module.name, new Error(metaErrors.join('; ')), response.data);
1326
1555
  const errorObj = errorResult.error;
1327
1556
  yield makeEvent('error', { error: errorObj });
1328
1557
  yield makeEvent('complete', { result: errorResult });
@@ -1335,12 +1564,15 @@ export async function* runModuleStream(module, provider, options = {}) {
1335
1564
  response = repairErrorEnvelope(response);
1336
1565
  response.version = ENVELOPE_VERSION;
1337
1566
  }
1567
+ const finalLatencyMs = Date.now() - startTime;
1568
+ _invokeAfterHooks(module.name, response, finalLatencyMs);
1338
1569
  // Emit complete event
1339
1570
  yield makeEvent('complete', { result: response });
1340
1571
  }
1341
1572
  catch (e) {
1573
+ _invokeErrorHooks(module.name, e, null);
1342
1574
  const errorResult = makeErrorResponse({
1343
- code: 'UNKNOWN',
1575
+ code: 'E4000', // INTERNAL_ERROR
1344
1576
  message: e.message,
1345
1577
  explain: `Unexpected error: ${e.name}`,
1346
1578
  });
@@ -1413,6 +1645,18 @@ function parseEnvelopeResponse(response, raw) {
1413
1645
  * Parse legacy (non-envelope) format response
1414
1646
  */
1415
1647
  function parseLegacyResponse(output, raw) {
1648
+ const isPlainObject = typeof output === 'object' && output !== null && !Array.isArray(output);
1649
+ if (!isPlainObject) {
1650
+ return {
1651
+ ok: true,
1652
+ data: {
1653
+ result: output,
1654
+ confidence: 0.5,
1655
+ rationale: '',
1656
+ },
1657
+ raw,
1658
+ };
1659
+ }
1416
1660
  const outputObj = output;
1417
1661
  const confidence = typeof outputObj.confidence === 'number' ? outputObj.confidence : 0.5;
1418
1662
  const rationale = typeof outputObj.rationale === 'string' ? outputObj.rationale : '';
@@ -1522,7 +1766,7 @@ export async function runModuleLegacy(module, provider, input, options = {}) {
1522
1766
  return result.data;
1523
1767
  }
1524
1768
  else {
1525
- const error = 'error' in result ? result.error : { code: 'UNKNOWN', message: 'Unknown error' };
1769
+ const error = 'error' in result ? result.error : { code: 'E4000', message: 'Unknown error' }; // INTERNAL_ERROR fallback
1526
1770
  throw new Error(`${error?.code ?? 'UNKNOWN'}: ${error?.message ?? 'Unknown error'}`);
1527
1771
  }
1528
1772
  }
@@ -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;