mirror of
https://github.com/openai/codex.git
synced 2026-11-12 21:20:34 +00:00
Propagate image generation asset pointers
This commit is contained in:
@@ -3811,6 +3811,8 @@ async fn turn_event_counts_completed_tool_items() {
|
||||
status: "completed".to_string(),
|
||||
revised_prompt: None,
|
||||
result: "ok".to_string(),
|
||||
asset_pointer: None,
|
||||
original_asset_pointer: None,
|
||||
saved_path: None,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -2536,9 +2536,23 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"asset_pointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"writeOnly": true
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"original_asset_pointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"writeOnly": true
|
||||
},
|
||||
"result": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -4207,9 +4207,21 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"assetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"originalAssetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
+26
@@ -14606,9 +14606,23 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"asset_pointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"writeOnly": true
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"original_asset_pointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"writeOnly": true
|
||||
},
|
||||
"result": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -17044,9 +17058,21 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"assetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"originalAssetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
+26
@@ -11108,9 +11108,23 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"asset_pointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"writeOnly": true
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"original_asset_pointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"writeOnly": true
|
||||
},
|
||||
"result": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -14861,9 +14875,21 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"assetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"originalAssetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -1089,9 +1089,21 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"assetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"originalAssetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -1089,9 +1089,21 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"assetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"originalAssetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
+14
@@ -755,9 +755,23 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"asset_pointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"writeOnly": true
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"original_asset_pointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"writeOnly": true
|
||||
},
|
||||
"result": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -1233,9 +1233,21 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"assetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"originalAssetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -1717,9 +1717,21 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"assetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"originalAssetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -1532,9 +1532,21 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"assetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"originalAssetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
+12
@@ -1532,9 +1532,21 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"assetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"originalAssetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -1532,9 +1532,21 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"assetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"originalAssetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -826,9 +826,23 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"asset_pointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"writeOnly": true
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"original_asset_pointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"writeOnly": true
|
||||
},
|
||||
"result": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -1717,9 +1717,21 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"assetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"originalAssetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -1532,9 +1532,21 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"assetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"originalAssetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -1717,9 +1717,21 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"assetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"originalAssetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -1532,9 +1532,21 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"assetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"originalAssetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -1532,9 +1532,21 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"assetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"originalAssetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -1233,9 +1233,21 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"assetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"originalAssetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -1233,9 +1233,21 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"assetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"originalAssetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -1233,9 +1233,21 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"assetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"originalAssetPointer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -99,4 +99,4 @@ reasoningEffort: ReasoningEffort | null,
|
||||
/**
|
||||
* Last known status of the target agents, when available.
|
||||
*/
|
||||
agentsStates: { [key in string]?: CollabAgentState }, } | { "type": "subAgentActivity", id: string, kind: SubAgentActivityKind, agentThreadId: string, agentPath: string, } | { "type": "webSearch", id: string, query: string, action: WebSearchAction | null, } | { "type": "imageView", id: string, path: AbsolutePathBuf, } | { "type": "imageGeneration", id: string, status: string, revisedPrompt: string | null, result: string, savedPath?: AbsolutePathBuf, } | { "type": "enteredReviewMode", id: string, review: string, } | { "type": "exitedReviewMode", id: string, review: string, } | { "type": "contextCompaction", id: string, };
|
||||
agentsStates: { [key in string]?: CollabAgentState }, } | { "type": "subAgentActivity", id: string, kind: SubAgentActivityKind, agentThreadId: string, agentPath: string, } | { "type": "webSearch", id: string, query: string, action: WebSearchAction | null, } | { "type": "imageView", id: string, path: AbsolutePathBuf, } | { "type": "imageGeneration", id: string, status: string, revisedPrompt: string | null, result: string, assetPointer: string | null, originalAssetPointer: string | null, savedPath?: AbsolutePathBuf, } | { "type": "enteredReviewMode", id: string, review: string, } | { "type": "exitedReviewMode", id: string, review: string, } | { "type": "contextCompaction", id: string, };
|
||||
|
||||
@@ -594,6 +594,8 @@ impl ThreadHistoryBuilder {
|
||||
status: String::new(),
|
||||
revised_prompt: None,
|
||||
result: String::new(),
|
||||
asset_pointer: None,
|
||||
original_asset_pointer: None,
|
||||
saved_path: None,
|
||||
};
|
||||
self.upsert_item_in_current_turn(item);
|
||||
@@ -605,6 +607,8 @@ impl ThreadHistoryBuilder {
|
||||
status: payload.status.clone(),
|
||||
revised_prompt: payload.revised_prompt.clone(),
|
||||
result: payload.result.clone(),
|
||||
asset_pointer: payload.asset_pointer.clone(),
|
||||
original_asset_pointer: payload.original_asset_pointer.clone(),
|
||||
saved_path: payload.saved_path.clone(),
|
||||
};
|
||||
self.upsert_item_in_current_turn(item);
|
||||
@@ -1577,6 +1581,8 @@ mod tests {
|
||||
status: "completed".into(),
|
||||
revised_prompt: Some("final prompt".into()),
|
||||
result: "Zm9v".into(),
|
||||
asset_pointer: Some("sediment://asset".into()),
|
||||
original_asset_pointer: Some("sediment://original".into()),
|
||||
saved_path: Some(test_path_buf("/tmp/ig_123.png").abs()),
|
||||
})),
|
||||
RolloutItem::EventMsg(EventMsg::TurnComplete(TurnCompleteEvent {
|
||||
@@ -1614,6 +1620,8 @@ mod tests {
|
||||
status: "completed".into(),
|
||||
revised_prompt: Some("final prompt".into()),
|
||||
result: "Zm9v".into(),
|
||||
asset_pointer: Some("sediment://asset".into()),
|
||||
original_asset_pointer: Some("sediment://original".into()),
|
||||
saved_path: Some(test_path_buf("/tmp/ig_123.png").abs()),
|
||||
},
|
||||
],
|
||||
|
||||
@@ -360,6 +360,8 @@ pub enum ThreadItem {
|
||||
status: String,
|
||||
revised_prompt: Option<String>,
|
||||
result: String,
|
||||
asset_pointer: Option<String>,
|
||||
original_asset_pointer: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
saved_path: Option<AbsolutePathBuf>,
|
||||
@@ -839,6 +841,8 @@ impl From<CoreTurnItem> for ThreadItem {
|
||||
status: image.status,
|
||||
revised_prompt: image.revised_prompt,
|
||||
result: image.result,
|
||||
asset_pointer: image.asset_pointer,
|
||||
original_asset_pointer: image.original_asset_pointer,
|
||||
saved_path: image.saved_path,
|
||||
},
|
||||
CoreTurnItem::FileChange(file_change) => ThreadItem::FileChange {
|
||||
|
||||
@@ -121,6 +121,32 @@ fn turn_defaults_legacy_missing_items_view_to_full() {
|
||||
assert_eq!(turn.items_view, TurnItemsView::Full);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn image_generation_item_serializes_provenance_fields() {
|
||||
let item = ThreadItem::ImageGeneration {
|
||||
id: "ig_123".to_string(),
|
||||
status: "completed".to_string(),
|
||||
revised_prompt: None,
|
||||
result: "Zm9v".to_string(),
|
||||
asset_pointer: Some("sediment://asset".to_string()),
|
||||
original_asset_pointer: None,
|
||||
saved_path: None,
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
serde_json::to_value(item).expect("serialize image generation item"),
|
||||
json!({
|
||||
"type": "imageGeneration",
|
||||
"id": "ig_123",
|
||||
"status": "completed",
|
||||
"revisedPrompt": null,
|
||||
"result": "Zm9v",
|
||||
"assetPointer": "sediment://asset",
|
||||
"originalAssetPointer": null,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn thread_turns_list_params_accepts_items_view() {
|
||||
let params = serde_json::from_value::<ThreadTurnsListParams>(json!({
|
||||
|
||||
@@ -1275,6 +1275,7 @@ Today both notifications carry an empty `items` array even when item events were
|
||||
- `collabToolCall` — `{id, tool, status, senderThreadId, receiverThreadId?, newThreadId?, prompt?, agentStatus?}` describing collab tool calls (`spawn_agent`, `send_input`, `resume_agent`, `wait`, `close_agent`); `status` is `inProgress`, `completed`, or `failed`.
|
||||
- `webSearch` — `{id, query, action?}` for a web search request issued by the agent; `action` mirrors the Responses API web_search action payload (`search`, `open_page`, `find_in_page`) and may be omitted until completion.
|
||||
- `imageView` — `{id, path}` emitted when the agent invokes the image viewer tool.
|
||||
- `imageGeneration` — `{id, status, revisedPrompt, result, assetPointer, originalAssetPointer, savedPath?}` for an image-generation request. The nullable asset pointer fields preserve upstream image provenance when available.
|
||||
- `enteredReviewMode` — `{id, review}` sent when the reviewer starts; `review` is a short user-facing label such as `"current changes"` or the requested target description.
|
||||
- `exitedReviewMode` — `{id, review}` emitted when the reviewer finishes; `review` is the full plain-text review (usually, overall notes plus bullet point findings).
|
||||
- `contextCompaction` — `{id}` emitted when codex compacts the conversation history. This can happen automatically.
|
||||
|
||||
@@ -96,6 +96,8 @@ mod tests {
|
||||
status: "completed".to_string(),
|
||||
revised_prompt: Some("revised".to_string()),
|
||||
result: "base64-result".to_string(),
|
||||
asset_pointer: None,
|
||||
original_asset_pointer: None,
|
||||
saved_path: Some(test_path_buf("/tmp/ig-1.png").abs()),
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -804,6 +804,8 @@ fn append_resume_redaction_history(
|
||||
status: "completed".to_string(),
|
||||
revised_prompt: Some("secret revised prompt".to_string()),
|
||||
result: "base64-image-result".to_string(),
|
||||
asset_pointer: None,
|
||||
original_asset_pointer: None,
|
||||
saved_path: Some(test_absolute_path("/tmp/ig-1.png")),
|
||||
}),
|
||||
]
|
||||
|
||||
@@ -517,6 +517,8 @@ fn for_prompt_preserves_image_generation_calls_when_images_are_supported() {
|
||||
status: "generating".to_string(),
|
||||
revised_prompt: Some("lobster".to_string()),
|
||||
result: "Zm9v".to_string(),
|
||||
asset_pointer: None,
|
||||
original_asset_pointer: None,
|
||||
},
|
||||
ResponseItem::Message {
|
||||
id: None,
|
||||
@@ -536,6 +538,8 @@ fn for_prompt_preserves_image_generation_calls_when_images_are_supported() {
|
||||
status: "generating".to_string(),
|
||||
revised_prompt: Some("lobster".to_string()),
|
||||
result: "Zm9v".to_string(),
|
||||
asset_pointer: None,
|
||||
original_asset_pointer: None,
|
||||
},
|
||||
ResponseItem::Message {
|
||||
id: None,
|
||||
@@ -565,6 +569,8 @@ fn for_prompt_clears_image_generation_result_when_images_are_unsupported() {
|
||||
status: "completed".to_string(),
|
||||
revised_prompt: Some("lobster".to_string()),
|
||||
result: "Zm9v".to_string(),
|
||||
asset_pointer: None,
|
||||
original_asset_pointer: None,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -584,6 +590,8 @@ fn for_prompt_clears_image_generation_result_when_images_are_unsupported() {
|
||||
status: "completed".to_string(),
|
||||
revised_prompt: Some("lobster".to_string()),
|
||||
result: String::new(),
|
||||
asset_pointer: None,
|
||||
original_asset_pointer: None,
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
@@ -196,12 +196,16 @@ pub fn parse_turn_item(item: &ResponseItem) -> Option<TurnItem> {
|
||||
status,
|
||||
revised_prompt,
|
||||
result,
|
||||
asset_pointer,
|
||||
original_asset_pointer,
|
||||
} => Some(TurnItem::ImageGeneration(
|
||||
codex_protocol::items::ImageGenerationItem {
|
||||
id: id.clone(),
|
||||
status: status.clone(),
|
||||
revised_prompt: revised_prompt.clone(),
|
||||
result: result.clone(),
|
||||
asset_pointer: asset_pointer.clone(),
|
||||
original_asset_pointer: original_asset_pointer.clone(),
|
||||
saved_path: None,
|
||||
},
|
||||
)),
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::context::InternalContextSource;
|
||||
use crate::context::InternalModelContextFragment;
|
||||
use codex_protocol::items::AgentMessageContent;
|
||||
use codex_protocol::items::HookPromptFragment;
|
||||
use codex_protocol::items::ImageGenerationItem;
|
||||
use codex_protocol::items::TurnItem;
|
||||
use codex_protocol::items::WebSearchItem;
|
||||
use codex_protocol::items::build_hook_prompt_message;
|
||||
@@ -145,6 +146,34 @@ fn parses_assistant_message_input_text_for_backward_compatibility() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_image_generation_asset_pointers() {
|
||||
let item = ResponseItem::ImageGenerationCall {
|
||||
id: "ig_123".to_string(),
|
||||
status: "completed".to_string(),
|
||||
revised_prompt: Some("A small blue square".to_string()),
|
||||
result: "Zm9v".to_string(),
|
||||
asset_pointer: Some("sediment://asset".to_string()),
|
||||
original_asset_pointer: Some("sediment://original".to_string()),
|
||||
};
|
||||
|
||||
let Some(TurnItem::ImageGeneration(image)) = parse_turn_item(&item) else {
|
||||
panic!("expected image generation turn item");
|
||||
};
|
||||
assert_eq!(
|
||||
image,
|
||||
ImageGenerationItem {
|
||||
id: "ig_123".to_string(),
|
||||
status: "completed".to_string(),
|
||||
revised_prompt: Some("A small blue square".to_string()),
|
||||
result: "Zm9v".to_string(),
|
||||
asset_pointer: Some("sediment://asset".to_string()),
|
||||
original_asset_pointer: Some("sediment://original".to_string()),
|
||||
saved_path: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn skips_unnamed_image_label_text() {
|
||||
let image_url = "data:image/png;base64,abc".to_string();
|
||||
|
||||
@@ -7573,6 +7573,8 @@ async fn build_initial_context_omits_default_image_save_location_with_image_hist
|
||||
status: "completed".to_string(),
|
||||
revised_prompt: Some("a tiny blue square".to_string()),
|
||||
result: "Zm9v".to_string(),
|
||||
asset_pointer: None,
|
||||
original_asset_pointer: None,
|
||||
}],
|
||||
/*reference_context_item*/ None,
|
||||
)
|
||||
@@ -7825,6 +7827,8 @@ async fn handle_output_item_done_records_image_save_history_message() {
|
||||
status: "completed".to_string(),
|
||||
revised_prompt: Some("a tiny blue square".to_string()),
|
||||
result: "Zm9v".to_string(),
|
||||
asset_pointer: None,
|
||||
original_asset_pointer: None,
|
||||
};
|
||||
|
||||
let mut ctx = HandleOutputCtx {
|
||||
@@ -7880,6 +7884,8 @@ async fn handle_output_item_done_skips_image_save_message_when_save_fails() {
|
||||
status: "completed".to_string(),
|
||||
revised_prompt: Some("broken payload".to_string()),
|
||||
result: "_-8".to_string(),
|
||||
asset_pointer: None,
|
||||
original_asset_pointer: None,
|
||||
};
|
||||
|
||||
let mut ctx = HandleOutputCtx {
|
||||
|
||||
@@ -410,6 +410,8 @@ fn completed_item_defers_mailbox_delivery_for_image_generation_calls() {
|
||||
status: "completed".to_string(),
|
||||
revised_prompt: None,
|
||||
result: "Zm9v".to_string(),
|
||||
asset_pointer: None,
|
||||
original_asset_pointer: None,
|
||||
};
|
||||
|
||||
assert!(completed_item_defers_mailbox_delivery_to_next_turn(
|
||||
|
||||
@@ -459,6 +459,8 @@ mod tests {
|
||||
status: "in_progress".to_string(),
|
||||
revised_prompt: None,
|
||||
result: String::new(),
|
||||
asset_pointer: None,
|
||||
original_asset_pointer: None,
|
||||
saved_path: None,
|
||||
},
|
||||
))
|
||||
@@ -470,6 +472,8 @@ mod tests {
|
||||
status: "completed".to_string(),
|
||||
revised_prompt: Some("A tiny blue square".to_string()),
|
||||
result: "cG5n".to_string(),
|
||||
asset_pointer: None,
|
||||
original_asset_pointer: None,
|
||||
saved_path: Some(test_path_buf("/tmp/extension-claimed.png").abs()),
|
||||
},
|
||||
))
|
||||
@@ -532,6 +536,8 @@ mod tests {
|
||||
status: "in_progress".to_string(),
|
||||
revised_prompt: None,
|
||||
result: String::new(),
|
||||
asset_pointer: None,
|
||||
original_asset_pointer: None,
|
||||
saved_path: None,
|
||||
}
|
||||
);
|
||||
@@ -542,6 +548,8 @@ mod tests {
|
||||
status: "completed".to_string(),
|
||||
revised_prompt: Some("A tiny blue square".to_string()),
|
||||
result: "cG5n".to_string(),
|
||||
asset_pointer: None,
|
||||
original_asset_pointer: None,
|
||||
saved_path: Some(expected_path.clone()),
|
||||
}
|
||||
);
|
||||
|
||||
@@ -103,6 +103,8 @@ fn recent_image_fallback_selects_newest_images_in_chronological_order() {
|
||||
status: "completed".to_string(),
|
||||
revised_prompt: None,
|
||||
result: "generated".to_string(),
|
||||
asset_pointer: None,
|
||||
original_asset_pointer: None,
|
||||
},
|
||||
ResponseItem::FunctionCallOutput {
|
||||
call_id: "orphan-call".to_string(),
|
||||
|
||||
@@ -105,6 +105,8 @@ impl ToolExecutor<ToolCall> for ImageGenerationTool {
|
||||
status: "in_progress".to_string(),
|
||||
revised_prompt: None,
|
||||
result: String::new(),
|
||||
asset_pointer: None,
|
||||
original_asset_pointer: None,
|
||||
saved_path: None,
|
||||
}))
|
||||
.await;
|
||||
@@ -126,6 +128,8 @@ impl ToolExecutor<ToolCall> for ImageGenerationTool {
|
||||
status: "completed".to_string(),
|
||||
revised_prompt: Some(args.prompt),
|
||||
result: result.clone(),
|
||||
asset_pointer: None,
|
||||
original_asset_pointer: None,
|
||||
saved_path: None,
|
||||
}))
|
||||
.await;
|
||||
|
||||
@@ -150,6 +150,12 @@ pub struct ImageGenerationItem {
|
||||
pub result: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub asset_pointer: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub original_asset_pointer: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub saved_path: Option<AbsolutePathBuf>,
|
||||
}
|
||||
|
||||
@@ -500,6 +506,8 @@ impl ImageGenerationItem {
|
||||
status: self.status.clone(),
|
||||
revised_prompt: self.revised_prompt.clone(),
|
||||
result: self.result.clone(),
|
||||
asset_pointer: self.asset_pointer.clone(),
|
||||
original_asset_pointer: self.original_asset_pointer.clone(),
|
||||
saved_path: self.saved_path.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -893,6 +893,12 @@ pub enum ResponseItem {
|
||||
#[ts(optional)]
|
||||
revised_prompt: Option<String>,
|
||||
result: String,
|
||||
#[serde(default, skip_serializing)]
|
||||
#[ts(skip)]
|
||||
asset_pointer: Option<String>,
|
||||
#[serde(default, skip_serializing)]
|
||||
#[ts(skip)]
|
||||
original_asset_pointer: Option<String>,
|
||||
},
|
||||
#[serde(alias = "compaction_summary")]
|
||||
Compaction {
|
||||
@@ -1776,6 +1782,8 @@ mod tests {
|
||||
"status": "completed",
|
||||
"revised_prompt": "A small blue square",
|
||||
"result": "Zm9v",
|
||||
"asset_pointer": "sediment://asset",
|
||||
"original_asset_pointer": "sediment://original",
|
||||
}))
|
||||
.expect("image generation item should deserialize");
|
||||
|
||||
@@ -1786,8 +1794,22 @@ mod tests {
|
||||
status: "completed".to_string(),
|
||||
revised_prompt: Some("A small blue square".to_string()),
|
||||
result: "Zm9v".to_string(),
|
||||
asset_pointer: Some("sediment://asset".to_string()),
|
||||
original_asset_pointer: Some("sediment://original".to_string()),
|
||||
}
|
||||
);
|
||||
let serialized =
|
||||
serde_json::to_value(&item).expect("image generation item should serialize");
|
||||
assert_eq!(
|
||||
serialized,
|
||||
serde_json::json!({
|
||||
"type": "image_generation_call",
|
||||
"id": "ig_123",
|
||||
"status": "completed",
|
||||
"revised_prompt": "A small blue square",
|
||||
"result": "Zm9v",
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1807,6 +1829,32 @@ mod tests {
|
||||
status: "completed".to_string(),
|
||||
revised_prompt: None,
|
||||
result: "Zm9v".to_string(),
|
||||
asset_pointer: None,
|
||||
original_asset_pointer: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn response_item_parses_image_generation_call_without_original_asset_pointer() {
|
||||
let item = serde_json::from_value::<ResponseItem>(serde_json::json!({
|
||||
"id": "ig_123",
|
||||
"type": "image_generation_call",
|
||||
"status": "completed",
|
||||
"result": "Zm9v",
|
||||
"asset_pointer": "sediment://asset",
|
||||
}))
|
||||
.expect("image generation item should deserialize");
|
||||
|
||||
assert_eq!(
|
||||
item,
|
||||
ResponseItem::ImageGenerationCall {
|
||||
id: "ig_123".to_string(),
|
||||
status: "completed".to_string(),
|
||||
revised_prompt: None,
|
||||
result: "Zm9v".to_string(),
|
||||
asset_pointer: Some("sediment://asset".to_string()),
|
||||
original_asset_pointer: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2338,6 +2338,12 @@ pub struct ImageGenerationEndEvent {
|
||||
#[ts(optional)]
|
||||
pub revised_prompt: Option<String>,
|
||||
pub result: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub asset_pointer: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub original_asset_pointer: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub saved_path: Option<AbsolutePathBuf>,
|
||||
@@ -4715,6 +4721,8 @@ mod tests {
|
||||
status: "in_progress".into(),
|
||||
revised_prompt: None,
|
||||
result: String::new(),
|
||||
asset_pointer: None,
|
||||
original_asset_pointer: None,
|
||||
saved_path: None,
|
||||
}),
|
||||
started_at_ms: 0,
|
||||
@@ -4811,6 +4819,8 @@ mod tests {
|
||||
status: "completed".into(),
|
||||
revised_prompt: Some("A tiny blue square".into()),
|
||||
result: "Zm9v".into(),
|
||||
asset_pointer: Some("sediment://asset".into()),
|
||||
original_asset_pointer: Some("sediment://original".into()),
|
||||
saved_path: Some(test_path_buf("/tmp/ig-1.png").abs()),
|
||||
}),
|
||||
completed_at_ms: 0,
|
||||
@@ -4824,6 +4834,11 @@ mod tests {
|
||||
assert_eq!(event.status, "completed");
|
||||
assert_eq!(event.revised_prompt.as_deref(), Some("A tiny blue square"));
|
||||
assert_eq!(event.result, "Zm9v");
|
||||
assert_eq!(event.asset_pointer.as_deref(), Some("sediment://asset"));
|
||||
assert_eq!(
|
||||
event.original_asset_pointer.as_deref(),
|
||||
Some("sediment://original")
|
||||
);
|
||||
assert_eq!(
|
||||
event.saved_path.as_ref().map(AbsolutePathBuf::as_path),
|
||||
Some(test_path_buf("/tmp/ig-1.png").as_path())
|
||||
|
||||
@@ -707,6 +707,8 @@ pub(super) fn handle_image_generation_end(
|
||||
status: "completed".to_string(),
|
||||
revised_prompt,
|
||||
result: String::new(),
|
||||
asset_pointer: None,
|
||||
original_asset_pointer: None,
|
||||
saved_path,
|
||||
},
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user