Skip to content

Commit ce70ae9

Browse files
committed
stable version 1.1
1 parent fae2bb5 commit ce70ae9

8 files changed

Lines changed: 191 additions & 77 deletions

File tree

‎chrome_extension/injected.js‎

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -654,10 +654,7 @@
654654
if (sentinelToken) headers['Openai-Sentinel-Chat-Requirements-Token'] = sentinelToken;
655655
if (proofToken) headers['Openai-Sentinel-Proof-Token'] = proofToken;
656656

657-
var targetModel = model || 'auto';
658-
if (targetModel.includes('5.6') || targetModel.includes('sol')) {
659-
targetModel = 'gpt-5.6-sol';
660-
}
657+
var targetModel = 'gpt-5-6-thinking';
661658

662659
var body = {
663660
action: 'next',
@@ -748,7 +745,7 @@
748745
var line = lines[li].trim();
749746
if (!line || line.startsWith('event:')) continue;
750747
if (!line.startsWith('data: ')) continue;
751-
var data = line.slice(6).trim();
748+
var data = line.slice(6).trim();
752749
if (data === '[DONE]') continue;
753750

754751
try {
@@ -767,29 +764,25 @@
767764
if (parsed.v.conversation_id) conversationId = parsed.v.conversation_id;
768765
if (parsed.v.message && parsed.v.message.conversation_id) conversationId = parsed.v.message.conversation_id;
769766
}
770-
// Publish ids as soon as they are known so a cancel arriving
771-
// mid-stream can address the real message. Waiting for onDone
772-
// meant activeStreams.messageId was still null at cancel time and
773-
// the backend cancel call never fired.
774767
if (onIds && (conversationId || messageId)) onIds(conversationId, messageId);
775768

776769
if (parsed.v && typeof parsed.v === 'object' && parsed.v.message) {
777770
var msg = parsed.v.message;
778771
var role = (msg.author || {}).role || '';
779-
isAssistant = role !== 'user';
780-
// Only an ASSISTANT message id may become the next turn's
781-
// parent_message_id. Recording the user echo (or a trailing
782-
// system/moderation message) here pointed the following turn at
783-
// the wrong node and forked the thread into a branch.
772+
isAssistant = role !== 'user' && role !== 'system';
784773
if (isAssistant && msg.id) {
785774
messageId = msg.id;
786775
if (onIds) onIds(conversationId, messageId);
787776
}
788777
if (isAssistant) {
789778
var parts = ((msg.content || {}).parts) || [];
790779
if (parts.length) {
791-
var p0 = parts[0];
792-
var newText = typeof p0 === 'string' ? p0 : (p0 && typeof p0 === 'object' ? (p0.text || p0.val || '') : '');
780+
var extractedParts = parts.map(function(p) {
781+
if (typeof p === 'string') return p;
782+
if (p && typeof p === 'object') return p.text || p.val || p.content || (p.text_content ? p.text_content : '');
783+
return '';
784+
});
785+
var newText = extractedParts.join('\n');
793786
if (typeof newText === 'string' && newText.length > fullText.length) {
794787
var delta = newText.slice(fullText.length);
795788
fullText = newText;
@@ -802,7 +795,7 @@
802795
if (parsed.o === 'append') {
803796
var path = parsed.p || lastPath;
804797
if (path) lastPath = path;
805-
if (path && (path.indexOf('/content/parts/') !== -1 || path === '/message/content/parts/0') && isAssistant) {
798+
if (path && (path.indexOf('/content/parts/') !== -1 || path.indexOf('/message/content/') !== -1) && isAssistant) {
806799
var val = String(parsed.v || '');
807800
fullText += val;
808801
onDelta(val);

‎codex_engine/engine.py‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2037,8 +2037,10 @@ def _strip_patch_blocks(content: str) -> str:
20372037
if not isinstance(content, str) or not content:
20382038
return content
20392039
if "*** Begin Patch" in content:
2040-
content = re.sub(r"\*\*\* Begin Patch.*?\*\*\* End Patch", "\n[File patch applied]\n", content, flags=re.DOTALL)
2041-
content = re.sub(r"```(?:apply_patch|diff|patch)\n.*?```", "\n[File patch applied]\n", content, flags=re.DOTALL)
2040+
content = re.sub(r"\*\*\* Begin Patch.*?\*\*\* End Patch", "", content, flags=re.DOTALL)
2041+
content = re.sub(r"```(?:apply_patch|diff|patch)\n.*?```", "", content, flags=re.DOTALL)
2042+
content = re.sub(r"\*\*\* Begin Patch.*$", "", content, flags=re.DOTALL)
2043+
content = re.sub(r"```(?:apply_patch|diff|patch).*$", "", content, flags=re.DOTALL)
20422044
return content.strip()
20432045

20442046

@@ -2083,6 +2085,11 @@ def _provider_response_to_responses_api(
20832085
patch_res = apply_git_patch(os.getcwd(), str(content))
20842086
if patch_res.get("success"):
20852087
logger.info("Hybrid Engine: Successfully applied git patch via %s", patch_res.get("method"))
2088+
prose = content.split("```", 1)[0].split("*** Begin Patch", 1)[0].strip() if isinstance(content, str) else ""
2089+
prose = _strip_patch_blocks(prose) or "Applying file edits to workspace..."
2090+
patch_tool_call = [{"name": "exec", "input": {"cmd": f"git diff --stat"}}]
2091+
_count_repair(metrics, "patch_tool_calls")
2092+
return _make_responses_tool_reply(resp_id, prose, patch_tool_call, request_tools)
20862093
else:
20872094
logger.warning("Hybrid Engine: Could not apply git patch: %s", patch_res.get("error"))
20882095
except Exception as e:

‎codex_engine/patch_engine.py‎

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def flush_hunk(hdr, hunk):
6363
old_start, new_start, rest = m.group(1), m.group(2), m.group(3)
6464
clean_lines.append(f"@@ -{old_start},{old_count} +{new_start},{new_count} @@{rest}")
6565
else:
66-
clean_lines.append(hdr)
66+
clean_lines.append(f"@@ -1,{old_count} +1,{new_count} @@")
6767
clean_lines.extend(hunk)
6868

6969
for line in lines:
@@ -140,7 +140,7 @@ def apply_git_patch(repo_path: str, patch_text: str) -> dict:
140140
clean_patch = sanitize_patch(clean_patch)
141141

142142
patch_file = os.path.join(tempfile.gettempdir(), f"patch_{int(time.time())}.patch")
143-
with open(patch_file, "w", encoding="utf-8") as f:
143+
with open(patch_file, "w", encoding="utf-8", errors="replace") as f:
144144
f.write(clean_patch)
145145

146146
candidate_repos = [os.path.abspath(repo_path), "/Users/adammaged/computer-science-learning-platform"]
@@ -154,8 +154,7 @@ def apply_git_patch(repo_path: str, patch_text: str) -> dict:
154154
res = subprocess.run(
155155
["git", "apply", "--recount", "--ignore-space-change", "--whitespace=nowarn", patch_file],
156156
cwd=target_repo,
157-
capture_output=True,
158-
text=True
157+
capture_output=True
159158
)
160159
if res.returncode == 0:
161160
logger.info("Git patch applied cleanly via git apply --recount in %s!", target_repo)
@@ -165,8 +164,7 @@ def apply_git_patch(repo_path: str, patch_text: str) -> dict:
165164
res3 = subprocess.run(
166165
["git", "apply", "-3", "--whitespace=nowarn", patch_file],
167166
cwd=target_repo,
168-
capture_output=True,
169-
text=True
167+
capture_output=True
170168
)
171169
if res3.returncode == 0:
172170
logger.info("Git patch applied cleanly via git apply -3 in %s!", target_repo)
@@ -176,14 +174,15 @@ def apply_git_patch(repo_path: str, patch_text: str) -> dict:
176174
patch_res = subprocess.run(
177175
["patch", "-p1", "--fuzz=3", "--ignore-whitespace", "-i", patch_file],
178176
cwd=target_repo,
179-
capture_output=True,
180-
text=True
177+
capture_output=True
181178
)
182179
if patch_res.returncode == 0:
183180
logger.info("Patch applied cleanly via patch -p1 --fuzz=3 in %s!", target_repo)
184181
return {"success": True, "method": "patch -p1 --fuzz=3", "patch_file": patch_file, "repo": target_repo}
185182
else:
186-
last_error = f"git apply: {res.stderr}; patch: {patch_res.stderr}"
183+
err1 = res.stderr.decode("utf-8", errors="replace") if res.stderr else ""
184+
err2 = patch_res.stderr.decode("utf-8", errors="replace") if patch_res.stderr else ""
185+
last_error = f"git apply: {err1}; patch: {err2}"
187186
except Exception as e:
188187
last_error = str(e)
189188
logger.error("Failed to apply patch in %s: %s", target_repo, e)

‎codex_engine/responses_streaming.py‎

Lines changed: 98 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,19 @@ def _clean_reasoning_stream(full_so_far: str) -> str:
2626
if not full_so_far:
2727
return ""
2828
text = re.sub(r"\[END_OF_RESPONSE(?:_[A-Za-z0-9-]+)?\]", "", full_so_far, flags=re.IGNORECASE)
29-
text = re.sub(r"\bKIM_[a-f0-9]{8}\b", "", text).strip()
29+
text = re.sub(r"\bKIM_[a-f0-9]{8}\b", "", text)
30+
text = re.sub(r"#\s*Codex Agent[\s\S]*?(?=(?:\b(?:Hi|Hello|I'll|I will|Let's|Looking|Checking|Running|Updating|Here|Done)\b|```|\Z))", "", text, flags=re.IGNORECASE)
31+
text = re.sub(r"This document defines exactly how the Codex agent[\s\S]*?(?=(?:\b(?:Hi|Hello|I'll|I will|Let's|Looking|Checking|Running|Updating|Here|Done)\b|```|\Z))", "", text, flags=re.IGNORECASE)
32+
text = re.sub(r"## Single Command Turn-by-Turn Protocol[\s\S]*?(?=(?:\b(?:Hi|Hello|I'll|I will|Let's|Looking|Checking|Running|Updating|Here|Done)\b|```|\Z))", "", text, flags=re.IGNORECASE)
33+
text = re.sub(r"in your response to cite this file[^\n]*\n?", "", text, flags=re.IGNORECASE)
34+
text = re.sub(r"Make sure to include\s+(?:filecite[^]+|turn\d+file\d+|\s*)*", "", text, flags=re.IGNORECASE)
35+
text = re.sub(r"filecite[^]+", "", text)
36+
text = re.sub(r"\bturn\d+file\d+\b", "", text, flags=re.IGNORECASE)
37+
text = re.sub(r"^\s*Make sure to include\s*$", "", text, flags=re.IGNORECASE | re.MULTILINE).strip()
3038
if text.startswith("{"):
3139
m = re.search(r'"text"\s*:\s*"((?:[^"\\]|\\.)*)', text)
3240
if m:
3341
text = m.group(1).replace('\\"', '"').replace('\\n', '\n')
34-
else:
35-
return ""
36-
if "```" in text:
37-
text = text.split("```", 1)[0]
3842
return text.strip()
3943

4044

@@ -63,6 +67,7 @@ async def stream_responses_http(
6367

6468
resp_id = f"resp_{uuid.uuid4().hex[:16]}"
6569
reasoning_id = f"item_{uuid.uuid4().hex[:12]}"
70+
msg_item_id = f"item_{uuid.uuid4().hex[:12]}"
6671

6772
in_progress = {
6873
"id": resp_id,
@@ -77,27 +82,52 @@ async def stream_responses_http(
7782
f"data: {json.dumps({'type': 'response.created', 'response': in_progress})}\n\n".encode("utf-8")
7883
)
7984

80-
# 2. Send response.output_item.added for reasoning (index 0)
85+
# 2. Send response.output_item.added for reasoning (index 0) and message (index 1)
8186
reasoning_item = {
8287
"id": reasoning_id,
8388
"type": "reasoning",
8489
"reasoning_text": "",
85-
"summary": [],
90+
"summary": [{"type": "summary_text", "text": ""}],
8691
"status": "in_progress",
8792
}
8893
await stream_res.write(
8994
f"data: {json.dumps({'type': 'response.output_item.added', 'output_index': 0, 'item': reasoning_item})}\n\n".encode("utf-8")
9095
)
9196

97+
msg_item_added = {
98+
"id": msg_item_id,
99+
"type": "message",
100+
"role": "assistant",
101+
"content": [],
102+
"status": "in_progress",
103+
}
104+
await stream_res.write(
105+
f"data: {json.dumps({'type': 'response.output_item.added', 'output_index': 1, 'item': msg_item_added})}\n\n".encode("utf-8")
106+
)
107+
await stream_res.write(
108+
f"data: {json.dumps({'type': 'response.content_part.added', 'item_id': msg_item_id, 'output_index': 1, 'content_index': 0, 'part': {'type': 'output_text', 'text': ''}})}\n\n".encode("utf-8")
109+
)
110+
92111
loop = asyncio.get_running_loop()
93112
queue: asyncio.Queue[Optional[str]] = asyncio.Queue()
94113
accumulated_reasoning: list[str] = []
95114
last_emitted_len = 0
115+
is_streaming_done = False
96116

97117
def _on_delta(delta: str) -> None:
98118
if delta:
99119
loop.call_soon_threadsafe(queue.put_nowait, delta)
100120

121+
async def _heartbeat_worker():
122+
while not is_streaming_done:
123+
await asyncio.sleep(1.5)
124+
if not is_streaming_done:
125+
try:
126+
await stream_res.write(b": ping\n\n")
127+
await stream_res.drain()
128+
except Exception:
129+
break
130+
101131
async def _stream_worker():
102132
nonlocal last_emitted_len
103133
while True:
@@ -111,20 +141,38 @@ async def _stream_worker():
111141
if len(clean_full) > last_emitted_len:
112142
new_delta = clean_full[last_emitted_len:]
113143
last_emitted_len = len(clean_full)
114-
ev = {
144+
ev1 = {
145+
"type": "response.reasoning_summary.text.delta",
146+
"item_id": reasoning_id,
147+
"output_index": 0,
148+
"content_index": 0,
149+
"delta": new_delta,
150+
}
151+
ev2 = {
115152
"type": "response.reasoning.text.delta",
116153
"item_id": reasoning_id,
117154
"output_index": 0,
118155
"content_index": 0,
119156
"delta": new_delta,
120157
}
158+
ev3 = {
159+
"type": "response.output_text.delta",
160+
"item_id": msg_item_id,
161+
"output_index": 1,
162+
"content_index": 0,
163+
"delta": new_delta,
164+
}
121165
try:
122-
await stream_res.write(f"data: {json.dumps(ev)}\n\n".encode("utf-8"))
166+
await stream_res.write(f"data: {json.dumps(ev1)}\n\n".encode("utf-8"))
167+
await stream_res.write(f"data: {json.dumps(ev2)}\n\n".encode("utf-8"))
168+
await stream_res.write(f"data: {json.dumps(ev3)}\n\n".encode("utf-8"))
169+
await stream_res.drain()
123170
except Exception:
124171
pass
125172
queue.task_done()
126173

127174
worker_task = asyncio.create_task(_stream_worker())
175+
heartbeat_task = asyncio.create_task(_heartbeat_worker())
128176

129177
# 3. Call provider complete with on_delta callback
130178
extra_kwargs = {"handoff": handoff} if handoff else {}
@@ -148,15 +196,9 @@ async def _stream_worker():
148196
on_delta=_on_delta,
149197
**extra_kwargs,
150198
)
151-
except Exception as e:
152-
logger.error(f"[relay #{relay_num}] Provider call failed: {e}")
153-
await queue.put(None)
154-
await worker_task
155-
error_payload = {"error": {"message": f"LLM call failed: {e}"}}
156-
await stream_res.write(f"data: {json.dumps(error_payload)}\n\n".encode("utf-8"))
157-
await stream_res.write(b"data: [DONE]\n\n")
158-
await stream_res.write_eof()
159-
return stream_res
199+
finally:
200+
is_streaming_done = True
201+
heartbeat_task.cancel()
160202

161203
# Signal worker to finish draining deltas
162204
await queue.put(None)
@@ -254,36 +296,52 @@ async def _stream_worker():
254296
}
255297
await stream_res.write(f"data: {json.dumps(reasoning_item_completed)}\n\n".encode("utf-8"))
256298

257-
# 6. Stream remaining output items (message, function_call, custom_tool_call)
258-
out_idx = 1
299+
final_text = curr_reasoning or "".join(accumulated_reasoning)
300+
for item in responses_reply.get("output") or []:
301+
if isinstance(item, dict) and item.get("type") == "message":
302+
for block in (item.get("content") or []):
303+
if isinstance(block, dict) and block.get("type") == "output_text":
304+
t = str(block.get("text") or "")
305+
if t:
306+
final_text = t
307+
break
308+
309+
part_dict = {"type": "output_text", "text": final_text}
310+
await stream_res.write(
311+
f"data: {json.dumps({'type': 'response.content_part.done', 'item_id': msg_item_id, 'output_index': 1, 'content_index': 0, 'part': part_dict})}\n\n".encode("utf-8")
312+
)
313+
await stream_res.write(
314+
f"data: {json.dumps({'type': 'response.output_item.done', 'output_index': 1, 'item': {'id': msg_item_id, 'type': 'message', 'role': 'assistant', 'status': 'completed', 'content': [part_dict]}})}\n\n".encode("utf-8")
315+
)
316+
317+
# Ensure responses_reply output contains message item
318+
has_msg = False
319+
for item in (responses_reply.get("output") or []):
320+
if isinstance(item, dict) and item.get("type") == "message":
321+
has_msg = True
322+
if not item.get("content"):
323+
item["content"] = [part_dict]
324+
if not has_msg:
325+
responses_reply.setdefault("output", []).append({
326+
"id": msg_item_id,
327+
"type": "message",
328+
"role": "assistant",
329+
"status": "completed",
330+
"content": [part_dict],
331+
})
332+
333+
# 6. Stream remaining tool call output items
334+
out_idx = 2
259335
for item in responses_reply.get("output") or []:
260336
if not isinstance(item, dict):
261337
continue
262338
itype = item.get("type", "")
263-
if itype == "reasoning":
339+
if itype in ("reasoning", "message"):
264340
continue
265341
item_id = str(item.get("id") or f"item_{uuid.uuid4().hex[:12]}")
266342
item_dict = {**item, "id": item_id}
267343

268-
if itype == "message":
269-
text = "".join(
270-
str(block.get("text") or "")
271-
for block in (item.get("content") or [])
272-
if isinstance(block, dict) and block.get("type") == "output_text"
273-
)
274-
await stream_res.write(
275-
f"data: {json.dumps({'type': 'response.output_item.added', 'output_index': out_idx, 'item': {**item_dict, 'content': [], 'status': 'in_progress'}})}\n\n".encode("utf-8")
276-
)
277-
await stream_res.write(
278-
f"data: {json.dumps({'type': 'response.output_text.delta', 'item_id': item_id, 'output_index': out_idx, 'content_index': 0, 'delta': text})}\n\n".encode("utf-8")
279-
)
280-
await stream_res.write(
281-
f"data: {json.dumps({'type': 'response.output_text.done', 'item_id': item_id, 'output_index': out_idx, 'content_index': 0, 'text': text})}\n\n".encode("utf-8")
282-
)
283-
await stream_res.write(
284-
f"data: {json.dumps({'type': 'response.output_item.done', 'output_index': out_idx, 'item': {**item_dict, 'status': 'completed'}})}\n\n".encode("utf-8")
285-
)
286-
elif itype in ("function_call", "custom_tool_call"):
344+
if itype in ("function_call", "custom_tool_call"):
287345
arguments = str(item.get("arguments") or item.get("input") or "{}")
288346
await stream_res.write(
289347
f"data: {json.dumps({'type': 'response.output_item.added', 'output_index': out_idx, 'item': {**item_dict, 'arguments': '', 'status': 'in_progress'}})}\n\n".encode("utf-8")

‎orchestrator/providers/browser/extension_bridge.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ async def _send_completion_locked(
293293
loop = asyncio.get_running_loop()
294294
fut: asyncio.Future = loop.create_future()
295295

296-
gizmo_id = os.getenv("KIM_GIZMO_ID") or None
296+
gizmo_id = os.getenv("KIM_GIZMO_ID") or "g-6a6799761630819197e463478a4e70e5"
297297

298298
payload = {
299299
"type": "request",

0 commit comments

Comments
 (0)