@yansigit/opencodex 2.35.1-dev.20260828.1 → 2.35.1-dev.20260828.12

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.
@@ -0,0 +1,233 @@
1
+ import { isDeepStrictEqual } from "node:util";
2
+ import type { OcxParsedRequest, OcxTool } from "../../types";
3
+ import type { SsePayloadRewrite } from "../sse-payload-rewrite";
4
+
5
+ const MIRROR_NAMESPACE = "ocx_agents";
6
+ const NATIVE_NAMESPACE = "collaboration";
7
+ const MIRRORED_NAMES = new Set(["spawn_agent", "send_message", "followup_task"]);
8
+ const GUIDANCE = "Use this routed-child mirror for collaboration operations.";
9
+ const MAX_SSE_BINDINGS = 128;
10
+
11
+ type RecordValue = Record<string, unknown>;
12
+
13
+ export interface V2RoutedDelegationBridgeContext {
14
+ readonly names: ReadonlySet<string>;
15
+ /** Request snapshot taken before mirror injection, for continuation-cache persistence. */
16
+ readonly requestStateBody: unknown;
17
+ }
18
+
19
+ function isRecord(value: unknown): value is RecordValue {
20
+ return !!value && typeof value === "object" && !Array.isArray(value);
21
+ }
22
+
23
+ function rawToolLists(body: unknown, replayPrefixLength: number): unknown[][] {
24
+ if (!isRecord(body)) return [];
25
+ const lists: unknown[][] = [];
26
+ if (Array.isArray(body.tools)) lists.push(body.tools);
27
+ if (Array.isArray(body.input)) {
28
+ for (const item of body.input.slice(Math.max(0, Math.min(replayPrefixLength, body.input.length)))) {
29
+ if (isRecord(item) && item.type === "additional_tools" && Array.isArray(item.tools)) lists.push(item.tools);
30
+ }
31
+ }
32
+ return lists;
33
+ }
34
+
35
+ function requestStateBody(body: unknown): unknown {
36
+ if (!isRecord(body) || !Array.isArray(body.input)) return body;
37
+ // Only additional_tools containers are mutated below. Clone that narrow path so the
38
+ // continuation cache retains the caller's catalog without copying unrelated context.
39
+ return {
40
+ ...body,
41
+ input: body.input.map(item => (
42
+ isRecord(item) && item.type === "additional_tools" && Array.isArray(item.tools)
43
+ ? { ...item, tools: [...item.tools] }
44
+ : item
45
+ )),
46
+ };
47
+ }
48
+
49
+ function mirrorTool(tool: RecordValue): RecordValue {
50
+ return { ...tool, description: `${GUIDANCE} ${tool.name}.` };
51
+ }
52
+
53
+ function mirrorChildren(group: RecordValue): RecordValue[] {
54
+ if (!Array.isArray(group.tools)) return [];
55
+ return group.tools.filter((tool): tool is RecordValue => (
56
+ isRecord(tool) && tool.type === "function" && typeof tool.name === "string" && MIRRORED_NAMES.has(tool.name)
57
+ )).map(mirrorTool);
58
+ }
59
+
60
+ function mirrorGroup(group: RecordValue): RecordValue {
61
+ return { type: "namespace", name: MIRROR_NAMESPACE, description: GUIDANCE, tools: mirrorChildren(group) };
62
+ }
63
+
64
+ /**
65
+ * Add request-local plaintext collaboration mirrors to raw and parsed Responses catalogs.
66
+ * The caller has already proved this request is eligible; this helper owns no routing policy.
67
+ */
68
+ export function injectV2RoutedDelegationBridge(
69
+ parsed: OcxParsedRequest,
70
+ ): V2RoutedDelegationBridgeContext | undefined {
71
+ const stateBody = requestStateBody(parsed._rawBody);
72
+ const lists = rawToolLists(parsed._rawBody, parsed._replayPrefixLen ?? 0);
73
+ const nativeGroups: Array<{ list: unknown[]; index: number; group: RecordValue }> = [];
74
+ const existing: Array<{ list: unknown[]; index: number; group: RecordValue }> = [];
75
+ for (const list of lists) {
76
+ list.forEach((tool, index) => {
77
+ if (!isRecord(tool) || tool.type !== "namespace") return;
78
+ if (tool.name === NATIVE_NAMESPACE) nativeGroups.push({ list, index, group: tool });
79
+ if (tool.name === MIRROR_NAMESPACE) existing.push({ list, index, group: tool });
80
+ });
81
+ }
82
+ if (nativeGroups.length === 0) return undefined;
83
+
84
+ const names = new Set<string>();
85
+ for (const { group } of nativeGroups) {
86
+ for (const child of mirrorChildren(group)) names.add(child.name as string);
87
+ }
88
+ if (names.size === 0) return undefined;
89
+
90
+ const expected = nativeGroups.map(({ list, index, group }) => ({ list, index: index + 1, group: mirrorGroup(group) }));
91
+ const idempotent = existing.length === expected.length && expected.every(candidate => {
92
+ const actual = candidate.list[candidate.index];
93
+ return isRecord(actual) && isDeepStrictEqual(actual, candidate.group);
94
+ });
95
+ if (existing.length > 0 && !idempotent) {
96
+ throw new Error("v2 routed delegation bridge namespace collision");
97
+ }
98
+ if (!idempotent) {
99
+ for (const { list, index, group } of [...expected].reverse()) list.splice(index, 0, group);
100
+ }
101
+
102
+ const mirrorTools: OcxTool[] = [];
103
+ for (const name of names) {
104
+ const source = parsed.context.tools?.find(tool => tool.namespace === NATIVE_NAMESPACE && tool.name === name);
105
+ if (source) {
106
+ mirrorTools.push({ ...source, namespace: MIRROR_NAMESPACE, description: `${GUIDANCE} ${name}.` });
107
+ continue;
108
+ }
109
+ const raw = nativeGroups.flatMap(entry => mirrorChildren(entry.group)).find(tool => tool.name === name);
110
+ mirrorTools.push({
111
+ name,
112
+ namespace: MIRROR_NAMESPACE,
113
+ description: `${GUIDANCE} ${name}.`,
114
+ parameters: isRecord(raw?.parameters) ? raw.parameters : {},
115
+ });
116
+ }
117
+ if (mirrorTools.length > 0) {
118
+ const present = new Set((parsed.context.tools ?? [])
119
+ .filter(tool => tool.namespace === MIRROR_NAMESPACE)
120
+ .map(tool => tool.name));
121
+ if (mirrorTools.some(tool => !present.has(tool.name))) {
122
+ parsed.context.tools = [...(parsed.context.tools ?? []), ...mirrorTools.filter(tool => !present.has(tool.name))];
123
+ }
124
+ }
125
+ return names.size > 0 ? { names, requestStateBody: stateBody } : undefined;
126
+ }
127
+
128
+ function rewriteValue(
129
+ value: unknown,
130
+ active: V2RoutedDelegationBridgeContext,
131
+ authorizedIds?: ReadonlySet<string>,
132
+ ): { value: unknown; changed: boolean } {
133
+ if (Array.isArray(value)) {
134
+ let changed = false;
135
+ const next = value.map(entry => {
136
+ const rewritten = rewriteValue(entry, active, authorizedIds);
137
+ changed ||= rewritten.changed;
138
+ return rewritten.value;
139
+ });
140
+ return changed ? { value: next, changed: true } : { value, changed: false };
141
+ }
142
+ if (!isRecord(value)) return { value, changed: false };
143
+ let changed = false;
144
+ const entries = Object.entries(value).map(([key, entry]) => {
145
+ const rewritten = rewriteValue(entry, active, authorizedIds);
146
+ changed ||= rewritten.changed;
147
+ return [key, rewritten.value];
148
+ });
149
+ const next: RecordValue = Object.fromEntries(entries);
150
+ const armed =
151
+ value.type === "function_call"
152
+ && value.namespace === MIRROR_NAMESPACE
153
+ && typeof value.name === "string"
154
+ && active.names.has(value.name);
155
+ if (armed && authorizedIds !== undefined) {
156
+ if (typeof value.id !== "string" || !authorizedIds.has(value.id)) {
157
+ const capped = authorizedIds.size >= MAX_SSE_BINDINGS;
158
+ throw Object.assign(new Error(capped
159
+ ? `v2 routed delegation bridge exceeded ${MAX_SSE_BINDINGS} SSE call bindings`
160
+ : "v2 routed delegation bridge received an unbound SSE call"), {
161
+ ...(capped ? { code: "translation_buffer_limit" } : {}),
162
+ });
163
+ }
164
+ }
165
+ if (armed) {
166
+ next.namespace = NATIVE_NAMESPACE;
167
+ next.encrypted_function_args = [];
168
+ changed = true;
169
+ }
170
+ return changed ? { value: next, changed: true } : { value, changed: false };
171
+ }
172
+
173
+ /** Normalize only mirror calls armed by this request in a complete JSON response. */
174
+ export function rewriteV2RoutedDelegationCallsInJson(
175
+ json: string,
176
+ active: V2RoutedDelegationBridgeContext | undefined,
177
+ ): string {
178
+ if (!active || active.names.size === 0) return json;
179
+ let parsed: unknown;
180
+ try { parsed = JSON.parse(json); } catch { return json; }
181
+ const rewritten = rewriteValue(parsed, active);
182
+ return rewritten.changed ? JSON.stringify(rewritten.value) : json;
183
+ }
184
+
185
+ /** Stateful payload rewrite for SSE; item ids bind later argument events to their mirror call. */
186
+ export function createV2RoutedDelegationSseRewrite(
187
+ active: V2RoutedDelegationBridgeContext | undefined,
188
+ ): SsePayloadRewrite | undefined {
189
+ if (!active || active.names.size === 0) return undefined;
190
+ const admittedIds = new Set<string>();
191
+ const openArgumentIds = new Set<string>();
192
+ const bind = (itemId: unknown): void => {
193
+ if (typeof itemId !== "string" || itemId.trim().length === 0) return;
194
+ if (admittedIds.has(itemId)) return;
195
+ if (admittedIds.size >= MAX_SSE_BINDINGS) {
196
+ throw Object.assign(
197
+ new Error(`v2 routed delegation bridge exceeded ${MAX_SSE_BINDINGS} SSE call bindings`),
198
+ { code: "translation_buffer_limit" },
199
+ );
200
+ }
201
+ admittedIds.add(itemId);
202
+ openArgumentIds.add(itemId);
203
+ };
204
+ return payload => {
205
+ let event: unknown;
206
+ try { event = JSON.parse(payload); } catch { return payload; }
207
+ if (!isRecord(event)) return payload;
208
+ const type = event.type;
209
+ const item = isRecord(event.item) ? event.item : undefined;
210
+ const armed = !!item && item.type === "function_call" && item.namespace === MIRROR_NAMESPACE
211
+ && typeof item.name === "string" && active.names.has(item.name);
212
+ const added = type === "response.output_item.added";
213
+ const itemDone = type === "response.output_item.done";
214
+ if (added && armed) bind(item?.id);
215
+ const admittedSnapshot = itemDone && armed && typeof item?.id === "string" && admittedIds.has(item.id);
216
+ const argumentEvent = type === "response.function_call_arguments.delta" || type === "response.function_call_arguments.done";
217
+ const matchedArgument = argumentEvent && typeof event.item_id === "string" && openArgumentIds.has(event.item_id);
218
+ const failedTerminal = type === "response.failed" || type === "response.incomplete";
219
+ const rewritten = rewriteValue(event, active, admittedIds);
220
+ if (type === "response.function_call_arguments.done" && matchedArgument) openArgumentIds.delete(event.item_id as string);
221
+ if (itemDone && admittedSnapshot) openArgumentIds.delete(item!.id as string);
222
+ if (type === "response.completed" || failedTerminal) {
223
+ admittedIds.clear();
224
+ openArgumentIds.clear();
225
+ }
226
+ if (matchedArgument) {
227
+ const next = rewritten.changed && isRecord(rewritten.value) ? rewritten.value : { ...event };
228
+ next.encrypted_function_args = [];
229
+ return JSON.stringify(next);
230
+ }
231
+ return rewritten.changed ? JSON.stringify(rewritten.value) : payload;
232
+ };
233
+ }
@@ -492,6 +492,8 @@ export interface OcxConfig {
492
492
  * Routed parents get v2 tools; Sol/Terra can still spawn Grok/Claude (issue #92).
493
493
  */
494
494
  keepNativeChatGptOnV1?: boolean;
495
+ /** Experimental plaintext delegation bridge for eligible native V2 roots. */
496
+ v2RoutedDelegationBridge?: boolean;
495
497
  /** Optional v2-native parent override for spawn_agent routing. */
496
498
  v2NativeParentOverride?: { enabled?: boolean; model?: string };
497
499
  /** Experimental, default-off ChatGPT recovery for encrypted V2 routed tasks. */