@probelabs/probe 0.6.0-rc339 → 0.6.0-rc341
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/bin/binaries/{probe-v0.6.0-rc339-x86_64-apple-darwin.tar.gz → probe-v0.6.0-rc341-aarch64-apple-darwin.tar.gz} +0 -0
- package/bin/binaries/{probe-v0.6.0-rc339-aarch64-unknown-linux-musl.tar.gz → probe-v0.6.0-rc341-aarch64-unknown-linux-musl.tar.gz} +0 -0
- package/bin/binaries/{probe-v0.6.0-rc339-x86_64-pc-windows-msvc.zip → probe-v0.6.0-rc341-x86_64-apple-darwin.tar.gz} +0 -0
- package/bin/binaries/probe-v0.6.0-rc341-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/{probe-v0.6.0-rc339-x86_64-unknown-linux-musl.tar.gz → probe-v0.6.0-rc341-x86_64-unknown-linux-musl.tar.gz} +0 -0
- package/build/agent/ProbeAgent.d.ts +37 -9
- package/build/agent/ProbeAgent.js +196 -62
- package/build/agent/acp/tools.js +1 -1
- package/build/agent/engines/codex.js +189 -52
- package/build/agent/engines/governed-answer-failure.js +164 -5
- package/build/agent/engines/governed-codex-exec.js +1227 -0
- package/build/agent/engines/governed-codex-profile.js +80 -28
- package/build/agent/governance/index.d.ts +18 -0
- package/build/agent/governance/index.js +14 -0
- package/build/index.js +26 -0
- package/cjs/agent/ProbeAgent.cjs +3291 -1117
- package/cjs/index.cjs +3318 -1119
- package/index.d.ts +53 -7
- package/package.json +1 -1
- package/src/agent/ProbeAgent.d.ts +37 -9
- package/src/agent/ProbeAgent.js +196 -62
- package/src/agent/acp/tools.js +1 -1
- package/src/agent/engines/codex.js +189 -52
- package/src/agent/engines/governed-answer-failure.js +164 -5
- package/src/agent/engines/governed-codex-exec.js +1227 -0
- package/src/agent/engines/governed-codex-profile.js +80 -28
- package/src/agent/governance/index.d.ts +18 -0
- package/src/agent/governance/index.js +14 -0
- package/src/index.js +26 -0
- package/bin/binaries/probe-v0.6.0-rc339-aarch64-apple-darwin.tar.gz +0 -0
|
@@ -13,18 +13,74 @@ import { attestGovernedCodexSession, buildGovernedCodexInitialToolArgs, validate
|
|
|
13
13
|
import { governedAnswerFailure, normalizeGovernedAnswerFailure } from './governed-answer-failure.js';
|
|
14
14
|
|
|
15
15
|
const GOVERNED_NATIVE_EVENT_LIMIT = 256;
|
|
16
|
+
const GOVERNED_WRITER_RAW_RESPONSE_ITEM_LIMIT = 1024;
|
|
16
17
|
const GOVERNED_SAFE_ID = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
17
18
|
const GOVERNED_SAFE_KIND = /^[A-Za-z0-9._:-]{1,64}$/;
|
|
18
|
-
const
|
|
19
|
+
const CODEX_REQUEST_TIMEOUT_DEFAULT = 600000;
|
|
20
|
+
const CODEX_REQUEST_TIMEOUT_MIN = 1000;
|
|
21
|
+
const CODEX_REQUEST_TIMEOUT_MAX = 3600000;
|
|
22
|
+
const GOVERNED_CODEX_NATIVE_CALLS = new Map([['apply_patch', 'apply_patch'], ['exec', 'exec']]);
|
|
19
23
|
const GOVERNED_PROBE_MCP_CALLS = new Map([
|
|
20
24
|
['mcp__probe__search', 'search'], ['mcp__probe__extract', 'extract'], ['mcp__probe__listFiles', 'listFiles'],
|
|
21
25
|
]);
|
|
26
|
+
function governedNativeProfile(profile) { return Array.isArray(profile?.codexNativeTools); }
|
|
27
|
+
function governedRawResponseItemLimit(profile) {
|
|
28
|
+
return profile?.version === 'probe.governed-codex-profile/v3' &&
|
|
29
|
+
profile?.profileId === 'luna-xhigh-isolated-writer-v1'
|
|
30
|
+
? GOVERNED_WRITER_RAW_RESPONSE_ITEM_LIMIT : GOVERNED_NATIVE_EVENT_LIMIT;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function emitGovernedRequestTimeout(agent, profile, session, method, timeoutMs) {
|
|
34
|
+
if (!profile || typeof agent?.events?.emit !== 'function') return;
|
|
35
|
+
const sessionId = typeof session?.id === 'string' && GOVERNED_SAFE_ID.test(session.id) ? session.id : null;
|
|
36
|
+
const boundary = method === 'initialize' ? 'acquire' : method === 'tools/call' ? 'query' : null;
|
|
37
|
+
if (!boundary) return;
|
|
38
|
+
const record = Object.freeze({
|
|
39
|
+
category: 'request_timeout', method, boundary, timeout_ms: timeoutMs,
|
|
40
|
+
profileId: profile.profileId, sessionId,
|
|
41
|
+
});
|
|
42
|
+
try { agent.events.emit('timeout.request', record); } catch { /* timeout rejection must remain authoritative */ }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function validateCodexRequestTimeout(value) {
|
|
46
|
+
return Number.isInteger(value) && (value === 0 ||
|
|
47
|
+
(value >= CODEX_REQUEST_TIMEOUT_MIN && value <= CODEX_REQUEST_TIMEOUT_MAX))
|
|
48
|
+
? value : CODEX_REQUEST_TIMEOUT_DEFAULT;
|
|
49
|
+
}
|
|
22
50
|
|
|
23
|
-
function
|
|
51
|
+
function validateGovernedEngineOverrides(options, profile) {
|
|
52
|
+
const invalid = (label) => { throw new TypeError(`Invalid governed Codex ${label}`); };
|
|
53
|
+
if (options.model !== undefined && options.model !== null && options.model !== profile.model) invalid('model');
|
|
54
|
+
for (const [key, expected] of [['sandbox', profile.sandbox], ['cwd', profile.cwd],
|
|
55
|
+
['approvalPolicy', profile.approvalPolicy], ['approval-policy', profile.approvalPolicy],
|
|
56
|
+
['reasoningEffort', profile.reasoningEffort], ['modelReasoningEffort', profile.reasoningEffort]]) {
|
|
57
|
+
if (Object.prototype.hasOwnProperty.call(options, key) && options[key] !== undefined && options[key] !== expected) invalid(key);
|
|
58
|
+
}
|
|
59
|
+
if (Object.prototype.hasOwnProperty.call(options, 'config') && options.config !== undefined) invalid('config');
|
|
60
|
+
if (Object.prototype.hasOwnProperty.call(options, 'env') && options.env !== undefined) invalid('env');
|
|
61
|
+
if (options.retry !== undefined && options.retry !== null) invalid('retry');
|
|
62
|
+
if (options.fallback !== undefined && options.fallback !== null) invalid('fallback');
|
|
63
|
+
if (options.sessionId !== undefined && profile.profileId === 'luna-xhigh-isolated-writer-v1') invalid('sessionId');
|
|
64
|
+
|
|
65
|
+
if (options.allowedTools === undefined) return;
|
|
66
|
+
const expectedTools = profile.probeTools ?? profile.probeMcpTools;
|
|
67
|
+
if (Array.isArray(options.allowedTools)) {
|
|
68
|
+
if (options.allowedTools.length !== expectedTools.length || options.allowedTools.some((name, index) => name !== expectedTools[index])) invalid('allowedTools');
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const parsed = options.allowedTools;
|
|
72
|
+
if (parsed === null || typeof parsed !== 'object' || parsed.mode !== 'whitelist' ||
|
|
73
|
+
!Array.isArray(parsed.allowed) || parsed.allowed.length !== expectedTools.length ||
|
|
74
|
+
parsed.allowed.some((name, index) => name !== expectedTools[index])) invalid('allowedTools');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function governedRawItemInvalid(predicate) {
|
|
78
|
+
throw governedAnswerFailure('native_event_grammar', 'raw_item_predicate', null, null, null, null, null, null, predicate);
|
|
79
|
+
}
|
|
24
80
|
function governedLiveEnvelopeInvalid(subreason, correlationOperand = null) {
|
|
25
81
|
throw governedAnswerFailure('native_event_grammar', 'live_envelope_session', subreason, correlationOperand);
|
|
26
82
|
}
|
|
27
|
-
function governedExactObject(value, keys, invalid = governedRawItemInvalid) {
|
|
83
|
+
function governedExactObject(value, keys, invalid = () => governedRawItemInvalid('shape')) {
|
|
28
84
|
if (value === null || typeof value !== 'object' || Array.isArray(value)) invalid();
|
|
29
85
|
const proto = Object.getPrototypeOf(value);
|
|
30
86
|
if (proto !== Object.prototype && proto !== null) invalid();
|
|
@@ -33,7 +89,7 @@ function governedExactObject(value, keys, invalid = governedRawItemInvalid) {
|
|
|
33
89
|
for (const key of keys) if (!Object.prototype.hasOwnProperty.call(Object.getOwnPropertyDescriptor(value, key), 'value')) invalid();
|
|
34
90
|
return value;
|
|
35
91
|
}
|
|
36
|
-
function governedSafeId(value) { if (typeof value !== 'string' || !GOVERNED_SAFE_ID.test(value)) governedRawItemInvalid(); }
|
|
92
|
+
function governedSafeId(value) { if (typeof value !== 'string' || !GOVERNED_SAFE_ID.test(value)) governedRawItemInvalid('id'); }
|
|
37
93
|
function governedProbeMcpCallCount(evidence) {
|
|
38
94
|
const invalid = () => { throw new TypeError('Invalid attester input'); };
|
|
39
95
|
const snapshot = governedExactObject(evidence, ['admitted', 'closed', 'overflow'], invalid);
|
|
@@ -47,14 +103,14 @@ function governedPassthrough(value, message = false) {
|
|
|
47
103
|
const keys = Object.keys(value ?? {}).sort().join(',');
|
|
48
104
|
const legacy = keys === 'turn_id';
|
|
49
105
|
const current = keys === (message ? 'content_item_kinds,create_time,turn_id' : 'create_time,turn_id');
|
|
50
|
-
if (!legacy && !current) governedRawItemInvalid();
|
|
106
|
+
if (!legacy && !current) governedRawItemInvalid('passthrough');
|
|
51
107
|
governedSafeId(value.turn_id);
|
|
52
108
|
if (current) {
|
|
53
109
|
if (typeof value.create_time !== 'number' || !Number.isFinite(value.create_time) ||
|
|
54
|
-
value.create_time < 0 || value.create_time > Number.MAX_SAFE_INTEGER) governedRawItemInvalid();
|
|
110
|
+
value.create_time < 0 || value.create_time > Number.MAX_SAFE_INTEGER) governedRawItemInvalid('passthrough');
|
|
55
111
|
if (message) {
|
|
56
|
-
if (!Array.isArray(value.content_item_kinds) || value.content_item_kinds.length > 16) governedRawItemInvalid();
|
|
57
|
-
for (const kind of value.content_item_kinds) if (typeof kind !== 'string' || !GOVERNED_SAFE_KIND.test(kind)) governedRawItemInvalid();
|
|
112
|
+
if (!Array.isArray(value.content_item_kinds) || value.content_item_kinds.length > 16) governedRawItemInvalid('passthrough');
|
|
113
|
+
for (const kind of value.content_item_kinds) if (typeof kind !== 'string' || !GOVERNED_SAFE_KIND.test(kind)) governedRawItemInvalid('passthrough');
|
|
58
114
|
}
|
|
59
115
|
}
|
|
60
116
|
}
|
|
@@ -66,25 +122,34 @@ function validateGovernedRawMessage(item) {
|
|
|
66
122
|
? ['type', 'id', 'role', 'content', 'internal_chat_message_metadata_passthrough']
|
|
67
123
|
: ['type', 'role', 'content', 'internal_chat_message_metadata_passthrough'];
|
|
68
124
|
governedExactObject(item, keys);
|
|
69
|
-
if (item.type !== 'message' || !['developer', 'user', 'assistant'].includes(item.role)) governedRawItemInvalid();
|
|
125
|
+
if (item.type !== 'message' || !['developer', 'user', 'assistant'].includes(item.role)) governedRawItemInvalid('type');
|
|
70
126
|
if (Object.prototype.hasOwnProperty.call(item, 'id')) governedSafeId(item.id);
|
|
71
|
-
if (assistant && !['commentary', 'final_answer'].includes(item.phase)) governedRawItemInvalid();
|
|
72
|
-
if (!Array.isArray(item.content)
|
|
127
|
+
if (assistant && !['commentary', 'final_answer'].includes(item.phase)) governedRawItemInvalid('phase');
|
|
128
|
+
if (!Array.isArray(item.content)) governedRawItemInvalid('message_content_array');
|
|
129
|
+
if (item.content.length < 1) governedRawItemInvalid('message_content_empty');
|
|
130
|
+
if (item.content.length > 64) governedRawItemInvalid('message_content_limit');
|
|
73
131
|
for (const part of item.content) {
|
|
74
132
|
governedExactObject(part, ['type', 'text']);
|
|
75
133
|
const allowed = assistant ? part.type === 'output_text' : part.type === 'input_text';
|
|
76
|
-
if (!allowed
|
|
134
|
+
if (!allowed) governedRawItemInvalid('message_content_kind');
|
|
135
|
+
if (typeof part.text !== 'string') governedRawItemInvalid('message_content_text_type');
|
|
136
|
+
if (Buffer.byteLength(part.text, 'utf8') > 131072) governedRawItemInvalid('message_content_text_limit');
|
|
77
137
|
}
|
|
78
138
|
governedPassthrough(item.internal_chat_message_metadata_passthrough, true);
|
|
79
139
|
}
|
|
80
140
|
function validateGovernedRawReasoning(item) {
|
|
81
141
|
governedExactObject(item, ['type', 'id', 'summary', 'encrypted_content', 'internal_chat_message_metadata_passthrough']);
|
|
82
|
-
if (item.type !== 'reasoning') governedRawItemInvalid(); governedSafeId(item.id);
|
|
83
|
-
if (!Array.isArray(item.summary)
|
|
142
|
+
if (item.type !== 'reasoning') governedRawItemInvalid('type'); governedSafeId(item.id);
|
|
143
|
+
if (!Array.isArray(item.summary)) governedRawItemInvalid('reasoning_summary_array');
|
|
144
|
+
if (item.summary.length !== 0) governedRawItemInvalid('reasoning_summary_nonempty');
|
|
145
|
+
if (typeof item.encrypted_content !== 'string') governedRawItemInvalid('reasoning_encrypted_content_type');
|
|
146
|
+
if (Buffer.byteLength(item.encrypted_content, 'utf8') > 1048576) governedRawItemInvalid('reasoning_encrypted_content_limit');
|
|
84
147
|
governedPassthrough(item.internal_chat_message_metadata_passthrough);
|
|
85
148
|
}
|
|
86
149
|
function createGovernedNativeCollector(profile) {
|
|
87
150
|
let sessionEvent = null, requestId = null, threadId = null, nativeCallCount = 0;
|
|
151
|
+
const nativeToolCounts = new Map(profile.codexNativeTools?.map((name) => [name, 0]) ?? []);
|
|
152
|
+
const rawResponseItemLimit = governedRawResponseItemLimit(profile);
|
|
88
153
|
let relevantEventCount = 0, totalCallCount = 0, rawResponseItemCount = 0, assistantMessageCount = 0, finalAnswerCount = 0;
|
|
89
154
|
const rawIds = new Set(), callOrigins = new Map(), outputIds = new Set();
|
|
90
155
|
function observe(event) {
|
|
@@ -96,7 +161,7 @@ function createGovernedNativeCollector(profile) {
|
|
|
96
161
|
threadId = event.params?._meta?.threadId;
|
|
97
162
|
return;
|
|
98
163
|
}
|
|
99
|
-
if (profile
|
|
164
|
+
if (!governedNativeProfile(profile) || type !== 'raw_response_item') return;
|
|
100
165
|
if (!sessionEvent) governedLiveEnvelopeInvalid('session_sequence');
|
|
101
166
|
governedExactObject(event, ['jsonrpc', 'method', 'params'], () => governedLiveEnvelopeInvalid('envelope_shape'));
|
|
102
167
|
if (event.jsonrpc !== '2.0' || event.method !== 'codex/event') governedLiveEnvelopeInvalid('envelope_shape');
|
|
@@ -108,35 +173,42 @@ function createGovernedNativeCollector(profile) {
|
|
|
108
173
|
const msg = governedExactObject(params.msg, ['type', 'item'], () => governedLiveEnvelopeInvalid('envelope_shape'));
|
|
109
174
|
if (msg.type !== 'raw_response_item') governedLiveEnvelopeInvalid('envelope_shape');
|
|
110
175
|
const item = msg.item;
|
|
111
|
-
if (++rawResponseItemCount >
|
|
176
|
+
if (++rawResponseItemCount > rawResponseItemLimit) governedRawItemInvalid('event_limit');
|
|
112
177
|
if (item?.type === 'message') {
|
|
113
178
|
validateGovernedRawMessage(item);
|
|
114
179
|
if (Object.prototype.hasOwnProperty.call(item, 'id')) {
|
|
115
|
-
if (rawIds.has(item.id)) governedRawItemInvalid(); rawIds.add(item.id);
|
|
180
|
+
if (rawIds.has(item.id)) governedRawItemInvalid('duplicate'); rawIds.add(item.id);
|
|
116
181
|
}
|
|
117
182
|
if (item.role === 'assistant') { assistantMessageCount++; if (item.phase === 'final_answer') finalAnswerCount++; }
|
|
118
183
|
return;
|
|
119
184
|
}
|
|
120
185
|
if (item?.type === 'reasoning') {
|
|
121
186
|
validateGovernedRawReasoning(item);
|
|
122
|
-
if (rawIds.has(item.id)) governedRawItemInvalid(); rawIds.add(item.id);
|
|
187
|
+
if (rawIds.has(item.id)) governedRawItemInvalid('duplicate'); rawIds.add(item.id);
|
|
123
188
|
return;
|
|
124
189
|
}
|
|
125
190
|
if (item?.type === 'custom_tool_call') {
|
|
126
191
|
governedExactObject(item, ['type', 'id', 'status', 'call_id', 'name', 'input', 'internal_chat_message_metadata_passthrough']);
|
|
127
192
|
governedSafeId(item.id); governedSafeId(item.call_id);
|
|
128
|
-
if (rawIds.has(item.id) || callOrigins.has(item.call_id)) governedRawItemInvalid();
|
|
193
|
+
if (rawIds.has(item.id) || callOrigins.has(item.call_id)) governedRawItemInvalid('duplicate');
|
|
129
194
|
const nativeName = GOVERNED_CODEX_NATIVE_CALLS.get(item.name);
|
|
130
195
|
const probeMcpName = GOVERNED_PROBE_MCP_CALLS.get(item.name);
|
|
131
|
-
if ((nativeName !== undefined) === (probeMcpName !== undefined)) governedRawItemInvalid();
|
|
132
|
-
if (nativeName !== undefined && !profile.codexNativeTools.includes(nativeName)) governedRawItemInvalid();
|
|
133
|
-
if (probeMcpName !== undefined && !profile.probeMcpTools.includes(probeMcpName)) governedRawItemInvalid();
|
|
134
|
-
if (item.status !== 'completed'
|
|
196
|
+
if ((nativeName !== undefined) === (probeMcpName !== undefined)) governedRawItemInvalid('tool_name_or_allow');
|
|
197
|
+
if (nativeName !== undefined && !profile.codexNativeTools.includes(nativeName)) governedRawItemInvalid('tool_name_or_allow');
|
|
198
|
+
if (probeMcpName !== undefined && !profile.probeMcpTools.includes(probeMcpName)) governedRawItemInvalid('tool_name_or_allow');
|
|
199
|
+
if (item.status !== 'completed') governedRawItemInvalid('status');
|
|
200
|
+
if (typeof item.input !== 'string' || Buffer.byteLength(item.input, 'utf8') > 131072) governedRawItemInvalid('input');
|
|
135
201
|
governedPassthrough(item.internal_chat_message_metadata_passthrough);
|
|
136
|
-
|
|
202
|
+
relevantEventCount++;
|
|
203
|
+
totalCallCount++;
|
|
204
|
+
if (totalCallCount > GOVERNED_NATIVE_EVENT_LIMIT) governedRawItemInvalid('tool_call_limit');
|
|
205
|
+
if (relevantEventCount > GOVERNED_NATIVE_EVENT_LIMIT) governedRawItemInvalid('tool_event_limit');
|
|
137
206
|
const origin = nativeName !== undefined ? 'codex-native' : 'probe-mcp';
|
|
138
207
|
rawIds.add(item.id); callOrigins.set(item.call_id, origin);
|
|
139
|
-
if (origin === 'codex-native')
|
|
208
|
+
if (origin === 'codex-native') {
|
|
209
|
+
nativeCallCount++;
|
|
210
|
+
nativeToolCounts.set(nativeName, (nativeToolCounts.get(nativeName) ?? 0) + 1);
|
|
211
|
+
}
|
|
140
212
|
return;
|
|
141
213
|
}
|
|
142
214
|
if (item?.type === 'custom_tool_call_output') {
|
|
@@ -144,25 +216,38 @@ function createGovernedNativeCollector(profile) {
|
|
|
144
216
|
governedExactObject(item, hasId
|
|
145
217
|
? ['type', 'id', 'call_id', 'output', 'internal_chat_message_metadata_passthrough']
|
|
146
218
|
: ['type', 'call_id', 'output', 'internal_chat_message_metadata_passthrough']);
|
|
147
|
-
if (hasId) { governedSafeId(item.id); if (rawIds.has(item.id)) governedRawItemInvalid(); }
|
|
219
|
+
if (hasId) { governedSafeId(item.id); if (rawIds.has(item.id)) governedRawItemInvalid('duplicate'); }
|
|
148
220
|
governedSafeId(item.call_id);
|
|
149
|
-
if (!callOrigins.has(item.call_id) || outputIds.has(item.call_id)
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
221
|
+
if (!callOrigins.has(item.call_id) || outputIds.has(item.call_id)) governedRawItemInvalid('call_output_pairing');
|
|
222
|
+
if (typeof item.output === 'string') {
|
|
223
|
+
if (Buffer.byteLength(item.output, 'utf8') > 1048576) governedRawItemInvalid('tool_output_text_limit');
|
|
224
|
+
} else {
|
|
225
|
+
if (!Array.isArray(item.output)) governedRawItemInvalid('tool_output_array');
|
|
226
|
+
if (item.output.length > 64) governedRawItemInvalid('tool_output_limit');
|
|
227
|
+
for (const part of item.output) {
|
|
228
|
+
governedExactObject(part, ['type', 'text']);
|
|
229
|
+
if (part.type !== 'input_text') governedRawItemInvalid('tool_output_kind');
|
|
230
|
+
if (typeof part.text !== 'string') governedRawItemInvalid('tool_output_text_type');
|
|
231
|
+
if (Buffer.byteLength(part.text, 'utf8') > 1048576) governedRawItemInvalid('tool_output_text_limit');
|
|
232
|
+
}
|
|
153
233
|
}
|
|
154
234
|
governedPassthrough(item.internal_chat_message_metadata_passthrough);
|
|
155
|
-
|
|
235
|
+
relevantEventCount++;
|
|
236
|
+
if (relevantEventCount > GOVERNED_NATIVE_EVENT_LIMIT) governedRawItemInvalid('tool_event_limit');
|
|
156
237
|
if (hasId) rawIds.add(item.id);
|
|
157
238
|
outputIds.add(item.call_id);
|
|
158
239
|
return;
|
|
159
240
|
}
|
|
160
|
-
governedRawItemInvalid();
|
|
241
|
+
governedRawItemInvalid('type');
|
|
161
242
|
}
|
|
162
243
|
function evidence() {
|
|
163
244
|
if (!sessionEvent) governedLiveEnvelopeInvalid('session_sequence');
|
|
164
|
-
if (assistantMessageCount > 0 && finalAnswerCount !== 1) governedRawItemInvalid();
|
|
165
|
-
const tools =
|
|
245
|
+
if (assistantMessageCount > 0 && finalAnswerCount !== 1) governedRawItemInvalid('final_answer_cardinality');
|
|
246
|
+
const tools = [];
|
|
247
|
+
for (const name of profile.codexNativeTools ?? []) {
|
|
248
|
+
const count = nativeToolCounts.get(name) ?? 0;
|
|
249
|
+
if (count > 0) tools.push({ name, status: 'completed', count });
|
|
250
|
+
}
|
|
166
251
|
return { sessionEvent, capabilities: { nativeTools: { total: nativeCallCount, tools } } };
|
|
167
252
|
}
|
|
168
253
|
return { observe, evidence };
|
|
@@ -235,8 +320,11 @@ function externalBoundReceipt(internal, dispatch, invocationDigest, capabilityCo
|
|
|
235
320
|
* Codex Engine using MCP Server with event streaming
|
|
236
321
|
*/
|
|
237
322
|
export async function createCodexEngine(options = {}) {
|
|
238
|
-
const { agent, systemPrompt, customPrompt, debug, sessionId, allowedTools, model
|
|
323
|
+
const { agent, systemPrompt, customPrompt, debug, sessionId, allowedTools, model,
|
|
324
|
+
requestTimeout: configuredRequestTimeout } = options;
|
|
325
|
+
const requestTimeout = validateCodexRequestTimeout(configuredRequestTimeout);
|
|
239
326
|
const governedProfile = options.governedCodexProfile === undefined ? null : validateGovernedCodexProfile(options.governedCodexProfile);
|
|
327
|
+
if (governedProfile) validateGovernedEngineOverrides(options, governedProfile);
|
|
240
328
|
|
|
241
329
|
const session = new Session(
|
|
242
330
|
sessionId || randomBytes(8).toString('hex'),
|
|
@@ -253,8 +341,8 @@ export async function createCodexEngine(options = {}) {
|
|
|
253
341
|
port: 0,
|
|
254
342
|
host: '127.0.0.1',
|
|
255
343
|
debug: debug,
|
|
256
|
-
...(governedProfile
|
|
257
|
-
? { governedProfileVersion:
|
|
344
|
+
...(governedNativeProfile(governedProfile)
|
|
345
|
+
? { governedProfileVersion: 'probe.governed-codex-profile/v2' } : {})
|
|
258
346
|
});
|
|
259
347
|
|
|
260
348
|
const { host, port } = await mcpServer.start();
|
|
@@ -356,13 +444,17 @@ export async function createCodexEngine(options = {}) {
|
|
|
356
444
|
params
|
|
357
445
|
};
|
|
358
446
|
|
|
359
|
-
//
|
|
360
|
-
|
|
447
|
+
// Keep the protocol startup handshake bounded even when query deadlines
|
|
448
|
+
// are explicitly disabled. Tool/query requests use no host timer at 0.
|
|
449
|
+
const effectiveTimeout = method === 'initialize' && requestTimeout === 0
|
|
450
|
+
? CODEX_REQUEST_TIMEOUT_DEFAULT : requestTimeout;
|
|
451
|
+
const timer = effectiveTimeout > 0 ? setTimeout(() => {
|
|
361
452
|
if (pendingRequests.has(id)) {
|
|
362
453
|
pendingRequests.delete(id);
|
|
363
|
-
|
|
454
|
+
emitGovernedRequestTimeout(agent, governedProfile, session, method, effectiveTimeout);
|
|
455
|
+
reject(new Error(`Request ${method} timed out after ${effectiveTimeout}ms`));
|
|
364
456
|
}
|
|
365
|
-
},
|
|
457
|
+
}, effectiveTimeout) : null;
|
|
366
458
|
pendingRequests.set(id, { resolve, reject, timer });
|
|
367
459
|
|
|
368
460
|
codexProcess.stdin.write(JSON.stringify(request) + '\n');
|
|
@@ -454,6 +546,7 @@ export async function createCodexEngine(options = {}) {
|
|
|
454
546
|
|
|
455
547
|
const reqId = requestId + 1;
|
|
456
548
|
let fullResponse = '';
|
|
549
|
+
let rawFinalMessageCount = 0, rawFinalPartCount = 0, rawFinalBytes = 0;
|
|
457
550
|
let gotSessionId = false;
|
|
458
551
|
const collector = governedProfile ? createGovernedNativeCollector(governedProfile) : null;
|
|
459
552
|
let evidenceFailure = null;
|
|
@@ -484,9 +577,22 @@ export async function createCodexEngine(options = {}) {
|
|
|
484
577
|
if (msg.type === 'raw_response_item' && msg.item?.role === 'assistant') {
|
|
485
578
|
const content = msg.item.content;
|
|
486
579
|
if (Array.isArray(content)) {
|
|
487
|
-
|
|
488
|
-
if (
|
|
489
|
-
|
|
580
|
+
if (governedProfile) {
|
|
581
|
+
if (msg.item.phase === 'final_answer') {
|
|
582
|
+
rawFinalMessageCount++;
|
|
583
|
+
for (const part of content) {
|
|
584
|
+
if (part.type === 'output_text') {
|
|
585
|
+
rawFinalPartCount++;
|
|
586
|
+
if (typeof part.text === 'string') rawFinalBytes += Buffer.byteLength(part.text, 'utf8');
|
|
587
|
+
if (part.text) fullResponse += part.text;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
} else {
|
|
592
|
+
for (const part of content) {
|
|
593
|
+
if (part.type === 'text' && part.text) {
|
|
594
|
+
fullResponse += part.text;
|
|
595
|
+
}
|
|
490
596
|
}
|
|
491
597
|
}
|
|
492
598
|
}
|
|
@@ -524,14 +630,14 @@ export async function createCodexEngine(options = {}) {
|
|
|
524
630
|
}
|
|
525
631
|
try {
|
|
526
632
|
internal = attestGovernedCodexSession({ profile: governedProfile,
|
|
527
|
-
events: governedProfile
|
|
633
|
+
events: governedNativeProfile(governedProfile)
|
|
528
634
|
? [collected.sessionEvent, collected.capabilities.nativeTools] : [collected.sessionEvent] });
|
|
529
635
|
} catch (error) {
|
|
530
636
|
throw normalizeGovernedAnswerFailure(error, 'native_event_grammar', 'live_envelope_session',
|
|
531
637
|
'attestation');
|
|
532
638
|
}
|
|
533
639
|
try {
|
|
534
|
-
probeMcpCallCount = governedProfile
|
|
640
|
+
probeMcpCallCount = governedNativeProfile(governedProfile)
|
|
535
641
|
? governedProbeMcpCallCount(mcpServer?.getGovernedCallEvidence()) : 0;
|
|
536
642
|
} catch (error) {
|
|
537
643
|
throw normalizeGovernedAnswerFailure(error, 'native_event_grammar', 'live_envelope_session',
|
|
@@ -555,9 +661,24 @@ export async function createCodexEngine(options = {}) {
|
|
|
555
661
|
}
|
|
556
662
|
|
|
557
663
|
// Parse result
|
|
664
|
+
let resultHasText = false;
|
|
665
|
+
let resultUsableTextItemCount = 0, resultUsableTextBytes = 0, resultSelectedChunkCount = 0;
|
|
666
|
+
let resultUsableText = '';
|
|
667
|
+
let candidateBoundary = null;
|
|
558
668
|
if (result && result.content && Array.isArray(result.content)) {
|
|
559
669
|
for (const item of result.content) {
|
|
670
|
+
if (governedProfile && item.type === 'text' &&
|
|
671
|
+
(typeof item.text === 'string' || item.text)) {
|
|
672
|
+
const selectedText = String(item.text);
|
|
673
|
+
resultUsableTextItemCount++;
|
|
674
|
+
resultUsableTextBytes += Buffer.byteLength(selectedText, 'utf8');
|
|
675
|
+
if (item.text) {
|
|
676
|
+
resultSelectedChunkCount++;
|
|
677
|
+
resultUsableText += selectedText;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
560
680
|
if (item.type === 'text' && item.text) {
|
|
681
|
+
resultHasText = true;
|
|
561
682
|
yield {
|
|
562
683
|
type: 'text',
|
|
563
684
|
content: item.text
|
|
@@ -568,14 +689,29 @@ export async function createCodexEngine(options = {}) {
|
|
|
568
689
|
}
|
|
569
690
|
|
|
570
691
|
// If we got a response from events but not from result, yield it
|
|
571
|
-
if (fullResponse && (!result.content || result.content.length === 0)) {
|
|
692
|
+
if (fullResponse && (governedProfile ? !resultHasText : (!result.content || result.content.length === 0))) {
|
|
572
693
|
yield {
|
|
573
694
|
type: 'text',
|
|
574
695
|
content: fullResponse
|
|
575
696
|
};
|
|
576
697
|
}
|
|
577
698
|
|
|
578
|
-
if (governedProfile
|
|
699
|
+
if (governedProfile) {
|
|
700
|
+
const selectedOrigin = resultHasText ? 'result_content' : fullResponse ? 'raw_final' : 'none';
|
|
701
|
+
const selectedChunk = resultHasText ? resultUsableText : fullResponse;
|
|
702
|
+
candidateBoundary = Object.freeze({
|
|
703
|
+
selectedOrigin,
|
|
704
|
+
selectedChunkCount: resultHasText ? resultSelectedChunkCount : fullResponse ? 1 : 0,
|
|
705
|
+
selectedBytes: Buffer.byteLength(selectedChunk, 'utf8'),
|
|
706
|
+
resultTextItemCount: resultUsableTextItemCount,
|
|
707
|
+
resultTextBytes: resultUsableTextBytes,
|
|
708
|
+
rawFinalMessageCount,
|
|
709
|
+
rawFinalPartCount,
|
|
710
|
+
rawFinalBytes,
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
if (governedNativeProfile(governedProfile)) {
|
|
579
715
|
yield { type: 'toolBatch', total: attestation.observed.nativeTools.total,
|
|
580
716
|
tools: attestation.observed.nativeTools.tools.map((item) => ({ ...item })) };
|
|
581
717
|
}
|
|
@@ -584,7 +720,7 @@ export async function createCodexEngine(options = {}) {
|
|
|
584
720
|
|
|
585
721
|
yield {
|
|
586
722
|
type: 'metadata',
|
|
587
|
-
data: governedProfile ? { attestation } : {
|
|
723
|
+
data: governedProfile ? { attestation, candidateBoundary } : {
|
|
588
724
|
sessionId: session.id,
|
|
589
725
|
conversationId: session.conversationId,
|
|
590
726
|
messageCount: session.messageCount
|
|
@@ -603,10 +739,11 @@ export async function createCodexEngine(options = {}) {
|
|
|
603
739
|
};
|
|
604
740
|
} finally {
|
|
605
741
|
if (opts.abortSignal && abortHandler) opts.abortSignal.removeEventListener('abort', abortHandler);
|
|
606
|
-
if (governedProfile) {
|
|
607
|
-
try { await cleanup(); }
|
|
742
|
+
if (governedProfile || queryError) {
|
|
743
|
+
try { await cleanup(queryError || undefined); }
|
|
608
744
|
catch (cleanupError) {
|
|
609
|
-
|
|
745
|
+
// Preserve the original query failure when process cleanup also fails.
|
|
746
|
+
if (!queryError && governedProfile) throw normalizeGovernedAnswerFailure(cleanupError, 'provider_engine', null, null,
|
|
610
747
|
null, null, null, 'close');
|
|
611
748
|
}
|
|
612
749
|
}
|