@ccpocket/bridge 1.68.2 → 1.69.1
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/dist/codex-process.d.ts +25 -0
- package/dist/codex-process.js +191 -27
- package/dist/codex-process.js.map +1 -1
- package/dist/parser.d.ts +5 -0
- package/dist/parser.js.map +1 -1
- package/dist/sessions-index.js +4 -0
- package/dist/sessions-index.js.map +1 -1
- package/dist/websocket.d.ts +5 -0
- package/dist/websocket.js +178 -68
- package/dist/websocket.js.map +1 -1
- package/package.json +1 -1
package/dist/codex-process.d.ts
CHANGED
|
@@ -16,6 +16,11 @@ export interface CodexStartOptions {
|
|
|
16
16
|
networkAccessEnabled?: boolean;
|
|
17
17
|
webSearchMode?: "disabled" | "cached" | "live";
|
|
18
18
|
collaborationMode?: "plan" | "default";
|
|
19
|
+
/**
|
|
20
|
+
* Managed Browser Use policy cached by Bridge metadata loading.
|
|
21
|
+
* `null` means app-server must read the policy before starting the thread.
|
|
22
|
+
*/
|
|
23
|
+
autoReviewDisabledByPolicy?: boolean | null;
|
|
19
24
|
}
|
|
20
25
|
export interface CodexProcessEvents {
|
|
21
26
|
message: [ServerMessage];
|
|
@@ -73,10 +78,25 @@ export interface CodexThreadSummary {
|
|
|
73
78
|
name: string | null;
|
|
74
79
|
}
|
|
75
80
|
export type CodexThreadSourceKind = "cli" | "vscode" | "exec" | "appServer" | "subAgent" | "subAgentReview" | "subAgentCompact" | "subAgentThreadSpawn" | "subAgentOther" | "unknown";
|
|
81
|
+
export declare class CodexRpcError extends Error {
|
|
82
|
+
readonly method: string;
|
|
83
|
+
readonly code: number | undefined;
|
|
84
|
+
readonly data: unknown;
|
|
85
|
+
constructor(method: string, error: {
|
|
86
|
+
code?: number;
|
|
87
|
+
message?: string;
|
|
88
|
+
data?: unknown;
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
export declare function isCodexThreadWriterConflict(error: unknown): boolean;
|
|
92
|
+
export declare function codexErrorMessage(error: unknown): string;
|
|
76
93
|
export interface CodexProfileConfig {
|
|
77
94
|
profiles: string[];
|
|
78
95
|
defaultProfile?: string;
|
|
79
96
|
}
|
|
97
|
+
export interface CodexConfigRequirements {
|
|
98
|
+
autoReviewDisabled: boolean;
|
|
99
|
+
}
|
|
80
100
|
export interface CodexModelMetadata {
|
|
81
101
|
model: string;
|
|
82
102
|
supportedReasoningEfforts: string[];
|
|
@@ -120,6 +140,7 @@ export declare class CodexProcess extends EventEmitter<CodexProcessEvents> {
|
|
|
120
140
|
private _approvalPolicy;
|
|
121
141
|
private _approvalsReviewer;
|
|
122
142
|
private _codexPermissionsMode;
|
|
143
|
+
private _autoReviewDisabledByPolicy;
|
|
123
144
|
private _collaborationMode;
|
|
124
145
|
private _runtimeModel;
|
|
125
146
|
private _runtimeModelReasoningEffort;
|
|
@@ -129,6 +150,8 @@ export declare class CodexProcess extends EventEmitter<CodexProcessEvents> {
|
|
|
129
150
|
private lastResultText;
|
|
130
151
|
/** Agent text received as deltas but not yet confirmed by item/completed. */
|
|
131
152
|
private readonly pendingAgentTextByItemId;
|
|
153
|
+
/** Agent text confirmed by item/completed during the active turn. */
|
|
154
|
+
private readonly confirmedAgentTextByItemId;
|
|
132
155
|
/** Suppresses late item/completed events after synthetic fallbacks. */
|
|
133
156
|
private readonly syntheticAgentTextByItemId;
|
|
134
157
|
private pendingPlanCompletion;
|
|
@@ -300,6 +323,7 @@ export declare class CodexProcess extends EventEmitter<CodexProcessEvents> {
|
|
|
300
323
|
private resolveWritableRootsConfig;
|
|
301
324
|
private initializeRpcConnection;
|
|
302
325
|
readProfileConfig(cwd?: string): Promise<CodexProfileConfig>;
|
|
326
|
+
readConfigRequirements(): Promise<CodexConfigRequirements>;
|
|
303
327
|
private fetchCompletionEntities;
|
|
304
328
|
private scheduleCompletionFetchFromNotification;
|
|
305
329
|
private _fetchCompletionEntitiesInternal;
|
|
@@ -312,6 +336,7 @@ export declare class CodexProcess extends EventEmitter<CodexProcessEvents> {
|
|
|
312
336
|
private handleNotification;
|
|
313
337
|
private isForeignThreadNotification;
|
|
314
338
|
private handleTurnCompleted;
|
|
339
|
+
private prepareTurnCompletionAgentSummary;
|
|
315
340
|
private finalizePendingAgentText;
|
|
316
341
|
private cleanupSteerTempPaths;
|
|
317
342
|
private processItemStarted;
|
package/dist/codex-process.js
CHANGED
|
@@ -11,6 +11,29 @@ const DEFAULT_CODEX_MODEL = "gpt-5.5";
|
|
|
11
11
|
const COMPLETION_FETCH_COOLDOWN_MS = 1000;
|
|
12
12
|
const UNKNOWN_AGENT_ITEM_ID = "__unknown_agent_message__";
|
|
13
13
|
const CODEX_CLI_NOT_FOUND_MESSAGE = "Codex CLI is not installed or not available on PATH on the Bridge machine. Install it with `curl -fsSL https://chatgpt.com/codex/install.sh | sh`, then restart Bridge.";
|
|
14
|
+
export class CodexRpcError extends Error {
|
|
15
|
+
method;
|
|
16
|
+
code;
|
|
17
|
+
data;
|
|
18
|
+
constructor(method, error) {
|
|
19
|
+
super(error.message ?? `RPC error ${error.code ?? ""}`.trim());
|
|
20
|
+
this.name = "CodexRpcError";
|
|
21
|
+
this.method = method;
|
|
22
|
+
this.code = error.code;
|
|
23
|
+
this.data = error.data;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export function isCodexThreadWriterConflict(error) {
|
|
27
|
+
return (error instanceof CodexRpcError &&
|
|
28
|
+
error.code === -32600 &&
|
|
29
|
+
/\b(active|live local)\s+writer\b/i.test(error.message));
|
|
30
|
+
}
|
|
31
|
+
export function codexErrorMessage(error) {
|
|
32
|
+
if (isCodexThreadWriterConflict(error)) {
|
|
33
|
+
return "This Codex thread is already open in another client. Close it there and try again.";
|
|
34
|
+
}
|
|
35
|
+
return error instanceof Error ? error.message : String(error);
|
|
36
|
+
}
|
|
14
37
|
function isCodexCliNotFoundError(err) {
|
|
15
38
|
const code = err.code;
|
|
16
39
|
return (code === "ENOENT" ||
|
|
@@ -71,6 +94,7 @@ export class CodexProcess extends EventEmitter {
|
|
|
71
94
|
_approvalPolicy = undefined;
|
|
72
95
|
_approvalsReviewer = undefined;
|
|
73
96
|
_codexPermissionsMode;
|
|
97
|
+
_autoReviewDisabledByPolicy = false;
|
|
74
98
|
_collaborationMode = "default";
|
|
75
99
|
_runtimeModel;
|
|
76
100
|
_runtimeModelReasoningEffort;
|
|
@@ -80,6 +104,8 @@ export class CodexProcess extends EventEmitter {
|
|
|
80
104
|
lastResultText = null;
|
|
81
105
|
/** Agent text received as deltas but not yet confirmed by item/completed. */
|
|
82
106
|
pendingAgentTextByItemId = new Map();
|
|
107
|
+
/** Agent text confirmed by item/completed during the active turn. */
|
|
108
|
+
confirmedAgentTextByItemId = new Map();
|
|
83
109
|
/** Suppresses late item/completed events after synthetic fallbacks. */
|
|
84
110
|
syntheticAgentTextByItemId = new Map();
|
|
85
111
|
pendingPlanCompletion = null;
|
|
@@ -169,7 +195,9 @@ export class CodexProcess extends EventEmitter {
|
|
|
169
195
|
* Takes effect on the next `turn/start` RPC call.
|
|
170
196
|
*/
|
|
171
197
|
setApprovalsReviewer(reviewer) {
|
|
172
|
-
this._approvalsReviewer =
|
|
198
|
+
this._approvalsReviewer = this._autoReviewDisabledByPolicy
|
|
199
|
+
? "user"
|
|
200
|
+
: normalizeApprovalsReviewerForAppServer(reviewer);
|
|
173
201
|
console.log(`[codex-process] Approvals reviewer changed to: ${this.approvalsReviewer}`);
|
|
174
202
|
}
|
|
175
203
|
/**
|
|
@@ -425,6 +453,8 @@ export class CodexProcess extends EventEmitter {
|
|
|
425
453
|
? undefined
|
|
426
454
|
: normalizeApprovalsReviewerForAppServer(options.approvalsReviewer);
|
|
427
455
|
this._codexPermissionsMode = options?.codexPermissionsMode;
|
|
456
|
+
this._autoReviewDisabledByPolicy =
|
|
457
|
+
options?.autoReviewDisabledByPolicy === true;
|
|
428
458
|
this._collaborationMode = options?.collaborationMode ?? "default";
|
|
429
459
|
this.lastPlanItemText = null;
|
|
430
460
|
this.lastResultText = null;
|
|
@@ -434,6 +464,7 @@ export class CodexProcess extends EventEmitter {
|
|
|
434
464
|
this._lastCompletionEntitiesSignature = null;
|
|
435
465
|
this._launchStartedAt = Date.now();
|
|
436
466
|
this.pendingAgentTextByItemId.clear();
|
|
467
|
+
this.confirmedAgentTextByItemId.clear();
|
|
437
468
|
this.syntheticAgentTextByItemId.clear();
|
|
438
469
|
this.pendingPlanCompletion = null;
|
|
439
470
|
this._pendingPlanInput = null;
|
|
@@ -888,13 +919,31 @@ export class CodexProcess extends EventEmitter {
|
|
|
888
919
|
async bootstrap(projectPath, options) {
|
|
889
920
|
try {
|
|
890
921
|
await this.initializeRpcConnection();
|
|
922
|
+
const autoReviewDisabled = options?.autoReviewDisabledByPolicy === null
|
|
923
|
+
? (await this.readConfigRequirements()).autoReviewDisabled
|
|
924
|
+
: options?.autoReviewDisabledByPolicy === true;
|
|
925
|
+
this._autoReviewDisabledByPolicy = autoReviewDisabled;
|
|
926
|
+
const effectiveApprovalsReviewer = autoReviewDisabled
|
|
927
|
+
? "user"
|
|
928
|
+
: options?.approvalsReviewer;
|
|
929
|
+
const effectiveCodexPermissionsMode = autoReviewDisabled && options?.codexPermissionsMode === "autoReview"
|
|
930
|
+
? "default"
|
|
931
|
+
: options?.codexPermissionsMode;
|
|
932
|
+
if (autoReviewDisabled) {
|
|
933
|
+
console.warn("[codex-process] Auto-review disabled by managed Browser Use policy");
|
|
934
|
+
}
|
|
935
|
+
this._approvalsReviewer =
|
|
936
|
+
effectiveApprovalsReviewer === undefined
|
|
937
|
+
? undefined
|
|
938
|
+
: normalizeApprovalsReviewerForAppServer(effectiveApprovalsReviewer);
|
|
939
|
+
this._codexPermissionsMode = effectiveCodexPermissionsMode;
|
|
891
940
|
const requestedApprovalPolicy = options?.approvalPolicy
|
|
892
941
|
? normalizeApprovalPolicy(options.approvalPolicy)
|
|
893
942
|
: undefined;
|
|
894
|
-
const requestedApprovalsReviewer =
|
|
943
|
+
const requestedApprovalsReviewer = effectiveApprovalsReviewer === undefined
|
|
895
944
|
? undefined
|
|
896
|
-
: normalizeApprovalsReviewerForAppServer(
|
|
897
|
-
const requestedClientApprovalsReviewer = normalizeApprovalsReviewerForClient(
|
|
945
|
+
: normalizeApprovalsReviewerForAppServer(effectiveApprovalsReviewer);
|
|
946
|
+
const requestedClientApprovalsReviewer = normalizeApprovalsReviewerForClient(effectiveApprovalsReviewer);
|
|
898
947
|
const requestedSandboxMode = options?.sandboxMode
|
|
899
948
|
? normalizeSandboxMode(options.sandboxMode)
|
|
900
949
|
: undefined;
|
|
@@ -970,14 +1019,17 @@ export class CodexProcess extends EventEmitter {
|
|
|
970
1019
|
this.startModel = thread.model;
|
|
971
1020
|
}
|
|
972
1021
|
const resolvedSettings = extractResolvedSettingsFromThreadResponse(response);
|
|
1022
|
+
const resolvedApprovalsReviewer = autoReviewDisabled
|
|
1023
|
+
? "user"
|
|
1024
|
+
: resolvedSettings.approvalsReviewer;
|
|
973
1025
|
if (resolvedSettings.model) {
|
|
974
1026
|
this.startModel = resolvedSettings.model;
|
|
975
1027
|
}
|
|
976
1028
|
if (resolvedSettings.approvalPolicy) {
|
|
977
1029
|
this._approvalPolicy = resolvedSettings.approvalPolicy;
|
|
978
1030
|
}
|
|
979
|
-
if (
|
|
980
|
-
this._approvalsReviewer = normalizeApprovalsReviewerForAppServer(
|
|
1031
|
+
if (resolvedApprovalsReviewer) {
|
|
1032
|
+
this._approvalsReviewer = normalizeApprovalsReviewerForAppServer(resolvedApprovalsReviewer);
|
|
981
1033
|
}
|
|
982
1034
|
this._threadId = threadId;
|
|
983
1035
|
this._agentNickname = stringOrNull(thread?.agentNickname);
|
|
@@ -996,18 +1048,18 @@ export class CodexProcess extends EventEmitter {
|
|
|
996
1048
|
approvalPolicy: resolvedSettings.approvalPolicy ?? requestedApprovalPolicy,
|
|
997
1049
|
}
|
|
998
1050
|
: {}),
|
|
999
|
-
...(
|
|
1051
|
+
...(resolvedApprovalsReviewer ?? effectiveApprovalsReviewer
|
|
1000
1052
|
? {
|
|
1001
|
-
approvalsReviewer:
|
|
1002
|
-
? normalizeApprovalsReviewerForClient(
|
|
1053
|
+
approvalsReviewer: resolvedApprovalsReviewer
|
|
1054
|
+
? normalizeApprovalsReviewerForClient(resolvedApprovalsReviewer)
|
|
1003
1055
|
: requestedClientApprovalsReviewer,
|
|
1004
1056
|
}
|
|
1005
1057
|
: {}),
|
|
1006
1058
|
...(resolvedSettings.sandboxMode ?? options?.sandboxMode
|
|
1007
1059
|
? { sandboxMode: resolvedSettings.sandboxMode ?? requestedSandboxMode }
|
|
1008
1060
|
: {}),
|
|
1009
|
-
...(
|
|
1010
|
-
? { codexPermissionsMode:
|
|
1061
|
+
...(effectiveCodexPermissionsMode
|
|
1062
|
+
? { codexPermissionsMode: effectiveCodexPermissionsMode }
|
|
1011
1063
|
: {}),
|
|
1012
1064
|
...(resolvedSettings.modelReasoningEffort
|
|
1013
1065
|
? { modelReasoningEffort: resolvedSettings.modelReasoningEffort }
|
|
@@ -1038,7 +1090,7 @@ export class CodexProcess extends EventEmitter {
|
|
|
1038
1090
|
}
|
|
1039
1091
|
catch (err) {
|
|
1040
1092
|
if (!this.stopped) {
|
|
1041
|
-
const message =
|
|
1093
|
+
const message = codexErrorMessage(err);
|
|
1042
1094
|
console.error("[codex-process] bootstrap error:", err);
|
|
1043
1095
|
this.emitMessage({ type: "error", message: `Codex error: ${message}` });
|
|
1044
1096
|
this.emitMessage({
|
|
@@ -1090,6 +1142,23 @@ export class CodexProcess extends EventEmitter {
|
|
|
1090
1142
|
: undefined,
|
|
1091
1143
|
};
|
|
1092
1144
|
}
|
|
1145
|
+
async readConfigRequirements() {
|
|
1146
|
+
try {
|
|
1147
|
+
const response = (await this.request("configRequirements/read"));
|
|
1148
|
+
const requirements = asRecord(response.requirements);
|
|
1149
|
+
const browserUse = asRecord(requirements?.browserUse ?? requirements?.browser_use);
|
|
1150
|
+
return {
|
|
1151
|
+
autoReviewDisabled: (browserUse?.disableAutoReview ??
|
|
1152
|
+
browserUse?.disable_auto_review) === true,
|
|
1153
|
+
};
|
|
1154
|
+
}
|
|
1155
|
+
catch (err) {
|
|
1156
|
+
if (err instanceof CodexRpcError && err.code === -32601) {
|
|
1157
|
+
return { autoReviewDisabled: false };
|
|
1158
|
+
}
|
|
1159
|
+
throw err;
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1093
1162
|
async fetchCompletionEntities(projectPath) {
|
|
1094
1163
|
if (this._completionFetchInFlight) {
|
|
1095
1164
|
return this._completionFetchInFlight;
|
|
@@ -1403,8 +1472,7 @@ export class CodexProcess extends EventEmitter {
|
|
|
1403
1472
|
return;
|
|
1404
1473
|
this.pendingRpc.delete(envelope.id);
|
|
1405
1474
|
if ("error" in envelope && envelope.error) {
|
|
1406
|
-
|
|
1407
|
-
pending.reject(new Error(message));
|
|
1475
|
+
pending.reject(new CodexRpcError(pending.method, envelope.error));
|
|
1408
1476
|
return;
|
|
1409
1477
|
}
|
|
1410
1478
|
pending.resolve(envelope.result);
|
|
@@ -1606,6 +1674,7 @@ export class CodexProcess extends EventEmitter {
|
|
|
1606
1674
|
}
|
|
1607
1675
|
this.lastResultText = null;
|
|
1608
1676
|
this.pendingAgentTextByItemId.clear();
|
|
1677
|
+
this.confirmedAgentTextByItemId.clear();
|
|
1609
1678
|
this.syntheticAgentTextByItemId.clear();
|
|
1610
1679
|
this.setStatus("running");
|
|
1611
1680
|
break;
|
|
@@ -1737,10 +1806,24 @@ export class CodexProcess extends EventEmitter {
|
|
|
1737
1806
|
const message = stringValue(params.message);
|
|
1738
1807
|
if (!message)
|
|
1739
1808
|
break;
|
|
1740
|
-
|
|
1809
|
+
const approval = parseGuardianApproval(message);
|
|
1810
|
+
if (approval?.risk === "low" &&
|
|
1811
|
+
isLowRiskAllowDecision(approval.reason)) {
|
|
1741
1812
|
console.debug("[codex-process] suppressed informational guardian approval notification");
|
|
1742
1813
|
break;
|
|
1743
1814
|
}
|
|
1815
|
+
if (approval &&
|
|
1816
|
+
(approval.risk === "medium" || approval.risk === "high")) {
|
|
1817
|
+
this.emitMessage({
|
|
1818
|
+
type: "guardian_approval",
|
|
1819
|
+
risk: approval.risk,
|
|
1820
|
+
reason: approval.reason,
|
|
1821
|
+
...(approval.authorization
|
|
1822
|
+
? { authorization: approval.authorization }
|
|
1823
|
+
: {}),
|
|
1824
|
+
});
|
|
1825
|
+
break;
|
|
1826
|
+
}
|
|
1744
1827
|
this.emitMessage({
|
|
1745
1828
|
type: "error",
|
|
1746
1829
|
errorCode: "codex_warning",
|
|
@@ -1791,7 +1874,11 @@ export class CodexProcess extends EventEmitter {
|
|
|
1791
1874
|
}
|
|
1792
1875
|
handleTurnCompleted(turn) {
|
|
1793
1876
|
const status = String(turn?.status ?? "completed");
|
|
1877
|
+
if (status === "completed") {
|
|
1878
|
+
this.prepareTurnCompletionAgentSummary(turn);
|
|
1879
|
+
}
|
|
1794
1880
|
this.finalizePendingAgentText();
|
|
1881
|
+
this.confirmedAgentTextByItemId.clear();
|
|
1795
1882
|
const usage = this.lastTokenUsage;
|
|
1796
1883
|
this.lastTokenUsage = null;
|
|
1797
1884
|
if (status === "failed") {
|
|
@@ -1857,6 +1944,41 @@ export class CodexProcess extends EventEmitter {
|
|
|
1857
1944
|
}
|
|
1858
1945
|
this.cleanupSteerTempPaths();
|
|
1859
1946
|
}
|
|
1947
|
+
prepareTurnCompletionAgentSummary(turn) {
|
|
1948
|
+
if (turn?.itemsView !== "summary" || !Array.isArray(turn.items))
|
|
1949
|
+
return;
|
|
1950
|
+
const summaryItem = [...turn.items]
|
|
1951
|
+
.reverse()
|
|
1952
|
+
.find((item) => typeof item === "object" &&
|
|
1953
|
+
item !== null &&
|
|
1954
|
+
normalizeItemType(item.type) ===
|
|
1955
|
+
"agentmessage" &&
|
|
1956
|
+
Boolean(extractAgentText(item)?.trim()));
|
|
1957
|
+
if (!summaryItem)
|
|
1958
|
+
return;
|
|
1959
|
+
const itemId = typeof summaryItem.id === "string"
|
|
1960
|
+
? summaryItem.id
|
|
1961
|
+
: UNKNOWN_AGENT_ITEM_ID;
|
|
1962
|
+
const summaryText = extractAgentText(summaryItem);
|
|
1963
|
+
if (!summaryText?.trim())
|
|
1964
|
+
return;
|
|
1965
|
+
const confirmedText = this.confirmedAgentTextByItemId.get(itemId);
|
|
1966
|
+
if (confirmedText !== undefined) {
|
|
1967
|
+
this.pendingAgentTextByItemId.delete(itemId);
|
|
1968
|
+
this.lastResultText = confirmedText;
|
|
1969
|
+
return;
|
|
1970
|
+
}
|
|
1971
|
+
if (itemId !== UNKNOWN_AGENT_ITEM_ID &&
|
|
1972
|
+
!this.pendingAgentTextByItemId.has(itemId)) {
|
|
1973
|
+
const unknownText = this.pendingAgentTextByItemId.get(UNKNOWN_AGENT_ITEM_ID);
|
|
1974
|
+
if (unknownText &&
|
|
1975
|
+
(summaryText.startsWith(unknownText) ||
|
|
1976
|
+
unknownText.startsWith(summaryText))) {
|
|
1977
|
+
this.pendingAgentTextByItemId.delete(UNKNOWN_AGENT_ITEM_ID);
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
this.pendingAgentTextByItemId.set(itemId, summaryText);
|
|
1981
|
+
}
|
|
1860
1982
|
finalizePendingAgentText() {
|
|
1861
1983
|
const pendingItems = [...this.pendingAgentTextByItemId.entries()];
|
|
1862
1984
|
this.pendingAgentTextByItemId.clear();
|
|
@@ -1888,11 +2010,6 @@ export class CodexProcess extends EventEmitter {
|
|
|
1888
2010
|
const itemType = normalizeItemType(item.type);
|
|
1889
2011
|
switch (itemType) {
|
|
1890
2012
|
case "commandexecution": {
|
|
1891
|
-
const commandText = typeof item.command === "string"
|
|
1892
|
-
? item.command
|
|
1893
|
-
: Array.isArray(item.command)
|
|
1894
|
-
? item.command.map((part) => String(part)).join(" ")
|
|
1895
|
-
: "";
|
|
1896
2013
|
this.emitMessage({
|
|
1897
2014
|
type: "assistant",
|
|
1898
2015
|
message: {
|
|
@@ -1903,7 +2020,7 @@ export class CodexProcess extends EventEmitter {
|
|
|
1903
2020
|
type: "tool_use",
|
|
1904
2021
|
id: itemId,
|
|
1905
2022
|
name: "Bash",
|
|
1906
|
-
input:
|
|
2023
|
+
input: commandExecutionToolUseInput(item),
|
|
1907
2024
|
},
|
|
1908
2025
|
],
|
|
1909
2026
|
model: this.getMessageModel(),
|
|
@@ -2021,13 +2138,20 @@ export class CodexProcess extends EventEmitter {
|
|
|
2021
2138
|
const completedText = extractAgentText(item);
|
|
2022
2139
|
const hasCompletedText = completedText?.trim().length > 0;
|
|
2023
2140
|
const directPendingText = this.pendingAgentTextByItemId.get(itemId);
|
|
2141
|
+
const unknownPendingText = directPendingText === undefined
|
|
2142
|
+
? this.pendingAgentTextByItemId.get(UNKNOWN_AGENT_ITEM_ID)
|
|
2143
|
+
: undefined;
|
|
2024
2144
|
const usedUnknownPendingText = !hasCompletedText && directPendingText === undefined;
|
|
2145
|
+
const matchedUnknownPendingText = hasCompletedText &&
|
|
2146
|
+
Boolean(unknownPendingText &&
|
|
2147
|
+
(completedText?.startsWith(unknownPendingText) ||
|
|
2148
|
+
unknownPendingText.startsWith(completedText ?? "")));
|
|
2025
2149
|
const pendingText = usedUnknownPendingText
|
|
2026
|
-
? (
|
|
2150
|
+
? (unknownPendingText ?? "")
|
|
2027
2151
|
: (directPendingText ?? "");
|
|
2028
2152
|
const text = hasCompletedText ? completedText : pendingText;
|
|
2029
2153
|
this.pendingAgentTextByItemId.delete(itemId);
|
|
2030
|
-
if (usedUnknownPendingText) {
|
|
2154
|
+
if (usedUnknownPendingText || matchedUnknownPendingText) {
|
|
2031
2155
|
this.pendingAgentTextByItemId.delete(UNKNOWN_AGENT_ITEM_ID);
|
|
2032
2156
|
}
|
|
2033
2157
|
if (!text.trim())
|
|
@@ -2047,6 +2171,7 @@ export class CodexProcess extends EventEmitter {
|
|
|
2047
2171
|
}
|
|
2048
2172
|
}
|
|
2049
2173
|
this.syntheticAgentTextByItemId.delete(itemId);
|
|
2174
|
+
this.confirmedAgentTextByItemId.set(itemId, text);
|
|
2050
2175
|
this.lastResultText = text;
|
|
2051
2176
|
this.emitMessage({
|
|
2052
2177
|
type: "assistant",
|
|
@@ -2293,7 +2418,7 @@ export class CodexProcess extends EventEmitter {
|
|
|
2293
2418
|
}
|
|
2294
2419
|
request(method, params) {
|
|
2295
2420
|
const id = this.rpcSeq++;
|
|
2296
|
-
const envelope = { id, method, params };
|
|
2421
|
+
const envelope = params === undefined ? { id, method } : { id, method, params };
|
|
2297
2422
|
return new Promise((resolve, reject) => {
|
|
2298
2423
|
this.pendingRpc.set(id, { resolve, reject, method });
|
|
2299
2424
|
try {
|
|
@@ -2736,6 +2861,20 @@ function toToolUseInput(value) {
|
|
|
2736
2861
|
}
|
|
2737
2862
|
return { value };
|
|
2738
2863
|
}
|
|
2864
|
+
function commandExecutionToolUseInput(item) {
|
|
2865
|
+
const command = typeof item.command === "string"
|
|
2866
|
+
? item.command
|
|
2867
|
+
: Array.isArray(item.command)
|
|
2868
|
+
? item.command.map((part) => String(part)).join(" ")
|
|
2869
|
+
: "";
|
|
2870
|
+
const pluginId = stringOrNull(item.pluginId ?? item.plugin_id);
|
|
2871
|
+
const scriptPath = stringOrNull(item.scriptPath ?? item.script_path);
|
|
2872
|
+
return {
|
|
2873
|
+
command,
|
|
2874
|
+
...(pluginId ? { pluginId } : {}),
|
|
2875
|
+
...(scriptPath ? { scriptPath } : {}),
|
|
2876
|
+
};
|
|
2877
|
+
}
|
|
2739
2878
|
function toImageGenerationToolInput(item) {
|
|
2740
2879
|
const input = {};
|
|
2741
2880
|
const status = typeof item.status === "string" ? item.status : undefined;
|
|
@@ -3040,9 +3179,34 @@ function parseResultObject(rawResult) {
|
|
|
3040
3179
|
return { byId: {}, byQuestion: {} };
|
|
3041
3180
|
}
|
|
3042
3181
|
}
|
|
3043
|
-
function
|
|
3044
|
-
const
|
|
3045
|
-
|
|
3182
|
+
function parseGuardianApproval(message) {
|
|
3183
|
+
const match = message
|
|
3184
|
+
.trim()
|
|
3185
|
+
.match(/^automatic approval review approved\s*\(([^)]*)\)\s*:\s*([\s\S]+)$/i);
|
|
3186
|
+
if (!match)
|
|
3187
|
+
return null;
|
|
3188
|
+
const metadata = new Map();
|
|
3189
|
+
for (const field of match[1].split(",")) {
|
|
3190
|
+
const separator = field.indexOf(":");
|
|
3191
|
+
if (separator === -1)
|
|
3192
|
+
continue;
|
|
3193
|
+
metadata.set(field.slice(0, separator).trim().toLowerCase(), field.slice(separator + 1).trim());
|
|
3194
|
+
}
|
|
3195
|
+
const risk = metadata.get("risk")?.toLowerCase();
|
|
3196
|
+
const reason = match[2].trim();
|
|
3197
|
+
if (!reason || (risk !== "low" && risk !== "medium" && risk !== "high")) {
|
|
3198
|
+
return null;
|
|
3199
|
+
}
|
|
3200
|
+
const authorization = metadata.get("authorization");
|
|
3201
|
+
return {
|
|
3202
|
+
risk,
|
|
3203
|
+
reason,
|
|
3204
|
+
...(authorization ? { authorization } : {}),
|
|
3205
|
+
};
|
|
3206
|
+
}
|
|
3207
|
+
function isLowRiskAllowDecision(reason) {
|
|
3208
|
+
const normalized = reason.trim().replace(/\s+/g, " ");
|
|
3209
|
+
return /^auto-review returned a low[- ]risk allow decision\.?$/i.test(normalized);
|
|
3046
3210
|
}
|
|
3047
3211
|
function normalizeAnswerValues(value) {
|
|
3048
3212
|
if (typeof value === "string") {
|