Update app-server support for Codex CLI 0.143.0

This commit is contained in:
murashit 2026-07-08 11:38:43 +09:00
parent e83dc59521
commit 19d35f7e33
63 changed files with 320 additions and 74 deletions

View file

@ -64,7 +64,7 @@ Threads can be archived as Markdown notes with a configurable folder, filename t
| ------------------------ | --------- | --------------------------------------------------------------------------------------------------- |
| `manifest.minAppVersion` | `1.12.0` | Minimum Obsidian desktop version declared for plugin loading. |
| `obsidian` API types | `1.12.3` | TypeScript API package used for compile-time checks; kept in the same minor as `manifest` baseline. |
| `codex.testedCliVersion` | `0.142.5` | Track app-server compatibility by Codex CLI minor version. |
| `codex.testedCliVersion` | `0.143.0` | Track app-server compatibility by Codex CLI minor version. |
Codex Panel depends on the experimental `codex app-server` API.

View file

@ -7,6 +7,7 @@ import type { AppsListResponse } from "../../generated/app-server/v2/AppsListRes
import type { CollaborationModeListResponse } from "../../generated/app-server/v2/CollaborationModeListResponse";
import type { ConfigReadResponse } from "../../generated/app-server/v2/ConfigReadResponse";
import type { ConfigWriteResponse } from "../../generated/app-server/v2/ConfigWriteResponse";
import type { EnvironmentInfoResponse } from "../../generated/app-server/v2/EnvironmentInfoResponse";
import type { FsReadFileResponse } from "../../generated/app-server/v2/FsReadFileResponse";
import type { GetAccountRateLimitsResponse } from "../../generated/app-server/v2/GetAccountRateLimitsResponse";
import type { HooksListResponse } from "../../generated/app-server/v2/HooksListResponse";
@ -25,6 +26,7 @@ import type { ThreadGoalClearResponse } from "../../generated/app-server/v2/Thre
import type { ThreadGoalGetResponse } from "../../generated/app-server/v2/ThreadGoalGetResponse";
import type { ThreadGoalSetResponse } from "../../generated/app-server/v2/ThreadGoalSetResponse";
import type { ThreadInjectItemsResponse } from "../../generated/app-server/v2/ThreadInjectItemsResponse";
import type { ThreadItemsListResponse } from "../../generated/app-server/v2/ThreadItemsListResponse";
import type { ThreadListResponse } from "../../generated/app-server/v2/ThreadListResponse";
import type { ThreadReadResponse } from "../../generated/app-server/v2/ThreadReadResponse";
import type { ThreadResumeResponse } from "../../generated/app-server/v2/ThreadResumeResponse";
@ -87,6 +89,7 @@ export interface ClientResponseByMethod {
"thread/name/set": ThreadSetNameResponse;
"thread/settings/update": ThreadSettingsUpdateResponse;
"thread/turns/list": ThreadTurnsListResponse;
"thread/items/list": ThreadItemsListResponse;
"skills/list": SkillsListResponse;
"app/list": AppsListResponse;
"plugin/installed": PluginInstalledResponse;
@ -102,6 +105,7 @@ export interface ClientResponseByMethod {
"turn/steer": TurnSteerResponse;
"turn/interrupt": TurnInterruptResponse;
"fs/readFile": FsReadFileResponse;
"environment/info": EnvironmentInfoResponse;
}
export type TypedClientRequestMethod = Extract<ClientRequestMethod, keyof ClientResponseByMethod>;

View file

@ -66,7 +66,7 @@ function sandboxPolicyFromConfig(config: Record<string, unknown>): RuntimeSandbo
}
function approvalPolicyOrNull(value: unknown): RuntimeApprovalPolicy | null {
if (value === "untrusted" || value === "on-failure" || value === "on-request" || value === "never") return value;
if (value === "untrusted" || value === "on-request" || value === "never") return value;
if (!value || typeof value !== "object") return null;
const granular = (value as Record<string, unknown>)["granular"];
if (!granular || typeof granular !== "object") return null;

View file

@ -28,6 +28,7 @@ interface ToolInventoryPluginSummary {
type ToolInventoryPluginSource =
| { type: "local"; path: string }
| { type: "git"; url: string; path: string | null; refName: string | null; sha: string | null }
| { type: "npm"; package: string; version: string | null; registry: string | null }
| { type: "remote" };
interface ToolInventoryMarketplaceLoadError {
@ -80,5 +81,6 @@ function pluginSourceLabel(source: ToolInventoryPluginSource): string {
const path = source.path ? `/${source.path}` : "";
return `${source.url}${path}${ref}`;
}
if (source.type === "npm") return source.version ? `${source.package}@${source.version}` : source.package;
return "remote";
}

View file

@ -191,11 +191,17 @@ export async function rollbackThread(client: ThreadRollbackClient, threadId: str
return threadRollbackSnapshotFromAppServerResponse(response);
}
export async function forkThread(client: ThreadForkClient, threadId: string, cwd: string): Promise<Thread> {
export async function forkThread(
client: ThreadForkClient,
threadId: string,
cwd: string,
lastTurnId: string | null = null,
): Promise<Thread> {
const response = await client.request("thread/fork", {
threadId,
cwd,
excludeTurns: true,
...(lastTurnId ? { lastTurnId } : {}),
});
return threadFromThreadRecord(response.thread);
}

View file

@ -1,6 +1,5 @@
export type RuntimeApprovalPolicy =
| "untrusted"
| "on-failure"
| "on-request"
| "never"
| {

View file

@ -135,9 +135,8 @@ function createChatThreadMutationTransport(host: ChatAppServerTransportHost): Th
});
return result ?? false;
},
forkThread: (threadId) => withConnectedChatAppServerClient(host, (client) => forkThread(client, threadId, host.vaultPath)),
rollbackForkedThread: (threadId, turnsToDrop) =>
withConnectedChatAppServerClient(host, async (client) => (await rollbackThread(client, threadId, turnsToDrop)).thread),
forkThread: (threadId, lastTurnId = null) =>
withConnectedChatAppServerClient(host, (client) => forkThread(client, threadId, host.vaultPath, lastTurnId)),
rollbackThread: (threadId) =>
withConnectedChatAppServerClient(host, async (client): Promise<ThreadRollbackSnapshot> => {
const snapshot = await rollbackThread(client, threadId);

View file

@ -113,22 +113,17 @@ async function forkThreadFromTurn(
}
const scope = captureThreadManagementPanelScope(host, threadId);
const turnsToDrop = turnId ? messageStreamTurnsAfterTurnId(threadManagementState(host).messageStream, turnId) : 0;
if (turnsToDrop === null) {
const selectedTurnDistanceFromEnd = turnId ? messageStreamTurnsAfterTurnId(threadManagementState(host).messageStream, turnId) : 0;
if (selectedTurnDistanceFromEnd === null) {
host.addSystemMessage("Could not find the selected turn to fork.");
return;
}
try {
const sourceName = inheritedForkThreadName(threadId, threadManagementState(host).threadList.listedThreads);
let forkedThread = await host.threadTransport.forkThread(threadId);
const forkedThread = turnId ? await host.threadTransport.forkThread(threadId, turnId) : await host.threadTransport.forkThread(threadId);
if (!forkedThread) return;
const forkedThreadId = forkedThread.id;
if (turnsToDrop > 0) {
const rolledBackThread = await host.threadTransport.rollbackForkedThread(forkedThreadId, turnsToDrop);
if (!rolledBackThread) return;
forkedThread = rolledBackThread;
}
host.recordForkedThread(forkedThread);
if (!threadManagementScopeStillTargetsOriginalPanel(host, scope)) return;
if (sourceName) {

View file

@ -9,7 +9,6 @@ export interface ThreadRollbackSnapshot {
export interface ThreadMutationTransport {
compactThread(threadId: string): Promise<boolean>;
forkThread(threadId: string): Promise<Thread | null>;
rollbackForkedThread(threadId: string, turnsToDrop: number): Promise<Thread | null>;
forkThread(threadId: string, lastTurnId?: string | null): Promise<Thread | null>;
rollbackThread(threadId: string): Promise<ThreadRollbackSnapshot | null>;
}

File diff suppressed because one or more lines are too long

View file

@ -3,9 +3,7 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
/**
* Controls whether the model receives multi-agent delegation instructions and,
* when it does, whether it should only spawn sub-agents after an explicit user
* request or may delegate proactively when doing so would help. `none` leaves
* the multi-agent tools available without injecting delegation instructions.
* Controls the effective multi-agent delegation instructions for a turn. `custom` means the
* configured mode hint defines the policy instead of a built-in policy.
*/
export type MultiAgentMode = "none" | "explicitRequestOnly" | "proactive";
export type MultiAgentMode = { "custom": string } | "explicitRequestOnly" | "proactive";

View file

@ -0,0 +1,30 @@
// 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.
/**
* An immutable, cross-platform representation of a `file:` URI.
*
* Only the `file:` scheme is currently accepted. Construction validates the
* URL, and the URI cannot be mutated after construction. [`Self::basename`],
* [`Self::parent`], and [`Self::join`] operate on URI path segments without
* interpreting them using the operating system running Codex. Fallback URIs
* created by [`Self::from_abs_path`] are opaque to these lexical operations.
*
* `file:` paths retain their URI spelling so they can be parsed independently
* of the current host. A local POSIX `file:` URI can also retain
* percent-encoded non-UTF-8 bytes for lossless native round trips.
*
* Like [VS Code resources], path operations use `/` URI separators on every
* host. Lexical path operations preserve a URL authority without interpreting
* Windows drive or UNC roots from path text. Native path normalization,
* filesystem aliases, symlinks, case sensitivity, and Unicode normalization
* are not resolved.
*
* Serde represents a `PathUri` as its canonical URI string. Deserialization
* accepts only valid `file:` URI strings. These strings round-trip through
* their canonical URL form, including encoded non-UTF-8 path bytes.
*
* [VS Code resources]: https://github.com/microsoft/vscode/blob/main/src/vs/base/common/resources.ts
*/
export type PathUri = string;

View file

@ -20,4 +20,4 @@ id?: string,
/**
* Set when using the Responses API.
*/
call_id: string | null, status: LocalShellStatus, action: LocalShellAction, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "function_call", id?: string, name: string, namespace?: string, arguments: string, call_id: string, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "tool_search_call", id?: string, call_id: string | null, status?: string, execution: string, arguments: unknown, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "function_call_output", id?: string, call_id: string, output: FunctionCallOutputBody, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "custom_tool_call", id?: string, status?: string, call_id: string, name: string, input: string, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "custom_tool_call_output", id?: string, call_id: string, name?: string, output: FunctionCallOutputBody, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "tool_search_output", id?: string, call_id: string | null, status: string, execution: string, tools: unknown[], internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "web_search_call", id?: string, status?: string, action?: WebSearchAction, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "image_generation_call", id?: string, status: string, revised_prompt?: string, result: string, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "compaction", id?: string, encrypted_content: string, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "compaction_trigger", } | { "type": "context_compaction", id?: string, encrypted_content?: string, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "other" };
call_id: string | null, status: LocalShellStatus, action: LocalShellAction, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "function_call", id?: string, name: string, namespace?: string, arguments: string, call_id: string, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "tool_search_call", id?: string, call_id: string | null, status?: string, execution: string, arguments: unknown, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "function_call_output", id?: string, call_id: string, output: FunctionCallOutputBody, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "custom_tool_call", id?: string, status?: string, call_id: string, name: string, namespace?: string, input: string, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "custom_tool_call_output", id?: string, call_id: string, name?: string, output: FunctionCallOutputBody, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "tool_search_output", id?: string, call_id: string | null, status: string, execution: string, tools: unknown[], internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "web_search_call", id?: string, status?: string, action?: WebSearchAction, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "image_generation_call", id?: string, status: string, revised_prompt?: string, result: string, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "compaction", id?: string, encrypted_content: string, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "compaction_trigger", } | { "type": "context_compaction", id?: string, encrypted_content?: string, internal_chat_message_metadata_passthrough?: InternalChatMessageMetadataPassthrough, } | { "type": "other" };

View file

@ -2,4 +2,9 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
/**
* Identifier for a Codex thread.
*
* Codex-generated thread IDs are UUIDv7, and some use cases rely on that.
*/
export type ThreadId = string;

View file

@ -60,6 +60,7 @@ export type { MultiAgentMode } from "./MultiAgentMode";
export type { NetworkPolicyAmendment } from "./NetworkPolicyAmendment";
export type { NetworkPolicyRuleAction } from "./NetworkPolicyRuleAction";
export type { ParsedCommand } from "./ParsedCommand";
export type { PathUri } from "./PathUri";
export type { Personality } from "./Personality";
export type { PlanType } from "./PlanType";
export type { RealtimeConversationVersion } from "./RealtimeConversationVersion";

View file

@ -7,7 +7,7 @@ import type { AppMetadata } from "./AppMetadata";
/**
* EXPERIMENTAL - app metadata returned by app-list APIs.
*/
export type AppInfo = { id: string, name: string, description: string | null, logoUrl: string | null, logoUrlDark: string | null, distributionChannel: string | null, branding: AppBranding | null, appMetadata: AppMetadata | null, labels: { [key in string]?: string } | null, installUrl: string | null, isAccessible: boolean,
export type AppInfo = { id: string, name: string, description: string | null, logoUrl: string | null, logoUrlDark: string | null, iconAssets: { [key in string]?: string } | null, iconDarkAssets: { [key in string]?: string } | null, distributionChannel: string | null, branding: AppBranding | null, appMetadata: AppMetadata | null, labels: { [key in string]?: string } | null, installUrl: string | null, isAccessible: boolean,
/**
* Whether this app is enabled in config.toml.
* Example:

View file

@ -2,4 +2,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type AskForApproval = "untrusted" | "on-failure" | "on-request" | { "granular": { sandbox_approval: boolean, rules: boolean, skill_approval: boolean, request_permissions: boolean, mcp_elicitations: boolean, } } | "never";
export type AskForApproval = "untrusted" | "on-request" | { "granular": { sandbox_approval: boolean, rules: boolean, skill_approval: boolean, request_permissions: boolean, mcp_elicitations: boolean, } } | "never";

View file

@ -5,4 +5,8 @@
/**
* Location used to resolve a selected capability root.
*/
export type CapabilityRootLocation = { "type": "environment", environmentId: string, path: string, };
export type CapabilityRootLocation = { "type": "environment", environmentId: string,
/**
* Absolute path for the root in the selected environment.
*/
path: string, };

View file

@ -9,4 +9,4 @@ import type { NonSteerableTurnKind } from "./NonSteerableTurnKind";
* When an upstream HTTP status is available (for example, from the Responses API or a provider),
* it is forwarded in `httpStatusCode` on the relevant `codexErrorInfo` variant.
*/
export type CodexErrorInfo = "contextWindowExceeded" | "usageLimitExceeded" | "serverOverloaded" | "cyberPolicy" | { "httpConnectionFailed": { httpStatusCode: number | null, } } | { "responseStreamConnectionFailed": { httpStatusCode: number | null, } } | "internalServerError" | "unauthorized" | "badRequest" | "threadRollbackFailed" | "sandboxError" | { "responseStreamDisconnected": { httpStatusCode: number | null, } } | { "responseTooManyFailedAttempts": { httpStatusCode: number | null, } } | { "activeTurnNotSteerable": { turnKind: NonSteerableTurnKind, } } | "other";
export type CodexErrorInfo = "contextWindowExceeded" | "sessionBudgetExceeded" | "usageLimitExceeded" | "serverOverloaded" | "cyberPolicy" | { "httpConnectionFailed": { httpStatusCode: number | null, } } | { "responseStreamConnectionFailed": { httpStatusCode: number | null, } } | "internalServerError" | "unauthorized" | "badRequest" | "threadRollbackFailed" | "sandboxError" | { "responseStreamDisconnected": { httpStatusCode: number | null, } } | { "responseTooManyFailedAttempts": { httpStatusCode: number | null, } } | { "activeTurnNotSteerable": { turnKind: NonSteerableTurnKind, } } | "other";

View file

@ -6,9 +6,10 @@ import type { ApprovalsReviewer } from "./ApprovalsReviewer";
import type { AskForApproval } from "./AskForApproval";
import type { ComputerUseRequirements } from "./ComputerUseRequirements";
import type { ManagedHooksRequirements } from "./ManagedHooksRequirements";
import type { ModelsRequirements } from "./ModelsRequirements";
import type { NetworkRequirements } from "./NetworkRequirements";
import type { ResidencyRequirement } from "./ResidencyRequirement";
import type { SandboxMode } from "./SandboxMode";
import type { WindowsSandboxSetupMode } from "./WindowsSandboxSetupMode";
export type ConfigRequirements = { allowedApprovalPolicies: Array<AskForApproval> | null, allowedApprovalsReviewers: Array<ApprovalsReviewer> | null, allowedSandboxModes: Array<SandboxMode> | null, allowedWindowsSandboxImplementations: Array<WindowsSandboxSetupMode> | null, allowedPermissionProfiles: { [key in string]?: boolean } | null, defaultPermissions: string | null, allowedWebSearchModes: Array<WebSearchMode> | null, allowManagedHooksOnly: boolean | null, allowAppshots: boolean | null, allowRemoteControl: boolean | null, computerUse: ComputerUseRequirements | null, featureRequirements: { [key in string]?: boolean } | null, hooks: ManagedHooksRequirements | null, enforceResidency: ResidencyRequirement | null, network: NetworkRequirements | null, };
export type ConfigRequirements = { allowedApprovalPolicies: Array<AskForApproval> | null, allowedApprovalsReviewers: Array<ApprovalsReviewer> | null, allowedSandboxModes: Array<SandboxMode> | null, allowedWindowsSandboxImplementations: Array<WindowsSandboxSetupMode> | null, allowedPermissionProfiles: { [key in string]?: boolean } | null, defaultPermissions: string | null, allowedWebSearchModes: Array<WebSearchMode> | null, allowManagedHooksOnly: boolean | null, allowAppshots: boolean | null, allowRemoteControl: boolean | null, computerUse: ComputerUseRequirements | null, featureRequirements: { [key in string]?: boolean } | null, hooks: ManagedHooksRequirements | null, enforceResidency: ResidencyRequirement | null, network: NetworkRequirements | null, models: ModelsRequirements | null, };

View file

@ -7,4 +7,9 @@ export type ConsumeAccountRateLimitResetCreditParams = {
* Identifies one logical reset attempt. A UUID is recommended; reuse the same value when
* retrying that attempt.
*/
idempotencyKey: string, };
idempotencyKey: string,
/**
* Opaque reset-credit identifier to redeem. When omitted, the backend selects the next
* available credit.
*/
creditId?: string | null, };

View file

@ -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 EnvironmentInfoParams = { environmentId: string, };

View file

@ -0,0 +1,11 @@
// 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.
import type { PathUri } from "../PathUri";
import type { EnvironmentShellInfo } from "./EnvironmentShellInfo";
export type EnvironmentInfoResponse = { shell: EnvironmentShellInfo,
/**
* Default working directory reported by the environment, as a canonical file URI.
*/
cwd: PathUri | null, };

View file

@ -0,0 +1,13 @@
// 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 EnvironmentShellInfo = {
/**
* Stable shell name, for example `zsh`, `bash`, `powershell`, `sh`, or `cmd`.
*/
name: string,
/**
* Target-native shell executable path or command name.
*/
path: string, };

View file

@ -2,4 +2,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type McpServerOauthLoginCompletedNotification = { name: string, success: boolean, error?: string, };
export type McpServerOauthLoginCompletedNotification = { name: string, threadId: string | null, success: boolean, error?: string, };

View file

@ -2,4 +2,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type McpServerOauthLoginParams = { name: string, scopes?: Array<string> | null, timeoutSecs?: bigint | null, };
export type McpServerOauthLoginParams = { name: string, threadId?: string | null, scopes?: Array<string> | null, timeoutSecs?: bigint | null, };

View file

@ -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 McpServerStartupFailureReason = "reauthenticationRequired";

View file

@ -1,6 +1,7 @@
// 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.
import type { McpServerStartupFailureReason } from "./McpServerStartupFailureReason";
import type { McpServerStartupState } from "./McpServerStartupState";
export type McpServerStatusUpdatedNotification = { threadId: string | null, name: string, status: McpServerStartupState, error: string | null, };
export type McpServerStatusUpdatedNotification = { threadId: string | null, name: string, status: McpServerStartupState, error: string | null, failureReason: McpServerStartupFailureReason | null, };

View file

@ -2,4 +2,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type McpToolCallAppContext = { connectorId: string, linkId: string | null, resourceUri: string | null, };
export type McpToolCallAppContext = { connectorId: string, linkId: string | null, resourceUri: string | null, appName: string | null, templateId: string | null, actionName: string | null, };

View file

@ -6,6 +6,7 @@ import type { HookMigration } from "./HookMigration";
import type { McpServerMigration } from "./McpServerMigration";
import type { PluginsMigration } from "./PluginsMigration";
import type { SessionMigration } from "./SessionMigration";
import type { SkillMigration } from "./SkillMigration";
import type { SubagentMigration } from "./SubagentMigration";
export type MigrationDetails = { plugins: Array<PluginsMigration>, sessions: Array<SessionMigration>, mcpServers: Array<McpServerMigration>, hooks: Array<HookMigration>, subagents: Array<SubagentMigration>, commands: Array<CommandMigration>, };
export type MigrationDetails = { plugins: Array<PluginsMigration>, skills: Array<SkillMigration>, sessions: Array<SessionMigration>, mcpServers: Array<McpServerMigration>, hooks: Array<HookMigration>, subagents: Array<SubagentMigration>, commands: Array<CommandMigration>, };

View file

@ -0,0 +1,6 @@
// 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.
import type { NewThreadModelDefaults } from "./NewThreadModelDefaults";
export type ModelsRequirements = { newThread: NewThreadModelDefaults | null, };

View file

@ -0,0 +1,6 @@
// 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.
import type { ReasoningEffort } from "../ReasoningEffort";
export type NewThreadModelDefaults = { model: string | null, modelReasoningEffort: ReasoningEffort | null, serviceTier: string | null, };

View file

@ -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 PluginInstallPolicySource = "WORKSPACE_SETTING" | "IMPLICIT_CANONICAL_APP";

View file

@ -3,4 +3,12 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { AbsolutePathBuf } from "../AbsolutePathBuf";
export type PluginSource = { "type": "local", path: AbsolutePathBuf, } | { "type": "git", url: string, path: string | null, refName: string | null, sha: string | null, } | { "type": "remote" };
export type PluginSource = { "type": "local", path: AbsolutePathBuf, } | { "type": "git", url: string, path: string | null, refName: string | null, sha: string | null, } | { "type": "npm", package: string,
/**
* Optional npm version or version range.
*/
version: string | null,
/**
* Optional HTTPS registry URL. Authentication stays in the user's npm config.
*/
registry: string | null, } | { "type": "remote" };

View file

@ -4,6 +4,7 @@
import type { PluginAuthPolicy } from "./PluginAuthPolicy";
import type { PluginAvailability } from "./PluginAvailability";
import type { PluginInstallPolicy } from "./PluginInstallPolicy";
import type { PluginInstallPolicySource } from "./PluginInstallPolicySource";
import type { PluginInterface } from "./PluginInterface";
import type { PluginShareContext } from "./PluginShareContext";
import type { PluginSource } from "./PluginSource";
@ -13,6 +14,10 @@ export type PluginSummary = { id: string,
* Backend remote plugin identifier when available.
*/
remotePluginId: string | null,
/**
* Version advertised by the remote marketplace backend when available.
*/
version: string | null,
/**
* Version of the locally materialized plugin package when available.
*/
@ -20,7 +25,7 @@ localVersion: string | null, name: string,
/**
* Remote sharing context associated with this plugin when available.
*/
shareContext: PluginShareContext | null, source: PluginSource, installed: boolean, enabled: boolean, installPolicy: PluginInstallPolicy, authPolicy: PluginAuthPolicy,
shareContext: PluginShareContext | null, source: PluginSource, installed: boolean, enabled: boolean, installPolicy: PluginInstallPolicy, installPolicySource: PluginInstallPolicySource | null, authPolicy: PluginAuthPolicy,
/**
* Availability state for installing and using the plugin.
*/

View file

@ -0,0 +1,27 @@
// 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.
import type { RateLimitResetCreditStatus } from "./RateLimitResetCreditStatus";
import type { RateLimitResetType } from "./RateLimitResetType";
export type RateLimitResetCredit = {
/**
* Opaque backend identifier for this reset credit.
*/
id: string, resetType: RateLimitResetType, status: RateLimitResetCreditStatus,
/**
* Unix timestamp in seconds when the credit was granted.
*/
grantedAt: number,
/**
* Unix timestamp in seconds when the credit expires, or `null` if it does not expire.
*/
expiresAt: number | null,
/**
* Backend-provided display title for this credit, or `null` when unavailable.
*/
title: string | null,
/**
* Backend-provided display description for this credit, or `null` when unavailable.
*/
description: string | null, };

View file

@ -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 RateLimitResetCreditStatus = "available" | "redeeming" | "redeemed" | "unknown";

View file

@ -1,5 +1,14 @@
// 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.
import type { RateLimitResetCredit } from "./RateLimitResetCredit";
export type RateLimitResetCreditsSummary = { availableCount: bigint, };
export type RateLimitResetCreditsSummary = { availableCount: bigint,
/**
* Detail rows for available reset credits, when the backend provides them.
*
* `null` means only `availableCount` is known, while an empty array means details were fetched
* and no available credits were returned. The backend may cap this list, so its length can be
* less than `availableCount`.
*/
credits: Array<RateLimitResetCredit> | null, };

View file

@ -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 RateLimitResetType = "codexRateLimits" | "unknown";

View file

@ -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 SkillMigration = { name: string, };

View file

@ -4,11 +4,21 @@
import type { AbsolutePathBuf } from "../AbsolutePathBuf";
import type { GitInfo } from "./GitInfo";
import type { SessionSource } from "./SessionSource";
import type { ThreadExtra } from "./ThreadExtra";
import type { ThreadHistoryMode } from "./ThreadHistoryMode";
import type { ThreadSource } from "./ThreadSource";
import type { ThreadStatus } from "./ThreadStatus";
import type { Turn } from "./Turn";
export type Thread = { id: string,
export type Thread = {
/**
* Identifier for this thread. Codex-generated thread IDs are UUIDv7.
*/
id: string,
/**
* Optional implementation-specific thread data.
*/
extra: ThreadExtra | null,
/**
* Session id shared by threads that belong to the same session tree.
*/
@ -29,6 +39,10 @@ preview: string,
* Whether the thread is ephemeral and should not be materialized on disk.
*/
ephemeral: boolean,
/**
* Persisted thread history contract selected when this thread was created.
*/
historyMode: ThreadHistoryMode,
/**
* Model provider used for this thread (for example, 'openai').
*/

View file

@ -0,0 +1,8 @@
// 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.
/**
* Extra app-server data for a thread.
*/
export type ThreadExtra = Record<string, never>;

View file

@ -20,6 +20,13 @@ import type { ThreadSource } from "./ThreadSource";
* Prefer using thread_id whenever possible.
*/
export type ThreadForkParams = { threadId: string,
/**
* Optional last turn id to fork through, inclusive.
*
* When specified, turns after `last_turn_id` are omitted from the fork.
* The referenced turn cannot be in progress.
*/
lastTurnId?: string | null,
/**
* [UNSTABLE] Specify the rollout path to fork from.
* If specified, the thread_id param will be ignored.

View file

@ -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 ThreadHistoryMode = "legacy" | "paginated";

View file

@ -105,4 +105,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": "sleep", id: string, durationMs: number, } | { "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: LegacyAppPathString, } | { "type": "sleep", id: string, durationMs: number, } | { "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, };

View file

@ -3,7 +3,11 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { SortDirection } from "./SortDirection";
export type ThreadTurnsItemsListParams = { threadId: string, turnId: string,
export type ThreadItemsListParams = { threadId: string,
/**
* Optional turn id to filter by. When omitted, returns items across the thread.
*/
turnId?: string | null,
/**
* Opaque cursor to pass to the next call to continue after the last item.
*/

View file

@ -3,7 +3,7 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { ThreadItem } from "./ThreadItem";
export type ThreadTurnsItemsListResponse = { data: Array<ThreadItem>,
export type ThreadItemsListResponse = { data: Array<ThreadItem>,
/**
* Opaque cursor to pass to the next call to continue after the last item.
* if None, there are no more items to return.

View file

@ -53,6 +53,11 @@ useStateDbOnly?: boolean,
*/
searchTerm?: string | null,
/**
* Optional direct parent thread filter.
* Optional direct parent thread filter. Mutually exclusive with `ancestorThreadId`.
*/
parentThreadId?: string | null, };
parentThreadId?: string | null,
/**
* Optional ancestor thread filter. Returns spawned descendants at any depth, excluding the
* ancestor itself. Mutually exclusive with `parentThreadId`.
*/
ancestorThreadId?: string | null, };

View file

@ -16,6 +16,11 @@ export type ThreadRealtimeStartParams = { threadId: string,
* them automatically. Defaults to false.
*/
clientManagedHandoffs?: boolean | null,
/**
* Routes any transcript tail remaining at session end through Codex. Defaults to false.
* TODO: Remove this rollout knob once transcript-tail flushing is always enabled.
*/
flushTranscriptTailOnSessionEnd?: boolean | null,
/**
* Sends automatic Codex responses as realtime conversation items instead of handoff appends.
*/

View file

@ -2,6 +2,9 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
/**
* DEPRECATED: `thread/rollback` will be removed soon.
*/
export type ThreadRollbackParams = { threadId: string,
/**
* The number of turns to drop from the end of the thread. Must be >= 1.

View file

@ -11,11 +11,17 @@ import type { AskForApproval } from "./AskForApproval";
import type { DynamicToolSpec } from "./DynamicToolSpec";
import type { SandboxMode } from "./SandboxMode";
import type { SelectedCapabilityRoot } from "./SelectedCapabilityRoot";
import type { ThreadHistoryMode } from "./ThreadHistoryMode";
import type { ThreadSource } from "./ThreadSource";
import type { ThreadStartSource } from "./ThreadStartSource";
import type { TurnEnvironmentParams } from "./TurnEnvironmentParams";
export type ThreadStartParams = { model?: string | null, modelProvider?: string | null, serviceTier?: string | null, cwd?: string | null,
export type ThreadStartParams = { model?: string | null, modelProvider?: string | null,
/**
* Allow a provider with an authoritative static model catalog to replace an unavailable
* requested model with its default.
*/
allowProviderModelFallback?: boolean, serviceTier?: string | null, cwd?: string | null,
/**
* Replace the thread's runtime workspace roots. Paths must be absolute.
*/
@ -32,7 +38,11 @@ permissions?: string | null, config?: { [key in string]?: JsonValue } | null, se
/**
* @deprecated Ignored. Use Ultra reasoning effort for proactive multi-agent behavior.
*/
multiAgentMode?: MultiAgentMode | null, ephemeral?: boolean | null, sessionStartSource?: ThreadStartSource | null,
multiAgentMode?: MultiAgentMode | null, ephemeral?: boolean | null,
/**
* Persisted thread history contract to use for this new thread.
*/
historyMode?: ThreadHistoryMode | null, sessionStartSource?: ThreadStartSource | null,
/**
* Optional client-supplied analytics source classification for this thread.
*/

View file

@ -6,7 +6,11 @@ import type { TurnError } from "./TurnError";
import type { TurnItemsView } from "./TurnItemsView";
import type { TurnStatus } from "./TurnStatus";
export type Turn = { id: string,
export type Turn = {
/**
* Identifier for this turn. Codex-generated turn IDs are UUIDv7.
*/
id: string,
/**
* Thread items currently included in this turn payload.
*/

View file

@ -105,6 +105,9 @@ export type { DynamicToolNamespaceTool } from "./DynamicToolNamespaceTool";
export type { DynamicToolSpec } from "./DynamicToolSpec";
export type { EnvironmentAddParams } from "./EnvironmentAddParams";
export type { EnvironmentAddResponse } from "./EnvironmentAddResponse";
export type { EnvironmentInfoParams } from "./EnvironmentInfoParams";
export type { EnvironmentInfoResponse } from "./EnvironmentInfoResponse";
export type { EnvironmentShellInfo } from "./EnvironmentShellInfo";
export type { ErrorNotification } from "./ErrorNotification";
export type { ExecPolicyAmendment } from "./ExecPolicyAmendment";
export type { ExperimentalFeature } from "./ExperimentalFeature";
@ -244,6 +247,7 @@ export type { McpServerOauthLoginCompletedNotification } from "./McpServerOauthL
export type { McpServerOauthLoginParams } from "./McpServerOauthLoginParams";
export type { McpServerOauthLoginResponse } from "./McpServerOauthLoginResponse";
export type { McpServerRefreshResponse } from "./McpServerRefreshResponse";
export type { McpServerStartupFailureReason } from "./McpServerStartupFailureReason";
export type { McpServerStartupState } from "./McpServerStartupState";
export type { McpServerStatus } from "./McpServerStatus";
export type { McpServerStatusDetail } from "./McpServerStatusDetail";
@ -275,6 +279,7 @@ export type { ModelServiceTier } from "./ModelServiceTier";
export type { ModelUpgradeInfo } from "./ModelUpgradeInfo";
export type { ModelVerification } from "./ModelVerification";
export type { ModelVerificationNotification } from "./ModelVerificationNotification";
export type { ModelsRequirements } from "./ModelsRequirements";
export type { NetworkAccess } from "./NetworkAccess";
export type { NetworkApprovalContext } from "./NetworkApprovalContext";
export type { NetworkApprovalProtocol } from "./NetworkApprovalProtocol";
@ -283,6 +288,7 @@ export type { NetworkPolicyAmendment } from "./NetworkPolicyAmendment";
export type { NetworkPolicyRuleAction } from "./NetworkPolicyRuleAction";
export type { NetworkRequirements } from "./NetworkRequirements";
export type { NetworkUnixSocketPermission } from "./NetworkUnixSocketPermission";
export type { NewThreadModelDefaults } from "./NewThreadModelDefaults";
export type { NonSteerableTurnKind } from "./NonSteerableTurnKind";
export type { OverriddenMetadata } from "./OverriddenMetadata";
export type { PatchApplyStatus } from "./PatchApplyStatus";
@ -300,6 +306,7 @@ export type { PluginDetail } from "./PluginDetail";
export type { PluginHookSummary } from "./PluginHookSummary";
export type { PluginInstallParams } from "./PluginInstallParams";
export type { PluginInstallPolicy } from "./PluginInstallPolicy";
export type { PluginInstallPolicySource } from "./PluginInstallPolicySource";
export type { PluginInstallResponse } from "./PluginInstallResponse";
export type { PluginInstalledParams } from "./PluginInstalledParams";
export type { PluginInstalledResponse } from "./PluginInstalledResponse";
@ -349,7 +356,10 @@ export type { ProcessTerminalSize } from "./ProcessTerminalSize";
export type { ProcessWriteStdinParams } from "./ProcessWriteStdinParams";
export type { ProcessWriteStdinResponse } from "./ProcessWriteStdinResponse";
export type { RateLimitReachedType } from "./RateLimitReachedType";
export type { RateLimitResetCredit } from "./RateLimitResetCredit";
export type { RateLimitResetCreditStatus } from "./RateLimitResetCreditStatus";
export type { RateLimitResetCreditsSummary } from "./RateLimitResetCreditsSummary";
export type { RateLimitResetType } from "./RateLimitResetType";
export type { RateLimitSnapshot } from "./RateLimitSnapshot";
export type { RateLimitWindow } from "./RateLimitWindow";
export type { RawResponseItemCompletedNotification } from "./RawResponseItemCompletedNotification";
@ -393,6 +403,7 @@ export type { SkillDependencies } from "./SkillDependencies";
export type { SkillErrorInfo } from "./SkillErrorInfo";
export type { SkillInterface } from "./SkillInterface";
export type { SkillMetadata } from "./SkillMetadata";
export type { SkillMigration } from "./SkillMigration";
export type { SkillScope } from "./SkillScope";
export type { SkillSummary } from "./SkillSummary";
export type { SkillToolDependency } from "./SkillToolDependency";
@ -434,6 +445,7 @@ export type { ThreadDecrementElicitationResponse } from "./ThreadDecrementElicit
export type { ThreadDeleteParams } from "./ThreadDeleteParams";
export type { ThreadDeleteResponse } from "./ThreadDeleteResponse";
export type { ThreadDeletedNotification } from "./ThreadDeletedNotification";
export type { ThreadExtra } from "./ThreadExtra";
export type { ThreadForkParams } from "./ThreadForkParams";
export type { ThreadForkResponse } from "./ThreadForkResponse";
export type { ThreadGoal } from "./ThreadGoal";
@ -446,11 +458,14 @@ export type { ThreadGoalSetParams } from "./ThreadGoalSetParams";
export type { ThreadGoalSetResponse } from "./ThreadGoalSetResponse";
export type { ThreadGoalStatus } from "./ThreadGoalStatus";
export type { ThreadGoalUpdatedNotification } from "./ThreadGoalUpdatedNotification";
export type { ThreadHistoryMode } from "./ThreadHistoryMode";
export type { ThreadIncrementElicitationParams } from "./ThreadIncrementElicitationParams";
export type { ThreadIncrementElicitationResponse } from "./ThreadIncrementElicitationResponse";
export type { ThreadInjectItemsParams } from "./ThreadInjectItemsParams";
export type { ThreadInjectItemsResponse } from "./ThreadInjectItemsResponse";
export type { ThreadItem } from "./ThreadItem";
export type { ThreadItemsListParams } from "./ThreadItemsListParams";
export type { ThreadItemsListResponse } from "./ThreadItemsListResponse";
export type { ThreadListParams } from "./ThreadListParams";
export type { ThreadListResponse } from "./ThreadListResponse";
export type { ThreadLoadedListParams } from "./ThreadLoadedListParams";
@ -512,8 +527,6 @@ export type { ThreadStatus } from "./ThreadStatus";
export type { ThreadStatusChangedNotification } from "./ThreadStatusChangedNotification";
export type { ThreadTokenUsage } from "./ThreadTokenUsage";
export type { ThreadTokenUsageUpdatedNotification } from "./ThreadTokenUsageUpdatedNotification";
export type { ThreadTurnsItemsListParams } from "./ThreadTurnsItemsListParams";
export type { ThreadTurnsItemsListResponse } from "./ThreadTurnsItemsListResponse";
export type { ThreadTurnsListParams } from "./ThreadTurnsListParams";
export type { ThreadTurnsListResponse } from "./ThreadTurnsListResponse";
export type { ThreadUnarchiveParams } from "./ThreadUnarchiveParams";

View file

@ -443,18 +443,20 @@ function threadStartResponse(threadId: string): ThreadStartResponse {
activePermissionProfile: null,
sandbox: { type: "readOnly", networkAccess: false },
reasoningEffort: null,
multiAgentMode: "none",
multiAgentMode: "explicitRequestOnly",
};
}
function thread(id: string): AppServerThread {
return {
id,
extra: null,
sessionId: "session",
forkedFromId: null,
parentThreadId: null,
preview: "",
ephemeral: true,
historyMode: "paginated",
modelProvider: "openai",
createdAt: 1,
updatedAt: 1,

View file

@ -46,11 +46,13 @@ function responseFixture(thread: AppServerThread): ThreadResumeResponse {
function threadFixture(id: string, name: string): AppServerThread {
return {
id,
extra: null,
sessionId: "session",
forkedFromId: null,
parentThreadId: null,
preview: "",
ephemeral: false,
historyMode: "paginated",
modelProvider: "openai",
createdAt: 1,
updatedAt: 1,

View file

@ -309,18 +309,20 @@ function threadStartResponse(threadId: string): ThreadStartResponse {
activePermissionProfile: null,
sandbox: { type: "readOnly", networkAccess: false },
reasoningEffort: null,
multiAgentMode: "none",
multiAgentMode: "explicitRequestOnly",
};
}
function threadFixture(id: string): ThreadStartResponse["thread"] {
return {
id,
extra: null,
sessionId: "session",
forkedFromId: null,
parentThreadId: null,
preview: "",
ephemeral: true,
historyMode: "paginated",
modelProvider: "openai",
createdAt: 1,
updatedAt: 1,

View file

@ -731,11 +731,13 @@ function startThreadClient(startThread: ReturnType<typeof vi.fn>): AppServerClie
function threadFixture(id: string, overrides: Partial<ThreadStartResponse["thread"]> = {}): ThreadStartResponse["thread"] {
return {
id,
extra: null,
sessionId: id,
forkedFromId: null,
parentThreadId: null,
preview: "",
ephemeral: false,
historyMode: "paginated",
modelProvider: "openai",
createdAt: 0,
updatedAt: 0,

View file

@ -707,6 +707,7 @@ describe("ChatInboundHandler", () => {
name: "github",
status: "failed",
error: "missing token",
failureReason: null,
},
} satisfies Extract<ServerNotification, { method: "mcpServer/startupStatus/updated" }>);
@ -738,7 +739,7 @@ describe("ChatInboundHandler", () => {
handler.handleNotification({
method: "mcpServer/oauthLogin/completed",
params: { name: "github", success: true },
params: { name: "github", threadId: null, success: true },
} satisfies Extract<ServerNotification, { method: "mcpServer/oauthLogin/completed" }>);
expect(refreshServerDiagnostics).toHaveBeenCalledWith({ forceResourceProbes: true });
@ -2165,11 +2166,13 @@ function mcpElicitationRequest(id: number): ServerRequest {
function appServerThread(id: string, cwd: string): ThreadStartedNotification["params"]["thread"] {
return {
id,
extra: null,
sessionId: id,
forkedFromId: null,
parentThreadId: null,
preview: "",
ephemeral: false,
historyMode: "paginated",
modelProvider: "openai",
createdAt: 0,
updatedAt: 0,

View file

@ -665,7 +665,7 @@ function mcpStartupStatusNotification(): ServerNotification {
function mcpStartupStatusNotificationForThread(threadId: string | null): ServerNotification {
return {
method: "mcpServer/startupStatus/updated",
params: { threadId, name: "github", status: "failed", error: "missing token" },
params: { threadId, name: "github", status: "failed", error: "missing token", failureReason: null },
};
}
@ -738,11 +738,13 @@ function rawResponseItemCompletedNotification(
function threadSnapshot(id: string): Extract<ServerNotification, { method: "thread/started" }>["params"]["thread"] {
return {
id,
extra: null,
sessionId: "session",
forkedFromId: null,
parentThreadId: null,
preview: "Preview",
ephemeral: false,
historyMode: "paginated",
modelProvider: "openai",
createdAt: 1,
updatedAt: 1,

View file

@ -451,7 +451,7 @@ function threadResumeResponse(threadId: string, overrides: Partial<AppServerThre
sandbox: { type: "readOnly", networkAccess: false },
activePermissionProfile: null,
reasoningEffort: null,
multiAgentMode: "none",
multiAgentMode: "explicitRequestOnly",
initialTurnsPage: null,
...overrides,
};

View file

@ -20,7 +20,6 @@ import { chatStateFixture } from "../../support/state";
interface ThreadMutationTransportMock {
compactThread: Mock<ThreadMutationTransport["compactThread"]>;
forkThread: Mock<ThreadMutationTransport["forkThread"]>;
rollbackForkedThread: Mock<ThreadMutationTransport["rollbackForkedThread"]>;
rollbackThread: Mock<ThreadMutationTransport["rollbackThread"]>;
}
@ -164,20 +163,16 @@ describe("thread management actions", () => {
expect(host.addSystemMessage).toHaveBeenCalledWith("disk full");
});
it("forks from a selected turn by dropping later turns on the fork", async () => {
it("forks through a selected turn", async () => {
const host = hostMock({ items: turnItems() });
const controller = threadManagementActions(host);
await controller.forkThreadFromTurn("source", "turn-1", false);
expect(host.threadTransport.forkThread).toHaveBeenCalledWith("source");
expect(host.threadTransport.rollbackForkedThread).toHaveBeenCalledWith("forked", 2);
expect(host.threadTransport.forkThread).toHaveBeenCalledWith("source", "turn-1");
expect(host.recordForkedThread).toHaveBeenCalledWith(
expect.objectContaining({
id: "forked",
name: "Rolled Back Thread",
preview: "Post-rollback",
updatedAt: 20,
}),
);
expect(host.openThreadInNewView).toHaveBeenCalledWith("forked");
@ -191,7 +186,7 @@ describe("thread management actions", () => {
await controller.forkThreadFromTurn("source", "turn-3", true);
expect(host.threadTransport.forkThread).toHaveBeenCalledWith("source");
expect(host.threadTransport.forkThread).toHaveBeenCalledWith("source", "turn-3");
expect(host.operations.archiveThread).toHaveBeenCalledWith("source", {});
expect(host.openThreadInCurrentPanel).toHaveBeenCalledWith("forked");
expect(callOrder(host.operations.archiveThread)).toBeLessThan(callOrder(host.openThreadInCurrentPanel));
@ -208,7 +203,6 @@ describe("thread management actions", () => {
await controller.forkThreadFromTurn("source", "turn-3", true);
expect(host.threadTransport.rollbackForkedThread).not.toHaveBeenCalled();
expect(host.operations.archiveThread).toHaveBeenCalledWith("source", {});
expect(host.openThreadInCurrentPanel).not.toHaveBeenCalled();
expect(host.addSystemMessage).toHaveBeenCalledWith("archive failed");
@ -530,13 +524,6 @@ function hostMock({
const threadTransport: ThreadMutationTransportMock = {
compactThread: vi.fn<ThreadMutationTransport["compactThread"]>().mockResolvedValue(true),
forkThread: vi.fn<ThreadMutationTransport["forkThread"]>().mockResolvedValue(panelThread("forked")),
rollbackForkedThread: vi.fn<ThreadMutationTransport["rollbackForkedThread"]>().mockResolvedValue(
panelThread("forked", {
name: "Rolled Back Thread",
preview: "Post-rollback",
updatedAt: 20,
}),
),
rollbackThread: vi.fn<ThreadMutationTransport["rollbackThread"]>().mockResolvedValue(rollbackSnapshot()),
...transportOverrides,
};

View file

@ -902,18 +902,20 @@ function threadStartResponse(threadId: string): ThreadStartResponse {
activePermissionProfile: null,
sandbox: { type: "readOnly", networkAccess: false },
reasoningEffort: null,
multiAgentMode: "none",
multiAgentMode: "explicitRequestOnly",
};
}
function thread(id: string): ThreadStartResponse["thread"] {
return {
id,
extra: null,
sessionId: "session",
forkedFromId: null,
parentThreadId: null,
preview: "",
ephemeral: true,
historyMode: "paginated",
modelProvider: "openai",
createdAt: 1,
updatedAt: 1,

View file

@ -639,7 +639,7 @@ describe("runtime settings", () => {
model: setRuntimeIntentValue("gpt-pending"),
reasoningEffort: setRuntimeIntentValue("low"),
permissionProfile: setRuntimeIntentValue(":workspace"),
approvalPolicy: setRuntimeIntentValue("on-failure"),
approvalPolicy: setRuntimeIntentValue("on-request"),
approvalsReviewer: setRuntimeIntentValue("guardian_subagent"),
fastMode: setRuntimeIntentValue("enabled"),
},
@ -673,7 +673,7 @@ describe("runtime settings", () => {
effective: null,
source: "pending",
},
approvalPolicy: { confirmed: "never", confirmedSource: "active-thread", effective: "on-failure", source: "pending" },
approvalPolicy: { confirmed: "never", confirmedSource: "active-thread", effective: "on-request", source: "pending" },
approvalsReviewer: { confirmed: "user", confirmedSource: "active-thread", effective: "guardian_subagent", source: "pending" },
serviceTier: { confirmed: "flex", confirmedSource: "active-thread", effective: "fast", source: "pending" },
fastMode: {