mirror of
https://github.com/openai/codex.git
synced 2026-04-08 23:04:47 +00:00
Compare commits
1 Commits
main
...
codex/sess
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48659e216a |
@@ -3186,10 +3186,27 @@
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionStartSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ThreadStartSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadStartSource": {
|
||||
"enum": [
|
||||
"startup",
|
||||
"clear"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadUnarchiveParams": {
|
||||
"properties": {
|
||||
"threadId": {
|
||||
|
||||
@@ -14167,6 +14167,16 @@
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionStartSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ThreadStartSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"title": "ThreadStartParams",
|
||||
@@ -14234,6 +14244,13 @@
|
||||
"title": "ThreadStartResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadStartSource": {
|
||||
"enum": [
|
||||
"startup",
|
||||
"clear"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadStartedNotification": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
|
||||
@@ -12022,6 +12022,16 @@
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionStartSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ThreadStartSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"title": "ThreadStartParams",
|
||||
@@ -12089,6 +12099,13 @@
|
||||
"title": "ThreadStartResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"ThreadStartSource": {
|
||||
"enum": [
|
||||
"startup",
|
||||
"clear"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadStartedNotification": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
|
||||
@@ -101,6 +101,13 @@
|
||||
"flex"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ThreadStartSource": {
|
||||
"enum": [
|
||||
"startup",
|
||||
"clear"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
@@ -210,6 +217,16 @@
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionStartSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ThreadStartSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"title": "ThreadStartParams",
|
||||
|
||||
@@ -7,12 +7,13 @@ import type { JsonValue } from "../serde_json/JsonValue";
|
||||
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
|
||||
import type { AskForApproval } from "./AskForApproval";
|
||||
import type { SandboxMode } from "./SandboxMode";
|
||||
import type { ThreadStartSource } from "./ThreadStartSource";
|
||||
|
||||
export type ThreadStartParams = {model?: string | null, modelProvider?: string | null, serviceTier?: ServiceTier | null | null, cwd?: string | null, approvalPolicy?: AskForApproval | null, /**
|
||||
* Override where approval requests are routed for review on this thread
|
||||
* and subsequent turns.
|
||||
*/
|
||||
approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, serviceName?: string | null, baseInstructions?: string | null, developerInstructions?: string | null, personality?: Personality | null, ephemeral?: boolean | null, /**
|
||||
approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, serviceName?: string | null, baseInstructions?: string | null, developerInstructions?: string | null, personality?: Personality | null, ephemeral?: boolean | null, sessionStartSource?: ThreadStartSource | null, /**
|
||||
* If true, opt into emitting raw Responses API items on the event stream.
|
||||
* This is for internal use only (e.g. Codex Cloud).
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
// GENERATED CODE! DO NOT MODIFY BY HAND!
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type ThreadStartSource = "startup" | "clear";
|
||||
@@ -310,6 +310,7 @@ export type { ThreadSortKey } from "./ThreadSortKey";
|
||||
export type { ThreadSourceKind } from "./ThreadSourceKind";
|
||||
export type { ThreadStartParams } from "./ThreadStartParams";
|
||||
export type { ThreadStartResponse } from "./ThreadStartResponse";
|
||||
export type { ThreadStartSource } from "./ThreadStartSource";
|
||||
export type { ThreadStartedNotification } from "./ThreadStartedNotification";
|
||||
export type { ThreadStatus } from "./ThreadStatus";
|
||||
export type { ThreadStatusChangedNotification } from "./ThreadStatusChangedNotification";
|
||||
|
||||
@@ -409,6 +409,14 @@ v2_enum_from_core!(
|
||||
}
|
||||
);
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase", export_to = "v2/")]
|
||||
pub enum ThreadStartSource {
|
||||
Startup,
|
||||
Clear,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
@@ -2611,6 +2619,8 @@ pub struct ThreadStartParams {
|
||||
pub personality: Option<Personality>,
|
||||
#[ts(optional = nullable)]
|
||||
pub ephemeral: Option<bool>,
|
||||
#[ts(optional = nullable)]
|
||||
pub session_start_source: Option<ThreadStartSource>,
|
||||
#[experimental("thread/start.dynamicTools")]
|
||||
#[ts(optional = nullable)]
|
||||
pub dynamic_tools: Option<Vec<DynamicToolSpec>>,
|
||||
|
||||
@@ -133,7 +133,7 @@ Example with notification opt-out:
|
||||
|
||||
## API Overview
|
||||
|
||||
- `thread/start` — create a new thread; emits `thread/started` (including the current `thread.status`) and auto-subscribes you to turn/item events for that thread. When the request includes a `cwd` and the resolved sandbox is `workspace-write` or full access, app-server also marks that project as trusted in the user `config.toml`.
|
||||
- `thread/start` — create a new thread; emits `thread/started` (including the current `thread.status`) and auto-subscribes you to turn/item events for that thread. When the request includes a `cwd` and the resolved sandbox is `workspace-write` or full access, app-server also marks that project as trusted in the user `config.toml`. Pass `sessionStartSource: "clear"` when starting a replacement thread after clearing the current session so `SessionStart` hooks receive `source: "clear"` instead of the default `"startup"`.
|
||||
- `thread/resume` — reopen an existing thread by id so subsequent `turn/start` calls append to it.
|
||||
- `thread/fork` — fork an existing thread into a new thread id by copying the stored history; if the source thread is currently mid-turn, the fork records the same interruption marker as `turn/interrupt` instead of inheriting an unmarked partial turn suffix. The returned `thread.forkedFromId` points at the source thread when known. Accepts `ephemeral: true` for an in-memory temporary fork, emits `thread/started` (including the current `thread.status`), and auto-subscribes you to turn/item events for the new thread.
|
||||
- `thread/list` — page through stored rollouts; supports cursor-based pagination and optional `modelProviders`, `sourceKinds`, `archived`, `cwd`, and `searchTerm` filters. Each returned `thread` includes `status` (`ThreadStatus`), defaulting to `notLoaded` when the thread is not currently loaded.
|
||||
@@ -212,6 +212,7 @@ Start a fresh thread when you need a new Codex conversation.
|
||||
"sandbox": "workspaceWrite",
|
||||
"personality": "friendly",
|
||||
"serviceName": "my_app_server_client", // optional metrics tag (`service_name`)
|
||||
"sessionStartSource": "startup", // optional: "startup" (default) or "clear"
|
||||
// Experimental: requires opt-in
|
||||
"dynamicTools": [
|
||||
{
|
||||
|
||||
@@ -2083,6 +2083,7 @@ impl CodexMessageProcessor {
|
||||
experimental_raw_events,
|
||||
personality,
|
||||
ephemeral,
|
||||
session_start_source,
|
||||
persist_extended_history,
|
||||
} = params;
|
||||
let mut typesafe_overrides = self.build_thread_config_overrides(
|
||||
@@ -2124,6 +2125,7 @@ impl CodexMessageProcessor {
|
||||
config,
|
||||
typesafe_overrides,
|
||||
dynamic_tools,
|
||||
session_start_source,
|
||||
persist_extended_history,
|
||||
service_name,
|
||||
experimental_raw_events,
|
||||
@@ -2199,6 +2201,7 @@ impl CodexMessageProcessor {
|
||||
config_overrides: Option<HashMap<String, serde_json::Value>>,
|
||||
typesafe_overrides: ConfigOverrides,
|
||||
dynamic_tools: Option<Vec<ApiDynamicToolSpec>>,
|
||||
session_start_source: Option<codex_app_server_protocol::ThreadStartSource>,
|
||||
persist_extended_history: bool,
|
||||
service_name: Option<String>,
|
||||
experimental_raw_events: bool,
|
||||
@@ -2322,6 +2325,12 @@ impl CodexMessageProcessor {
|
||||
.thread_manager
|
||||
.start_thread_with_tools_and_service_name(
|
||||
config,
|
||||
match session_start_source
|
||||
.unwrap_or(codex_app_server_protocol::ThreadStartSource::Startup)
|
||||
{
|
||||
codex_app_server_protocol::ThreadStartSource::Startup => InitialHistory::New,
|
||||
codex_app_server_protocol::ThreadStartSource::Clear => InitialHistory::Cleared,
|
||||
},
|
||||
core_dynamic_tools,
|
||||
persist_extended_history,
|
||||
service_name,
|
||||
@@ -4239,7 +4248,7 @@ impl CodexMessageProcessor {
|
||||
thread.preview = preview_from_rollout_items(items);
|
||||
Ok(thread)
|
||||
}
|
||||
InitialHistory::New => Err(format!(
|
||||
InitialHistory::New | InitialHistory::Cleared => Err(format!(
|
||||
"failed to build resume response for thread {thread_id}: initial history missing"
|
||||
)),
|
||||
};
|
||||
@@ -8856,7 +8865,7 @@ pub(crate) async fn read_rollout_items_from_rollout(
|
||||
path: &Path,
|
||||
) -> std::io::Result<Vec<RolloutItem>> {
|
||||
let items = match RolloutRecorder::get_rollout_history(path).await? {
|
||||
InitialHistory::New => Vec::new(),
|
||||
InitialHistory::New | InitialHistory::Cleared => Vec::new(),
|
||||
InitialHistory::Forked(items) => items,
|
||||
InitialHistory::Resumed(resumed) => resumed.history,
|
||||
};
|
||||
|
||||
@@ -241,6 +241,7 @@ async fn skills_changed_notification_is_emitted_after_skill_change() -> Result<(
|
||||
developer_instructions: None,
|
||||
personality: None,
|
||||
ephemeral: None,
|
||||
session_start_source: None,
|
||||
dynamic_tools: None,
|
||||
mock_experimental_field: None,
|
||||
experimental_raw_events: false,
|
||||
|
||||
@@ -591,7 +591,7 @@ impl Codex {
|
||||
let thread_id = match &conversation_history {
|
||||
InitialHistory::Resumed(resumed) => Some(resumed.conversation_id),
|
||||
InitialHistory::Forked(_) => conversation_history.forked_from_id(),
|
||||
InitialHistory::New => None,
|
||||
InitialHistory::New | InitialHistory::Cleared => None,
|
||||
};
|
||||
match thread_id {
|
||||
Some(thread_id) => {
|
||||
@@ -1530,7 +1530,7 @@ impl Session {
|
||||
let forked_from_id = initial_history.forked_from_id();
|
||||
|
||||
let (conversation_id, rollout_params) = match &initial_history {
|
||||
InitialHistory::New | InitialHistory::Forked(_) => {
|
||||
InitialHistory::New | InitialHistory::Cleared | InitialHistory::Forked(_) => {
|
||||
let conversation_id = ThreadId::default();
|
||||
(
|
||||
conversation_id,
|
||||
@@ -1571,14 +1571,14 @@ impl Session {
|
||||
.count(),
|
||||
)
|
||||
.unwrap_or(u64::MAX),
|
||||
InitialHistory::New | InitialHistory::Forked(_) => 0,
|
||||
InitialHistory::New | InitialHistory::Cleared | InitialHistory::Forked(_) => 0,
|
||||
};
|
||||
let state_builder = match &initial_history {
|
||||
InitialHistory::Resumed(resumed) => metadata::builder_from_items(
|
||||
resumed.history.as_slice(),
|
||||
resumed.rollout_path.as_path(),
|
||||
),
|
||||
InitialHistory::New | InitialHistory::Forked(_) => None,
|
||||
InitialHistory::New | InitialHistory::Cleared | InitialHistory::Forked(_) => None,
|
||||
};
|
||||
|
||||
// Kick off independent async setup tasks in parallel to reduce startup latency.
|
||||
@@ -2111,6 +2111,7 @@ impl Session {
|
||||
InitialHistory::New | InitialHistory::Forked(_) => {
|
||||
codex_hooks::SessionStartSource::Startup
|
||||
}
|
||||
InitialHistory::Cleared => codex_hooks::SessionStartSource::Clear,
|
||||
};
|
||||
|
||||
// record_initial_history can emit events. We record only after the SessionConfiguredEvent is emitted.
|
||||
@@ -2245,7 +2246,7 @@ impl Session {
|
||||
)
|
||||
};
|
||||
match conversation_history {
|
||||
InitialHistory::New => {
|
||||
InitialHistory::New | InitialHistory::Cleared => {
|
||||
// Defer initial context insertion until the first real turn starts so
|
||||
// turn/start overrides can be merged before we write model-visible context.
|
||||
self.set_previous_turn_settings(/*previous_turn_settings*/ None)
|
||||
|
||||
@@ -469,6 +469,7 @@ impl ThreadManager {
|
||||
) -> CodexResult<NewThread> {
|
||||
Box::pin(self.start_thread_with_tools_and_service_name(
|
||||
config,
|
||||
InitialHistory::New,
|
||||
dynamic_tools,
|
||||
persist_extended_history,
|
||||
/*metrics_service_name*/ None,
|
||||
@@ -480,6 +481,7 @@ impl ThreadManager {
|
||||
pub async fn start_thread_with_tools_and_service_name(
|
||||
&self,
|
||||
config: Config,
|
||||
initial_history: InitialHistory,
|
||||
dynamic_tools: Vec<codex_protocol::dynamic_tools::DynamicToolSpec>,
|
||||
persist_extended_history: bool,
|
||||
metrics_service_name: Option<String>,
|
||||
@@ -487,7 +489,7 @@ impl ThreadManager {
|
||||
) -> CodexResult<NewThread> {
|
||||
Box::pin(self.state.spawn_thread(
|
||||
config,
|
||||
InitialHistory::New,
|
||||
initial_history,
|
||||
Arc::clone(&self.state.auth_manager),
|
||||
self.agent_control(),
|
||||
dynamic_tools,
|
||||
@@ -663,6 +665,7 @@ impl ThreadManager {
|
||||
ForkSnapshot::Interrupted => {
|
||||
let history = match history {
|
||||
InitialHistory::New => InitialHistory::New,
|
||||
InitialHistory::Cleared => InitialHistory::Cleared,
|
||||
InitialHistory::Forked(history) => InitialHistory::Forked(history),
|
||||
InitialHistory::Resumed(resumed) => InitialHistory::Forked(resumed.history),
|
||||
};
|
||||
@@ -1064,7 +1067,7 @@ fn append_interrupted_boundary(history: InitialHistory, turn_id: Option<String>)
|
||||
}));
|
||||
|
||||
match history {
|
||||
InitialHistory::New => InitialHistory::Forked(vec![
|
||||
InitialHistory::New | InitialHistory::Cleared => InitialHistory::Forked(vec![
|
||||
RolloutItem::ResponseItem(interrupted_turn_history_marker()),
|
||||
aborted_event,
|
||||
]),
|
||||
|
||||
@@ -20,6 +20,7 @@ use crate::schema::SessionStartCommandInput;
|
||||
pub enum SessionStartSource {
|
||||
Startup,
|
||||
Resume,
|
||||
Clear,
|
||||
}
|
||||
|
||||
impl SessionStartSource {
|
||||
@@ -27,6 +28,7 @@ impl SessionStartSource {
|
||||
match self {
|
||||
Self::Startup => "startup",
|
||||
Self::Resume => "resume",
|
||||
Self::Clear => "clear",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2274,6 +2274,7 @@ pub struct ResumedHistory {
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
|
||||
pub enum InitialHistory {
|
||||
New,
|
||||
Cleared,
|
||||
Resumed(ResumedHistory),
|
||||
Forked(Vec<RolloutItem>),
|
||||
}
|
||||
@@ -2281,7 +2282,7 @@ pub enum InitialHistory {
|
||||
impl InitialHistory {
|
||||
pub fn forked_from_id(&self) -> Option<ThreadId> {
|
||||
match self {
|
||||
InitialHistory::New => None,
|
||||
InitialHistory::New | InitialHistory::Cleared => None,
|
||||
InitialHistory::Resumed(resumed) => {
|
||||
resumed.history.iter().find_map(|item| match item {
|
||||
RolloutItem::SessionMeta(meta_line) => meta_line.meta.forked_from_id,
|
||||
@@ -2297,7 +2298,7 @@ impl InitialHistory {
|
||||
|
||||
pub fn session_cwd(&self) -> Option<PathBuf> {
|
||||
match self {
|
||||
InitialHistory::New => None,
|
||||
InitialHistory::New | InitialHistory::Cleared => None,
|
||||
InitialHistory::Resumed(resumed) => session_cwd_from_items(&resumed.history),
|
||||
InitialHistory::Forked(items) => session_cwd_from_items(items),
|
||||
}
|
||||
@@ -2305,7 +2306,7 @@ impl InitialHistory {
|
||||
|
||||
pub fn get_rollout_items(&self) -> Vec<RolloutItem> {
|
||||
match self {
|
||||
InitialHistory::New => Vec::new(),
|
||||
InitialHistory::New | InitialHistory::Cleared => Vec::new(),
|
||||
InitialHistory::Resumed(resumed) => resumed.history.clone(),
|
||||
InitialHistory::Forked(items) => items.clone(),
|
||||
}
|
||||
@@ -2313,7 +2314,7 @@ impl InitialHistory {
|
||||
|
||||
pub fn get_event_msgs(&self) -> Option<Vec<EventMsg>> {
|
||||
match self {
|
||||
InitialHistory::New => None,
|
||||
InitialHistory::New | InitialHistory::Cleared => None,
|
||||
InitialHistory::Resumed(resumed) => Some(
|
||||
resumed
|
||||
.history
|
||||
@@ -2339,7 +2340,7 @@ impl InitialHistory {
|
||||
pub fn get_base_instructions(&self) -> Option<BaseInstructions> {
|
||||
// TODO: SessionMeta should (in theory) always be first in the history, so we can probably only check the first item?
|
||||
match self {
|
||||
InitialHistory::New => None,
|
||||
InitialHistory::New | InitialHistory::Cleared => None,
|
||||
InitialHistory::Resumed(resumed) => {
|
||||
resumed.history.iter().find_map(|item| match item {
|
||||
RolloutItem::SessionMeta(meta_line) => meta_line.meta.base_instructions.clone(),
|
||||
@@ -2355,7 +2356,7 @@ impl InitialHistory {
|
||||
|
||||
pub fn get_dynamic_tools(&self) -> Option<Vec<DynamicToolSpec>> {
|
||||
match self {
|
||||
InitialHistory::New => None,
|
||||
InitialHistory::New | InitialHistory::Cleared => None,
|
||||
InitialHistory::Resumed(resumed) => {
|
||||
resumed.history.iter().find_map(|item| match item {
|
||||
RolloutItem::SessionMeta(meta_line) => meta_line.meta.dynamic_tools.clone(),
|
||||
|
||||
@@ -80,6 +80,7 @@ use codex_app_server_protocol::SkillsListResponse;
|
||||
use codex_app_server_protocol::ThreadItem;
|
||||
use codex_app_server_protocol::ThreadLoadedListParams;
|
||||
use codex_app_server_protocol::ThreadRollbackResponse;
|
||||
use codex_app_server_protocol::ThreadStartSource;
|
||||
use codex_app_server_protocol::Turn;
|
||||
use codex_app_server_protocol::TurnError as AppServerTurnError;
|
||||
use codex_app_server_protocol::TurnStatus;
|
||||
@@ -3271,6 +3272,7 @@ impl App {
|
||||
&mut self,
|
||||
tui: &mut tui::Tui,
|
||||
app_server: &mut AppServerSession,
|
||||
session_start_source: Option<ThreadStartSource>,
|
||||
) {
|
||||
// Start a fresh in-memory session while preserving resumability via persisted rollout
|
||||
// history.
|
||||
@@ -3292,7 +3294,10 @@ impl App {
|
||||
}
|
||||
}
|
||||
self.config = config.clone();
|
||||
match app_server.start_thread(&config).await {
|
||||
match app_server
|
||||
.start_thread_with_session_start_source(&config, session_start_source)
|
||||
.await
|
||||
{
|
||||
Ok(started) => {
|
||||
if let Err(err) = self
|
||||
.replace_chat_widget_with_app_server_thread(tui, app_server, started)
|
||||
@@ -4019,15 +4024,21 @@ impl App {
|
||||
) -> Result<AppRunControl> {
|
||||
match event {
|
||||
AppEvent::NewSession => {
|
||||
self.start_fresh_session_with_summary_hint(tui, app_server)
|
||||
.await;
|
||||
self.start_fresh_session_with_summary_hint(
|
||||
tui, app_server, /*session_start_source*/ None,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
AppEvent::ClearUi => {
|
||||
self.clear_terminal_ui(tui, /*redraw_header*/ false)?;
|
||||
self.reset_app_ui_state_after_clear();
|
||||
|
||||
self.start_fresh_session_with_summary_hint(tui, app_server)
|
||||
.await;
|
||||
self.start_fresh_session_with_summary_hint(
|
||||
tui,
|
||||
app_server,
|
||||
Some(ThreadStartSource::Clear),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
AppEvent::OpenResumePicker => {
|
||||
let picker_app_server = match crate::start_app_server_for_picker(
|
||||
|
||||
@@ -55,6 +55,7 @@ use codex_app_server_protocol::ThreadShellCommandParams;
|
||||
use codex_app_server_protocol::ThreadShellCommandResponse;
|
||||
use codex_app_server_protocol::ThreadStartParams;
|
||||
use codex_app_server_protocol::ThreadStartResponse;
|
||||
use codex_app_server_protocol::ThreadStartSource;
|
||||
use codex_app_server_protocol::ThreadUnsubscribeParams;
|
||||
use codex_app_server_protocol::ThreadUnsubscribeResponse;
|
||||
use codex_app_server_protocol::Turn;
|
||||
@@ -300,6 +301,15 @@ impl AppServerSession {
|
||||
}
|
||||
|
||||
pub(crate) async fn start_thread(&mut self, config: &Config) -> Result<AppServerStartedThread> {
|
||||
self.start_thread_with_session_start_source(config, /*session_start_source*/ None)
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn start_thread_with_session_start_source(
|
||||
&mut self,
|
||||
config: &Config,
|
||||
session_start_source: Option<ThreadStartSource>,
|
||||
) -> Result<AppServerStartedThread> {
|
||||
let request_id = self.next_request_id();
|
||||
let response: ThreadStartResponse = self
|
||||
.client
|
||||
@@ -309,6 +319,7 @@ impl AppServerSession {
|
||||
config,
|
||||
self.thread_params_mode(),
|
||||
self.remote_cwd_override.as_deref(),
|
||||
session_start_source,
|
||||
),
|
||||
})
|
||||
.await
|
||||
@@ -869,6 +880,7 @@ fn thread_start_params_from_config(
|
||||
config: &Config,
|
||||
thread_params_mode: ThreadParamsMode,
|
||||
remote_cwd_override: Option<&std::path::Path>,
|
||||
session_start_source: Option<ThreadStartSource>,
|
||||
) -> ThreadStartParams {
|
||||
ThreadStartParams {
|
||||
model: config.model.clone(),
|
||||
@@ -879,6 +891,7 @@ fn thread_start_params_from_config(
|
||||
sandbox: sandbox_mode_from_policy(config.permissions.sandbox_policy.get().clone()),
|
||||
config: config_request_overrides_from_config(config),
|
||||
ephemeral: Some(config.ephemeral),
|
||||
session_start_source,
|
||||
persist_extended_history: true,
|
||||
..ThreadStartParams::default()
|
||||
}
|
||||
@@ -1185,12 +1198,28 @@ mod tests {
|
||||
&config,
|
||||
ThreadParamsMode::Embedded,
|
||||
/*remote_cwd_override*/ None,
|
||||
/*session_start_source*/ None,
|
||||
);
|
||||
|
||||
assert_eq!(params.cwd, Some(config.cwd.to_string_lossy().to_string()));
|
||||
assert_eq!(params.model_provider, Some(config.model_provider_id));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn thread_start_params_can_mark_clear_source() {
|
||||
let temp_dir = tempfile::tempdir().expect("tempdir");
|
||||
let config = build_config(&temp_dir).await;
|
||||
|
||||
let params = thread_start_params_from_config(
|
||||
&config,
|
||||
ThreadParamsMode::Embedded,
|
||||
/*remote_cwd_override*/ None,
|
||||
Some(ThreadStartSource::Clear),
|
||||
);
|
||||
|
||||
assert_eq!(params.session_start_source, Some(ThreadStartSource::Clear));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn thread_lifecycle_params_omit_cwd_without_remote_override_for_remote_sessions() {
|
||||
let temp_dir = tempfile::tempdir().expect("tempdir");
|
||||
@@ -1201,6 +1230,7 @@ mod tests {
|
||||
&config,
|
||||
ThreadParamsMode::Remote,
|
||||
/*remote_cwd_override*/ None,
|
||||
/*session_start_source*/ None,
|
||||
);
|
||||
let resume = thread_resume_params_from_config(
|
||||
config.clone(),
|
||||
@@ -1234,6 +1264,7 @@ mod tests {
|
||||
&config,
|
||||
ThreadParamsMode::Remote,
|
||||
Some(remote_cwd.as_path()),
|
||||
/*session_start_source*/ None,
|
||||
);
|
||||
let resume = thread_resume_params_from_config(
|
||||
config.clone(),
|
||||
|
||||
Reference in New Issue
Block a user