cognitive-runtime 0.4.0 → 0.5.0

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/README.md CHANGED
@@ -65,6 +65,45 @@ echo "review this code" | cog pipe --module code-reviewer
65
65
  cog doctor
66
66
  ```
67
67
 
68
+ ## Module Formats
69
+
70
+ ### v2 (Recommended)
71
+
72
+ ```
73
+ my-module/
74
+ ├── module.yaml # Machine-readable manifest
75
+ ├── prompt.md # Human-readable prompt
76
+ ├── schema.json # IO contract
77
+ └── tests/
78
+ ├── case1.input.json
79
+ └── case1.expected.json
80
+ ```
81
+
82
+ **module.yaml**:
83
+ ```yaml
84
+ name: my-module
85
+ version: 2.0.0
86
+ responsibility: What this module does
87
+ constraints:
88
+ no_network: true
89
+ no_side_effects: true
90
+ output:
91
+ mode: json_strict
92
+ require_confidence: true
93
+ require_rationale: true
94
+ require_behavior_equivalence: true
95
+ tools:
96
+ allowed: []
97
+ ```
98
+
99
+ ### v1 (Legacy, still supported)
100
+
101
+ ```
102
+ my-module/
103
+ ├── MODULE.md # Frontmatter + prompt combined
104
+ └── schema.json
105
+ ```
106
+
68
107
  ## Providers
69
108
 
70
109
  | Provider | Environment Variable | Default Model |
package/dist/cli.js CHANGED
@@ -10,7 +10,7 @@
10
10
  import { parseArgs } from 'node:util';
11
11
  import { getProvider, listProviders } from './providers/index.js';
12
12
  import { run, list, pipe, init } from './commands/index.js';
13
- const VERSION = '0.4.0';
13
+ const VERSION = '0.5.0';
14
14
  async function main() {
15
15
  const args = process.argv.slice(2);
16
16
  const command = args[0];
@@ -37,16 +37,20 @@ export async function pipe(ctx, options) {
37
37
  args: inputData ? undefined : input,
38
38
  input: inputData,
39
39
  });
40
- // Output JSON to stdout
41
- console.log(JSON.stringify(result.output));
40
+ // Output envelope format to stdout
41
+ console.log(JSON.stringify(result));
42
42
  return {
43
- success: true,
43
+ success: result.ok,
44
44
  data: result,
45
45
  };
46
46
  }
47
47
  catch (e) {
48
48
  const error = e instanceof Error ? e.message : String(e);
49
- console.error(JSON.stringify({ error }));
49
+ // Output error in envelope format
50
+ console.log(JSON.stringify({
51
+ ok: false,
52
+ error: { code: 'RUNTIME_ERROR', message: error }
53
+ }));
50
54
  return {
51
55
  success: false,
52
56
  error,
@@ -32,10 +32,29 @@ export async function run(moduleName, ctx, options = {}) {
32
32
  input: inputData,
33
33
  verbose: options.verbose || ctx.verbose,
34
34
  });
35
- return {
36
- success: true,
37
- data: options.pretty ? result : result.output,
38
- };
35
+ // Return envelope format or extracted data
36
+ if (options.pretty) {
37
+ return {
38
+ success: result.ok,
39
+ data: result,
40
+ };
41
+ }
42
+ else {
43
+ // For non-pretty mode, return data (success) or error (failure)
44
+ if (result.ok) {
45
+ return {
46
+ success: true,
47
+ data: result.data,
48
+ };
49
+ }
50
+ else {
51
+ return {
52
+ success: false,
53
+ error: `${result.error?.code}: ${result.error?.message}`,
54
+ data: result.partial_data,
55
+ };
56
+ }
57
+ }
39
58
  }
40
59
  catch (e) {
41
60
  return {
@@ -57,9 +57,11 @@ async function loadModuleV2(modulePath) {
57
57
  responsibility: manifest.responsibility || '',
58
58
  excludes: manifest.excludes || [],
59
59
  constraints: manifest.constraints,
60
+ policies: manifest.policies,
60
61
  tools: manifest.tools,
61
62
  output: manifest.output,
62
63
  failure: manifest.failure,
64
+ runtimeRequirements: manifest.runtime_requirements,
63
65
  context: manifest.context,
64
66
  prompt,
65
67
  inputSchema,
@@ -1,11 +1,12 @@
1
1
  /**
2
2
  * Module Runner - Execute Cognitive Modules
3
- * v2: Clean input mapping, no CLI pollution
3
+ * v2.1: Envelope format support, clean input mapping
4
4
  */
5
5
  import type { Provider, CognitiveModule, ModuleResult, ModuleInput } from '../types.js';
6
6
  export interface RunOptions {
7
7
  input?: ModuleInput;
8
8
  args?: string;
9
9
  verbose?: boolean;
10
+ useEnvelope?: boolean;
10
11
  }
11
12
  export declare function runModule(module: CognitiveModule, provider: Provider, options?: RunOptions): Promise<ModuleResult>;
@@ -1,9 +1,11 @@
1
1
  /**
2
2
  * Module Runner - Execute Cognitive Modules
3
- * v2: Clean input mapping, no CLI pollution
3
+ * v2.1: Envelope format support, clean input mapping
4
4
  */
5
5
  export async function runModule(module, provider, options = {}) {
6
- const { args, input, verbose = false } = options;
6
+ const { args, input, verbose = false, useEnvelope } = options;
7
+ // Determine if we should use envelope format
8
+ const shouldUseEnvelope = useEnvelope ?? (module.output?.envelope === true || module.format === 'v2');
7
9
  // Build clean input data (v2 style: no $ARGUMENTS pollution)
8
10
  const inputData = input || {};
9
11
  // Map legacy --args to clean input
@@ -22,6 +24,7 @@ export async function runModule(module, provider, options = {}) {
22
24
  console.error('--- Module ---');
23
25
  console.error(`Name: ${module.name} (${module.format})`);
24
26
  console.error(`Responsibility: ${module.responsibility}`);
27
+ console.error(`Envelope: ${shouldUseEnvelope}`);
25
28
  console.error('--- Input ---');
26
29
  console.error(JSON.stringify(inputData, null, 2));
27
30
  console.error('--- Prompt ---');
@@ -53,12 +56,27 @@ export async function runModule(module, provider, options = {}) {
53
56
  systemParts.push('', 'BEHAVIOR EQUIVALENCE:');
54
57
  systemParts.push('- You MUST set behavior_equivalence=true ONLY if the output is functionally identical');
55
58
  systemParts.push('- If unsure, set behavior_equivalence=false and explain in rationale');
59
+ const maxConfidence = module.constraints?.behavior_equivalence_false_max_confidence ?? 0.7;
60
+ systemParts.push(`- If behavior_equivalence=false, confidence MUST be <= ${maxConfidence}`);
56
61
  }
57
- systemParts.push('', 'OUTPUT FORMAT:');
58
- systemParts.push('- Respond with ONLY valid JSON');
59
- systemParts.push('- Include "confidence" (0-1) and "rationale" fields');
60
- if (module.output?.require_behavior_equivalence) {
61
- systemParts.push('- Include "behavior_equivalence" (boolean) field');
62
+ // Add envelope format instructions
63
+ if (shouldUseEnvelope) {
64
+ systemParts.push('', 'RESPONSE FORMAT (Envelope):');
65
+ systemParts.push('- Wrap your response in the envelope format');
66
+ systemParts.push('- Success: { "ok": true, "data": { ...your output... } }');
67
+ systemParts.push('- Error: { "ok": false, "error": { "code": "ERROR_CODE", "message": "..." } }');
68
+ systemParts.push('- Include "confidence" (0-1) and "rationale" in data');
69
+ if (module.output?.require_behavior_equivalence) {
70
+ systemParts.push('- Include "behavior_equivalence" (boolean) in data');
71
+ }
72
+ }
73
+ else {
74
+ systemParts.push('', 'OUTPUT FORMAT:');
75
+ systemParts.push('- Respond with ONLY valid JSON');
76
+ systemParts.push('- Include "confidence" (0-1) and "rationale" fields');
77
+ if (module.output?.require_behavior_equivalence) {
78
+ systemParts.push('- Include "behavior_equivalence" (boolean) field');
79
+ }
62
80
  }
63
81
  const messages = [
64
82
  { role: 'system', content: systemParts.join('\n') },
@@ -76,28 +94,90 @@ export async function runModule(module, provider, options = {}) {
76
94
  console.error('--- End Response ---');
77
95
  }
78
96
  // Parse response
79
- let output;
97
+ let parsed;
80
98
  try {
81
99
  const jsonMatch = result.content.match(/```(?:json)?\s*([\s\S]*?)\s*```/);
82
100
  const jsonStr = jsonMatch ? jsonMatch[1] : result.content;
83
- output = JSON.parse(jsonStr.trim());
101
+ parsed = JSON.parse(jsonStr.trim());
84
102
  }
85
103
  catch {
86
104
  throw new Error(`Failed to parse JSON response: ${result.content.substring(0, 500)}`);
87
105
  }
88
- // Extract standard fields
106
+ // Handle envelope format
107
+ if (shouldUseEnvelope && isEnvelopeResponse(parsed)) {
108
+ return parseEnvelopeResponse(parsed, result.content);
109
+ }
110
+ // Handle legacy format (non-envelope)
111
+ return parseLegacyResponse(parsed, result.content);
112
+ }
113
+ /**
114
+ * Check if response is in envelope format
115
+ */
116
+ function isEnvelopeResponse(obj) {
117
+ if (typeof obj !== 'object' || obj === null)
118
+ return false;
119
+ const o = obj;
120
+ return typeof o.ok === 'boolean';
121
+ }
122
+ /**
123
+ * Parse envelope format response
124
+ */
125
+ function parseEnvelopeResponse(response, raw) {
126
+ if (response.ok) {
127
+ const data = response.data;
128
+ return {
129
+ ok: true,
130
+ data: {
131
+ ...data,
132
+ confidence: typeof data.confidence === 'number' ? data.confidence : 0.5,
133
+ rationale: typeof data.rationale === 'string' ? data.rationale : '',
134
+ behavior_equivalence: data.behavior_equivalence,
135
+ },
136
+ raw,
137
+ };
138
+ }
139
+ else {
140
+ return {
141
+ ok: false,
142
+ error: response.error,
143
+ partial_data: response.partial_data,
144
+ raw,
145
+ };
146
+ }
147
+ }
148
+ /**
149
+ * Parse legacy (non-envelope) format response
150
+ */
151
+ function parseLegacyResponse(output, raw) {
89
152
  const outputObj = output;
90
153
  const confidence = typeof outputObj.confidence === 'number' ? outputObj.confidence : 0.5;
91
154
  const rationale = typeof outputObj.rationale === 'string' ? outputObj.rationale : '';
92
155
  const behaviorEquivalence = typeof outputObj.behavior_equivalence === 'boolean'
93
156
  ? outputObj.behavior_equivalence
94
157
  : undefined;
158
+ // Check if this is an error response (has error.code)
159
+ if (outputObj.error && typeof outputObj.error === 'object') {
160
+ const errorObj = outputObj.error;
161
+ if (typeof errorObj.code === 'string') {
162
+ return {
163
+ ok: false,
164
+ error: {
165
+ code: errorObj.code,
166
+ message: typeof errorObj.message === 'string' ? errorObj.message : 'Unknown error',
167
+ },
168
+ raw,
169
+ };
170
+ }
171
+ }
95
172
  return {
96
- output,
97
- confidence,
98
- rationale,
99
- behaviorEquivalence,
100
- raw: result.content,
173
+ ok: true,
174
+ data: {
175
+ ...outputObj,
176
+ confidence,
177
+ rationale,
178
+ behavior_equivalence: behaviorEquivalence,
179
+ },
180
+ raw,
101
181
  };
102
182
  }
103
183
  /**
package/dist/types.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Cognitive Runtime - Core Types
3
- * Version 2.0 - With tools policy, failure contract, and behavior equivalence
3
+ * Version 2.1 - With envelope format, tools policy, failure contract
4
4
  */
5
5
  export interface Provider {
6
6
  name: string;
@@ -31,9 +31,11 @@ export interface CognitiveModule {
31
31
  responsibility: string;
32
32
  excludes: string[];
33
33
  constraints?: ModuleConstraints;
34
+ policies?: ModulePolicies;
34
35
  tools?: ToolsPolicy;
35
36
  output?: OutputContract;
36
37
  failure?: FailureContract;
38
+ runtimeRequirements?: RuntimeRequirements;
37
39
  context?: 'fork' | 'main';
38
40
  prompt: string;
39
41
  inputSchema?: object;
@@ -47,20 +49,68 @@ export interface ModuleConstraints {
47
49
  no_side_effects?: boolean;
48
50
  no_file_write?: boolean;
49
51
  no_inventing_data?: boolean;
52
+ behavior_equivalence_false_max_confidence?: number;
53
+ }
54
+ export interface ModulePolicies {
55
+ network?: 'allow' | 'deny';
56
+ filesystem_write?: 'allow' | 'deny';
57
+ side_effects?: 'allow' | 'deny';
58
+ code_execution?: 'allow' | 'deny';
50
59
  }
51
60
  export interface ToolsPolicy {
61
+ policy?: 'allow_by_default' | 'deny_by_default';
52
62
  allowed: string[];
63
+ denied?: string[];
53
64
  }
54
65
  export interface OutputContract {
55
- mode?: 'json_strict' | 'json_lenient' | 'text';
66
+ format?: 'json_strict' | 'json_lenient' | 'text';
67
+ envelope?: boolean;
68
+ require?: string[];
56
69
  require_confidence?: boolean;
57
70
  require_rationale?: boolean;
58
71
  require_behavior_equivalence?: boolean;
59
72
  }
60
73
  export interface FailureContract {
74
+ contract?: 'error_union' | 'throw';
75
+ partial_allowed?: boolean;
76
+ must_return_error_schema?: boolean;
61
77
  schema?: object;
62
78
  }
79
+ export interface RuntimeRequirements {
80
+ structured_output?: boolean;
81
+ max_input_tokens?: number;
82
+ preferred_capabilities?: string[];
83
+ }
84
+ export interface EnvelopeSuccess<T = unknown> {
85
+ ok: true;
86
+ data: T;
87
+ }
88
+ export interface EnvelopeError {
89
+ ok: false;
90
+ error: {
91
+ code: string;
92
+ message: string;
93
+ };
94
+ partial_data?: unknown;
95
+ }
96
+ export type EnvelopeResponse<T = unknown> = EnvelopeSuccess<T> | EnvelopeError;
97
+ export interface ModuleResultData {
98
+ [key: string]: unknown;
99
+ confidence: number;
100
+ rationale: string;
101
+ behavior_equivalence?: boolean;
102
+ }
63
103
  export interface ModuleResult {
104
+ ok: boolean;
105
+ data?: ModuleResultData;
106
+ error?: {
107
+ code: string;
108
+ message: string;
109
+ };
110
+ partial_data?: unknown;
111
+ raw?: string;
112
+ }
113
+ export interface LegacyModuleResult {
64
114
  output: unknown;
65
115
  confidence: number;
66
116
  rationale: string;
package/dist/types.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
2
  * Cognitive Runtime - Core Types
3
- * Version 2.0 - With tools policy, failure contract, and behavior equivalence
3
+ * Version 2.1 - With envelope format, tools policy, failure contract
4
4
  */
5
5
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cognitive-runtime",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Cognitive Runtime - Structured AI Task Execution",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/src/cli.ts CHANGED
@@ -13,7 +13,7 @@ import { getProvider, listProviders } from './providers/index.js';
13
13
  import { run, list, pipe, init } from './commands/index.js';
14
14
  import type { CommandContext } from './types.js';
15
15
 
16
- const VERSION = '0.4.0';
16
+ const VERSION = '0.5.0';
17
17
 
18
18
  async function main() {
19
19
  const args = process.argv.slice(2);
@@ -54,16 +54,20 @@ export async function pipe(
54
54
  input: inputData,
55
55
  });
56
56
 
57
- // Output JSON to stdout
58
- console.log(JSON.stringify(result.output));
57
+ // Output envelope format to stdout
58
+ console.log(JSON.stringify(result));
59
59
 
60
60
  return {
61
- success: true,
61
+ success: result.ok,
62
62
  data: result,
63
63
  };
64
64
  } catch (e) {
65
65
  const error = e instanceof Error ? e.message : String(e);
66
- console.error(JSON.stringify({ error }));
66
+ // Output error in envelope format
67
+ console.log(JSON.stringify({
68
+ ok: false,
69
+ error: { code: 'RUNTIME_ERROR', message: error }
70
+ }));
67
71
  return {
68
72
  success: false,
69
73
  error,
@@ -50,10 +50,27 @@ export async function run(
50
50
  verbose: options.verbose || ctx.verbose,
51
51
  });
52
52
 
53
- return {
54
- success: true,
55
- data: options.pretty ? result : result.output,
56
- };
53
+ // Return envelope format or extracted data
54
+ if (options.pretty) {
55
+ return {
56
+ success: result.ok,
57
+ data: result,
58
+ };
59
+ } else {
60
+ // For non-pretty mode, return data (success) or error (failure)
61
+ if (result.ok) {
62
+ return {
63
+ success: true,
64
+ data: result.data,
65
+ };
66
+ } else {
67
+ return {
68
+ success: false,
69
+ error: `${result.error?.code}: ${result.error?.message}`,
70
+ data: result.partial_data,
71
+ };
72
+ }
73
+ }
57
74
  } catch (e) {
58
75
  return {
59
76
  success: false,
@@ -6,7 +6,7 @@
6
6
  import * as fs from 'node:fs/promises';
7
7
  import * as path from 'node:path';
8
8
  import yaml from 'js-yaml';
9
- import type { CognitiveModule, ModuleConstraints, ToolsPolicy, OutputContract, FailureContract } from '../types.js';
9
+ import type { CognitiveModule, ModuleConstraints, ModulePolicies, ToolsPolicy, OutputContract, FailureContract, RuntimeRequirements } from '../types.js';
10
10
 
11
11
  const FRONTMATTER_REGEX = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n([\s\S]*))?/;
12
12
 
@@ -64,9 +64,11 @@ async function loadModuleV2(modulePath: string): Promise<CognitiveModule> {
64
64
  responsibility: manifest.responsibility as string || '',
65
65
  excludes: (manifest.excludes as string[]) || [],
66
66
  constraints: manifest.constraints as ModuleConstraints | undefined,
67
+ policies: manifest.policies as ModulePolicies | undefined,
67
68
  tools: manifest.tools as ToolsPolicy | undefined,
68
69
  output: manifest.output as OutputContract | undefined,
69
70
  failure: manifest.failure as FailureContract | undefined,
71
+ runtimeRequirements: manifest.runtime_requirements as RuntimeRequirements | undefined,
70
72
  context: manifest.context as 'fork' | 'main' | undefined,
71
73
  prompt,
72
74
  inputSchema,
@@ -1,9 +1,17 @@
1
1
  /**
2
2
  * Module Runner - Execute Cognitive Modules
3
- * v2: Clean input mapping, no CLI pollution
3
+ * v2.1: Envelope format support, clean input mapping
4
4
  */
5
5
 
6
- import type { Provider, CognitiveModule, ModuleResult, Message, ModuleInput } from '../types.js';
6
+ import type {
7
+ Provider,
8
+ CognitiveModule,
9
+ ModuleResult,
10
+ Message,
11
+ ModuleInput,
12
+ EnvelopeResponse,
13
+ ModuleResultData
14
+ } from '../types.js';
7
15
 
8
16
  export interface RunOptions {
9
17
  // Clean input (v2 style)
@@ -14,6 +22,9 @@ export interface RunOptions {
14
22
 
15
23
  // Runtime options
16
24
  verbose?: boolean;
25
+
26
+ // Force envelope format (default: auto-detect from module.output.envelope)
27
+ useEnvelope?: boolean;
17
28
  }
18
29
 
19
30
  export async function runModule(
@@ -21,7 +32,10 @@ export async function runModule(
21
32
  provider: Provider,
22
33
  options: RunOptions = {}
23
34
  ): Promise<ModuleResult> {
24
- const { args, input, verbose = false } = options;
35
+ const { args, input, verbose = false, useEnvelope } = options;
36
+
37
+ // Determine if we should use envelope format
38
+ const shouldUseEnvelope = useEnvelope ?? (module.output?.envelope === true || module.format === 'v2');
25
39
 
26
40
  // Build clean input data (v2 style: no $ARGUMENTS pollution)
27
41
  const inputData: ModuleInput = input || {};
@@ -43,6 +57,7 @@ export async function runModule(
43
57
  console.error('--- Module ---');
44
58
  console.error(`Name: ${module.name} (${module.format})`);
45
59
  console.error(`Responsibility: ${module.responsibility}`);
60
+ console.error(`Envelope: ${shouldUseEnvelope}`);
46
61
  console.error('--- Input ---');
47
62
  console.error(JSON.stringify(inputData, null, 2));
48
63
  console.error('--- Prompt ---');
@@ -74,13 +89,28 @@ export async function runModule(
74
89
  systemParts.push('', 'BEHAVIOR EQUIVALENCE:');
75
90
  systemParts.push('- You MUST set behavior_equivalence=true ONLY if the output is functionally identical');
76
91
  systemParts.push('- If unsure, set behavior_equivalence=false and explain in rationale');
92
+
93
+ const maxConfidence = module.constraints?.behavior_equivalence_false_max_confidence ?? 0.7;
94
+ systemParts.push(`- If behavior_equivalence=false, confidence MUST be <= ${maxConfidence}`);
77
95
  }
78
96
 
79
- systemParts.push('', 'OUTPUT FORMAT:');
80
- systemParts.push('- Respond with ONLY valid JSON');
81
- systemParts.push('- Include "confidence" (0-1) and "rationale" fields');
82
- if (module.output?.require_behavior_equivalence) {
83
- systemParts.push('- Include "behavior_equivalence" (boolean) field');
97
+ // Add envelope format instructions
98
+ if (shouldUseEnvelope) {
99
+ systemParts.push('', 'RESPONSE FORMAT (Envelope):');
100
+ systemParts.push('- Wrap your response in the envelope format');
101
+ systemParts.push('- Success: { "ok": true, "data": { ...your output... } }');
102
+ systemParts.push('- Error: { "ok": false, "error": { "code": "ERROR_CODE", "message": "..." } }');
103
+ systemParts.push('- Include "confidence" (0-1) and "rationale" in data');
104
+ if (module.output?.require_behavior_equivalence) {
105
+ systemParts.push('- Include "behavior_equivalence" (boolean) in data');
106
+ }
107
+ } else {
108
+ systemParts.push('', 'OUTPUT FORMAT:');
109
+ systemParts.push('- Respond with ONLY valid JSON');
110
+ systemParts.push('- Include "confidence" (0-1) and "rationale" fields');
111
+ if (module.output?.require_behavior_equivalence) {
112
+ systemParts.push('- Include "behavior_equivalence" (boolean) field');
113
+ }
84
114
  }
85
115
 
86
116
  const messages: Message[] = [
@@ -102,16 +132,63 @@ export async function runModule(
102
132
  }
103
133
 
104
134
  // Parse response
105
- let output: unknown;
135
+ let parsed: unknown;
106
136
  try {
107
137
  const jsonMatch = result.content.match(/```(?:json)?\s*([\s\S]*?)\s*```/);
108
138
  const jsonStr = jsonMatch ? jsonMatch[1] : result.content;
109
- output = JSON.parse(jsonStr.trim());
139
+ parsed = JSON.parse(jsonStr.trim());
110
140
  } catch {
111
141
  throw new Error(`Failed to parse JSON response: ${result.content.substring(0, 500)}`);
112
142
  }
113
143
 
114
- // Extract standard fields
144
+ // Handle envelope format
145
+ if (shouldUseEnvelope && isEnvelopeResponse(parsed)) {
146
+ return parseEnvelopeResponse(parsed, result.content);
147
+ }
148
+
149
+ // Handle legacy format (non-envelope)
150
+ return parseLegacyResponse(parsed, result.content);
151
+ }
152
+
153
+ /**
154
+ * Check if response is in envelope format
155
+ */
156
+ function isEnvelopeResponse(obj: unknown): obj is EnvelopeResponse {
157
+ if (typeof obj !== 'object' || obj === null) return false;
158
+ const o = obj as Record<string, unknown>;
159
+ return typeof o.ok === 'boolean';
160
+ }
161
+
162
+ /**
163
+ * Parse envelope format response
164
+ */
165
+ function parseEnvelopeResponse(response: EnvelopeResponse, raw: string): ModuleResult {
166
+ if (response.ok) {
167
+ const data = response.data as ModuleResultData;
168
+ return {
169
+ ok: true,
170
+ data: {
171
+ ...data,
172
+ confidence: typeof data.confidence === 'number' ? data.confidence : 0.5,
173
+ rationale: typeof data.rationale === 'string' ? data.rationale : '',
174
+ behavior_equivalence: data.behavior_equivalence,
175
+ },
176
+ raw,
177
+ };
178
+ } else {
179
+ return {
180
+ ok: false,
181
+ error: response.error,
182
+ partial_data: response.partial_data,
183
+ raw,
184
+ };
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Parse legacy (non-envelope) format response
190
+ */
191
+ function parseLegacyResponse(output: unknown, raw: string): ModuleResult {
115
192
  const outputObj = output as Record<string, unknown>;
116
193
  const confidence = typeof outputObj.confidence === 'number' ? outputObj.confidence : 0.5;
117
194
  const rationale = typeof outputObj.rationale === 'string' ? outputObj.rationale : '';
@@ -119,12 +196,30 @@ export async function runModule(
119
196
  ? outputObj.behavior_equivalence
120
197
  : undefined;
121
198
 
199
+ // Check if this is an error response (has error.code)
200
+ if (outputObj.error && typeof outputObj.error === 'object') {
201
+ const errorObj = outputObj.error as Record<string, unknown>;
202
+ if (typeof errorObj.code === 'string') {
203
+ return {
204
+ ok: false,
205
+ error: {
206
+ code: errorObj.code,
207
+ message: typeof errorObj.message === 'string' ? errorObj.message : 'Unknown error',
208
+ },
209
+ raw,
210
+ };
211
+ }
212
+ }
213
+
122
214
  return {
123
- output,
124
- confidence,
125
- rationale,
126
- behaviorEquivalence,
127
- raw: result.content,
215
+ ok: true,
216
+ data: {
217
+ ...outputObj,
218
+ confidence,
219
+ rationale,
220
+ behavior_equivalence: behaviorEquivalence,
221
+ } as ModuleResultData,
222
+ raw,
128
223
  };
129
224
  }
130
225
 
package/src/types.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Cognitive Runtime - Core Types
3
- * Version 2.0 - With tools policy, failure contract, and behavior equivalence
3
+ * Version 2.1 - With envelope format, tools policy, failure contract
4
4
  */
5
5
 
6
6
  // Provider interface - all LLM providers implement this
@@ -31,7 +31,7 @@ export interface InvokeResult {
31
31
  };
32
32
  }
33
33
 
34
- // Module types (v2)
34
+ // Module types (v2.1)
35
35
  export interface CognitiveModule {
36
36
  // Core identity
37
37
  name: string;
@@ -42,6 +42,9 @@ export interface CognitiveModule {
42
42
  excludes: string[];
43
43
  constraints?: ModuleConstraints;
44
44
 
45
+ // Unified policies (v2.1)
46
+ policies?: ModulePolicies;
47
+
45
48
  // Tools policy
46
49
  tools?: ToolsPolicy;
47
50
 
@@ -51,6 +54,9 @@ export interface CognitiveModule {
51
54
  // Failure contract
52
55
  failure?: FailureContract;
53
56
 
57
+ // Runtime requirements
58
+ runtimeRequirements?: RuntimeRequirements;
59
+
54
60
  // Execution context
55
61
  context?: 'fork' | 'main';
56
62
 
@@ -72,24 +78,82 @@ export interface ModuleConstraints {
72
78
  no_side_effects?: boolean;
73
79
  no_file_write?: boolean;
74
80
  no_inventing_data?: boolean;
81
+ behavior_equivalence_false_max_confidence?: number;
82
+ }
83
+
84
+ export interface ModulePolicies {
85
+ network?: 'allow' | 'deny';
86
+ filesystem_write?: 'allow' | 'deny';
87
+ side_effects?: 'allow' | 'deny';
88
+ code_execution?: 'allow' | 'deny';
75
89
  }
76
90
 
77
91
  export interface ToolsPolicy {
92
+ policy?: 'allow_by_default' | 'deny_by_default';
78
93
  allowed: string[];
94
+ denied?: string[];
79
95
  }
80
96
 
81
97
  export interface OutputContract {
82
- mode?: 'json_strict' | 'json_lenient' | 'text';
98
+ format?: 'json_strict' | 'json_lenient' | 'text';
99
+ envelope?: boolean; // v2.1: Use {ok, data/error} wrapper
100
+ require?: string[];
83
101
  require_confidence?: boolean;
84
102
  require_rationale?: boolean;
85
103
  require_behavior_equivalence?: boolean;
86
104
  }
87
105
 
88
106
  export interface FailureContract {
107
+ contract?: 'error_union' | 'throw';
108
+ partial_allowed?: boolean;
109
+ must_return_error_schema?: boolean;
89
110
  schema?: object;
90
111
  }
91
112
 
113
+ export interface RuntimeRequirements {
114
+ structured_output?: boolean;
115
+ max_input_tokens?: number;
116
+ preferred_capabilities?: string[];
117
+ }
118
+
119
+ // Envelope response format (v2.1)
120
+ export interface EnvelopeSuccess<T = unknown> {
121
+ ok: true;
122
+ data: T;
123
+ }
124
+
125
+ export interface EnvelopeError {
126
+ ok: false;
127
+ error: {
128
+ code: string;
129
+ message: string;
130
+ };
131
+ partial_data?: unknown;
132
+ }
133
+
134
+ export type EnvelopeResponse<T = unknown> = EnvelopeSuccess<T> | EnvelopeError;
135
+
136
+ // Module result types
137
+ export interface ModuleResultData {
138
+ [key: string]: unknown;
139
+ confidence: number;
140
+ rationale: string;
141
+ behavior_equivalence?: boolean;
142
+ }
143
+
92
144
  export interface ModuleResult {
145
+ ok: boolean;
146
+ data?: ModuleResultData;
147
+ error?: {
148
+ code: string;
149
+ message: string;
150
+ };
151
+ partial_data?: unknown;
152
+ raw?: string;
153
+ }
154
+
155
+ // Legacy result format (for backward compatibility)
156
+ export interface LegacyModuleResult {
93
157
  output: unknown;
94
158
  confidence: number;
95
159
  rationale: string;