mirror of
https://github.com/openai/codex.git
synced 2026-10-20 17:38:45 +00:00
Add promise settlement streaming helpers to code mode (#51126)
## What changed Expose two JavaScript globals for consuming results as inputs settle: - `as_settled(promises)` returns an async iterator of fulfilled and rejected records in settlement order, preserving queued results while the consumer is busy. - `stream_settled(promises, emit)` delivers those records to a callback, awaiting each invocation and propagating callback errors. Records include an `index`, a `status`, and either a `value` or a `reason`. Iterable inputs use positional indices; `Map` inputs retain their keys. Both helpers accept promises, thenables, and plain values. ## Testing Add runtime coverage for ordering, input types, object identity, callback behavior, early iteration exit, and termination. Add stdio and gRPC host tests for partial results across waits, plus a scenario snapshot verifying fulfilled and rejected records reach the model. GitOrigin-RevId: cddc9f3679ae04f2421e154caa0417afb15f550d
This commit is contained in:
committed by
copyberry
parent
402f5b6fdf
commit
28a264fbc7
@@ -46,6 +46,12 @@ pub(super) fn install_globals(scope: &mut v8::PinScope<'_, '_>) -> Result<(), St
|
||||
set_global(scope, global, "notify", notify.into())?;
|
||||
set_global(scope, global, "yield_control", yield_control.into())?;
|
||||
set_global(scope, global, "exit", exit.into())?;
|
||||
|
||||
let source = v8::String::new(scope, include_str!("settled.js"))
|
||||
.ok_or_else(|| "failed to allocate settlement helpers".to_string())?;
|
||||
v8::Script::compile(scope, source, /*origin*/ None)
|
||||
.and_then(|script| script.run(scope))
|
||||
.ok_or_else(|| "failed to initialize settlement helpers".to_string())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// Runtime-owned promise combinators; all state stays in the cell's V8 heap.
|
||||
// Observe each input once and queue settlements while the consumer is busy.
|
||||
// Repeated races can lose that order and attach extra reactions to pending inputs.
|
||||
(() => {
|
||||
function as_settled(promises) {
|
||||
let ready = [];
|
||||
let pending = 0;
|
||||
let wake;
|
||||
let closed = false;
|
||||
|
||||
function settle(result) {
|
||||
pending--;
|
||||
if (closed) return;
|
||||
ready.push(result);
|
||||
if (wake) {
|
||||
const resolve = wake;
|
||||
wake = undefined;
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
|
||||
const keyed = promises instanceof Map;
|
||||
let position = 0;
|
||||
try {
|
||||
for (const entry of promises) {
|
||||
const [index, promise] = keyed ? entry : [position++, entry];
|
||||
pending++;
|
||||
Promise.resolve(promise).then(
|
||||
(value) => settle({ index, status: "fulfilled", value }),
|
||||
(reason) => settle({ index, status: "rejected", reason }),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
closed = true;
|
||||
throw error;
|
||||
}
|
||||
|
||||
return (async function* () {
|
||||
try {
|
||||
while (pending > 0 || ready.length > 0) {
|
||||
if (ready.length === 0) {
|
||||
await new Promise((resolve) => {
|
||||
wake = resolve;
|
||||
});
|
||||
}
|
||||
const batch = ready;
|
||||
ready = [];
|
||||
yield* batch;
|
||||
}
|
||||
} finally {
|
||||
closed = true;
|
||||
ready = [];
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
async function stream_settled(promises, emit) {
|
||||
if (typeof emit !== "function") {
|
||||
throw new TypeError("stream_settled requires a callback");
|
||||
}
|
||||
for await (const result of as_settled(promises)) {
|
||||
await emit(result);
|
||||
}
|
||||
}
|
||||
|
||||
Object.assign(globalThis, { as_settled, stream_settled });
|
||||
})();
|
||||
@@ -1127,6 +1127,7 @@ async fn global_scope_contains_only_allowed_items() {
|
||||
"WeakSet",
|
||||
"__codexContentItems",
|
||||
"add_content",
|
||||
"as_settled",
|
||||
"audio",
|
||||
"decodeURI",
|
||||
"decodeURIComponent",
|
||||
@@ -1146,6 +1147,7 @@ async fn global_scope_contains_only_allowed_items() {
|
||||
"parseInt",
|
||||
"setTimeout",
|
||||
"store",
|
||||
"stream_settled",
|
||||
"text",
|
||||
"tools",
|
||||
"undefined",
|
||||
|
||||
Reference in New Issue
Block a user