mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
## Why Standalone image generation returns image bytes to the model, but the model also needs the host artifact path to reference the generated file in follow-up work. ## What changed - Append the default saved-image path hint alongside the generated image tool output. - Reuse the existing core image-generation hint text. - Pass the thread ID and Codex home directory needed to compute the artifact path. - Add app-server and extension coverage for the model-visible hint. ## Validation - `just fmt` - `just bazel-lock-check` - `just test -p codex-app-server standalone_image_generation_returns_saved_path_hint_to_model`
161 lines
6.3 KiB
Rust
161 lines
6.3 KiB
Rust
use super::RuntimeState;
|
|
use super::callbacks::clear_timeout_callback;
|
|
use super::callbacks::exit_callback;
|
|
use super::callbacks::generated_image_callback;
|
|
use super::callbacks::image_callback;
|
|
use super::callbacks::load_callback;
|
|
use super::callbacks::notify_callback;
|
|
use super::callbacks::set_timeout_callback;
|
|
use super::callbacks::store_callback;
|
|
use super::callbacks::text_callback;
|
|
use super::callbacks::tool_callback;
|
|
use super::callbacks::yield_control_callback;
|
|
|
|
pub(super) fn install_globals(scope: &mut v8::PinScope<'_, '_>) -> Result<(), String> {
|
|
let global = scope.get_current_context().global(scope);
|
|
delete_global(scope, global, "console")?;
|
|
delete_global(scope, global, "Atomics")?;
|
|
delete_global(scope, global, "SharedArrayBuffer")?;
|
|
delete_global(scope, global, "WebAssembly")?;
|
|
|
|
let tools = build_tools_object(scope)?;
|
|
let all_tools = build_all_tools_value(scope)?;
|
|
let clear_timeout = helper_function(scope, "clearTimeout", clear_timeout_callback)?;
|
|
let set_timeout = helper_function(scope, "setTimeout", set_timeout_callback)?;
|
|
let text = helper_function(scope, "text", text_callback)?;
|
|
let image = helper_function(scope, "image", image_callback)?;
|
|
let generated_image = helper_function(scope, "generatedImage", generated_image_callback)?;
|
|
let store = helper_function(scope, "store", store_callback)?;
|
|
let load = helper_function(scope, "load", load_callback)?;
|
|
let notify = helper_function(scope, "notify", notify_callback)?;
|
|
let yield_control = helper_function(scope, "yield_control", yield_control_callback)?;
|
|
let exit = helper_function(scope, "exit", exit_callback)?;
|
|
|
|
set_global(scope, global, "tools", tools.into())?;
|
|
set_global(scope, global, "ALL_TOOLS", all_tools)?;
|
|
set_global(scope, global, "clearTimeout", clear_timeout.into())?;
|
|
set_global(scope, global, "setTimeout", set_timeout.into())?;
|
|
set_global(scope, global, "text", text.into())?;
|
|
set_global(scope, global, "image", image.into())?;
|
|
set_global(scope, global, "generatedImage", generated_image.into())?;
|
|
set_global(scope, global, "store", store.into())?;
|
|
set_global(scope, global, "load", load.into())?;
|
|
set_global(scope, global, "notify", notify.into())?;
|
|
set_global(scope, global, "yield_control", yield_control.into())?;
|
|
set_global(scope, global, "exit", exit.into())?;
|
|
Ok(())
|
|
}
|
|
|
|
fn build_tools_object<'s>(
|
|
scope: &mut v8::PinScope<'s, '_>,
|
|
) -> Result<v8::Local<'s, v8::Object>, String> {
|
|
let tools = v8::Object::new(scope);
|
|
let enabled_tools = scope
|
|
.get_slot::<RuntimeState>()
|
|
.map(|state| state.enabled_tools.clone())
|
|
.unwrap_or_default();
|
|
|
|
for (tool_index, tool) in enabled_tools.iter().enumerate() {
|
|
let name = v8::String::new(scope, &tool.global_name)
|
|
.ok_or_else(|| "failed to allocate tool name".to_string())?;
|
|
let function = tool_function(scope, tool_index)?;
|
|
tools.set(scope, name.into(), function.into());
|
|
}
|
|
Ok(tools)
|
|
}
|
|
|
|
fn build_all_tools_value<'s>(
|
|
scope: &mut v8::PinScope<'s, '_>,
|
|
) -> Result<v8::Local<'s, v8::Value>, String> {
|
|
let enabled_tools = scope
|
|
.get_slot::<RuntimeState>()
|
|
.map(|state| state.enabled_tools.clone())
|
|
.unwrap_or_default();
|
|
let array = v8::Array::new(scope, enabled_tools.len() as i32);
|
|
let name_key = v8::String::new(scope, "name")
|
|
.ok_or_else(|| "failed to allocate ALL_TOOLS name key".to_string())?;
|
|
let description_key = v8::String::new(scope, "description")
|
|
.ok_or_else(|| "failed to allocate ALL_TOOLS description key".to_string())?;
|
|
|
|
for (index, tool) in enabled_tools.iter().enumerate() {
|
|
let item = v8::Object::new(scope);
|
|
let name = v8::String::new(scope, &tool.global_name)
|
|
.ok_or_else(|| "failed to allocate ALL_TOOLS name".to_string())?;
|
|
let description = v8::String::new(scope, &tool.description)
|
|
.ok_or_else(|| "failed to allocate ALL_TOOLS description".to_string())?;
|
|
|
|
if item.set(scope, name_key.into(), name.into()) != Some(true) {
|
|
return Err("failed to set ALL_TOOLS name".to_string());
|
|
}
|
|
if item.set(scope, description_key.into(), description.into()) != Some(true) {
|
|
return Err("failed to set ALL_TOOLS description".to_string());
|
|
}
|
|
if array.set_index(scope, index as u32, item.into()) != Some(true) {
|
|
return Err("failed to append ALL_TOOLS metadata".to_string());
|
|
}
|
|
}
|
|
|
|
Ok(array.into())
|
|
}
|
|
|
|
fn helper_function<'s, F>(
|
|
scope: &mut v8::PinScope<'s, '_>,
|
|
name: &str,
|
|
callback: F,
|
|
) -> Result<v8::Local<'s, v8::Function>, String>
|
|
where
|
|
F: v8::MapFnTo<v8::FunctionCallback>,
|
|
{
|
|
let name =
|
|
v8::String::new(scope, name).ok_or_else(|| "failed to allocate helper name".to_string())?;
|
|
let template = v8::FunctionTemplate::builder(callback)
|
|
.data(name.into())
|
|
.build(scope);
|
|
template
|
|
.get_function(scope)
|
|
.ok_or_else(|| "failed to create helper function".to_string())
|
|
}
|
|
|
|
fn tool_function<'s>(
|
|
scope: &mut v8::PinScope<'s, '_>,
|
|
tool_index: usize,
|
|
) -> Result<v8::Local<'s, v8::Function>, String> {
|
|
let data = v8::String::new(scope, &tool_index.to_string())
|
|
.ok_or_else(|| "failed to allocate tool callback data".to_string())?;
|
|
let template = v8::FunctionTemplate::builder(tool_callback)
|
|
.data(data.into())
|
|
.build(scope);
|
|
template
|
|
.get_function(scope)
|
|
.ok_or_else(|| "failed to create tool function".to_string())
|
|
}
|
|
|
|
fn set_global<'s>(
|
|
scope: &mut v8::PinScope<'s, '_>,
|
|
global: v8::Local<'s, v8::Object>,
|
|
name: &str,
|
|
value: v8::Local<'s, v8::Value>,
|
|
) -> Result<(), String> {
|
|
let key = v8::String::new(scope, name)
|
|
.ok_or_else(|| format!("failed to allocate global `{name}`"))?;
|
|
if global.set(scope, key.into(), value) == Some(true) {
|
|
Ok(())
|
|
} else {
|
|
Err(format!("failed to set global `{name}`"))
|
|
}
|
|
}
|
|
|
|
fn delete_global<'s>(
|
|
scope: &mut v8::PinScope<'s, '_>,
|
|
global: v8::Local<'s, v8::Object>,
|
|
name: &str,
|
|
) -> Result<(), String> {
|
|
let key = v8::String::new(scope, name)
|
|
.ok_or_else(|| format!("failed to allocate global `{name}`"))?;
|
|
if global.delete(scope, key.into()) == Some(true) {
|
|
Ok(())
|
|
} else {
|
|
Err(format!("failed to remove global `{name}`"))
|
|
}
|
|
}
|