mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
Add experimental turn additional context (#24154)
## Summary
Adds experimental `additionalContext` support to `turn/start` and
`turn/steer` so clients can provide ephemeral external context, such as
browser or automation state, without turning that plumbing into a
visible user prompt or triggering user-prompt lifecycle behavior.
## API Shape
The parameter shape is:
```ts
additionalContext?: Record<string, {
value: string
kind: "untrusted" | "application"
}> | null
```
Example:
```json
{
"additionalContext": {
"browser_info": {
"value": "Active tab is CI failures.",
"kind": "untrusted"
},
"automation_info": {
"value": "CI rerun is in progress.",
"kind": "application"
}
}
}
```
The keys are opaque and caller-defined.
## Context Injection
When provided, accepted entries are inserted into model context as
hidden contextual message items, not as visible thread user-message
items.
`kind: "untrusted"` entries are inserted with role `user`:
```text
<external_${key}>${value}</external_${key}>
```
`kind: "application"` entries are inserted with role `developer`:
```text
<${key}>${value}</${key}>
```
Values are not escaped. Each value is truncated to 1k approximate tokens
before wrapping.
For `turn/start`, accepted additional context is inserted before normal
user input. For `turn/steer`, additional context is merged only when the
steer includes non-empty user input; context-only steers still reject as
empty input.
## Dedupe Strategy
`AdditionalContextStore` lives on session state and stores the latest
complete additional-context map.
Each `turn/start` or non-empty `turn/steer` treats its
`additionalContext` as the current complete set of values. Entries are
injected only when the key is new or the exact entry for that key
changed, including `value` or `kind`. After merging, the store is
replaced with the provided map, so omitted keys are removed from the
retained set and can be injected again later if reintroduced.
Omitting `additionalContext`, passing `null`, or passing an empty object
resets the store to empty and injects nothing.
## What Changed
- Threads experimental v2 `additionalContext` through app-server into
core turn start and steer handling.
- Adds separate contextual fragment types for untrusted user-role
context and application developer-role context.
- Uses pending response input items so additional context can be
combined with normal user input without treating it as prompt text.
- Adds integration coverage for start/steer flow, role routing,
dedupe/reset behavior, deletion/re-add behavior, hook-blocked input
behavior, empty context-only steer rejection, external-fragment marker
matching, and truncation.
This commit is contained in:
@@ -658,6 +658,7 @@ async fn turn_start_jsonrpc_span_parents_core_turn_spans() -> Result<()> {
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: None,
|
||||
cwd: None,
|
||||
runtime_workspace_roots: None,
|
||||
approval_policy: None,
|
||||
|
||||
@@ -25,6 +25,8 @@ use codex_app_server_protocol::AccountLoginCompletedNotification;
|
||||
use codex_app_server_protocol::AccountUpdatedNotification;
|
||||
use codex_app_server_protocol::AddCreditsNudgeCreditType;
|
||||
use codex_app_server_protocol::AddCreditsNudgeEmailStatus;
|
||||
use codex_app_server_protocol::AdditionalContextEntry;
|
||||
use codex_app_server_protocol::AdditionalContextKind;
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
use codex_app_server_protocol::AppListUpdatedNotification;
|
||||
use codex_app_server_protocol::AppSummary;
|
||||
@@ -421,6 +423,7 @@ use codex_thread_store::ThreadStore;
|
||||
use codex_thread_store::ThreadStoreError;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use codex_utils_pty::DEFAULT_OUTPUT_BYTES_CAP;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::io::Error as IoError;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use super::*;
|
||||
use codex_protocol::protocol::AdditionalContextEntry as CoreAdditionalContextEntry;
|
||||
use codex_protocol::protocol::AdditionalContextKind as CoreAdditionalContextKind;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct TurnRequestProcessor {
|
||||
@@ -30,6 +32,29 @@ fn resolve_runtime_workspace_roots(
|
||||
resolved_roots
|
||||
}
|
||||
|
||||
fn map_additional_context(
|
||||
additional_context: Option<HashMap<String, AdditionalContextEntry>>,
|
||||
) -> BTreeMap<String, CoreAdditionalContextEntry> {
|
||||
additional_context
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(|(key, entry)| {
|
||||
(
|
||||
key,
|
||||
CoreAdditionalContextEntry {
|
||||
value: entry.value,
|
||||
kind: match entry.kind {
|
||||
AdditionalContextKind::Untrusted => CoreAdditionalContextKind::Untrusted,
|
||||
AdditionalContextKind::Application => {
|
||||
CoreAdditionalContextKind::Application
|
||||
}
|
||||
},
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
struct ThreadSettingsBuildParams {
|
||||
method: &'static str,
|
||||
cwd: Option<PathBuf>,
|
||||
@@ -391,6 +416,7 @@ impl TurnRequestProcessor {
|
||||
.into_iter()
|
||||
.map(V2UserInput::into_core)
|
||||
.collect();
|
||||
let additional_context = map_additional_context(params.additional_context);
|
||||
let turn_has_input = !mapped_items.is_empty();
|
||||
let thread_settings = self
|
||||
.build_thread_settings_overrides(
|
||||
@@ -419,6 +445,7 @@ impl TurnRequestProcessor {
|
||||
environments: environment_selections,
|
||||
final_output_json_schema: params.output_schema,
|
||||
responsesapi_client_metadata: params.responsesapi_client_metadata,
|
||||
additional_context,
|
||||
thread_settings,
|
||||
};
|
||||
let turn_id = self
|
||||
@@ -746,10 +773,12 @@ impl TurnRequestProcessor {
|
||||
.into_iter()
|
||||
.map(V2UserInput::into_core)
|
||||
.collect();
|
||||
let additional_context = map_additional_context(params.additional_context);
|
||||
|
||||
let turn_id = thread
|
||||
.steer_input(
|
||||
mapped_items,
|
||||
additional_context,
|
||||
Some(¶ms.expected_turn_id),
|
||||
params.responsesapi_client_metadata,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user