diff --git a/apps/desktop/src/preview/BrowserSession.test.ts b/apps/desktop/src/preview/BrowserSession.test.ts index e258bb2dfc5a..743fd6a1fcec 100644 --- a/apps/desktop/src/preview/BrowserSession.test.ts +++ b/apps/desktop/src/preview/BrowserSession.test.ts @@ -15,6 +15,7 @@ const { fromPartition, sessions } = vi.hoisted(() => ({ readonly clearStorageData: ReturnType; readonly getUserAgent: ReturnType; readonly setPermissionRequestHandler: ReturnType; + readonly setPermissionCheckHandler: ReturnType; readonly setUserAgent: ReturnType; } >(), @@ -40,6 +41,7 @@ describe("BrowserSession", () => { clearStorageData: vi.fn(() => Promise.resolve()), getUserAgent: vi.fn(() => "Mozilla/5.0 Electron/41.5.0 t3code/0.0.27"), setPermissionRequestHandler: vi.fn(), + setPermissionCheckHandler: vi.fn(), setUserAgent: vi.fn(), }; sessions.set(partition, browserSession); @@ -61,6 +63,55 @@ describe("BrowserSession", () => { }).pipe(Effect.provide(layer)), ); + it.effect("grants clipboard-sanitized-write through both the request and check handlers", () => + Effect.gen(function* () { + const browserSessions = yield* BrowserSession.BrowserSession; + const partition = yield* browserSessions.getPartition("scope-a"); + yield* browserSessions.getSession("scope-a"); + + const browserSession = sessions.get(partition); + assert.isDefined(browserSession); + + const requestHandler = browserSession.setPermissionRequestHandler.mock.calls[0]?.[0]; + const checkHandler = browserSession.setPermissionCheckHandler.mock.calls[0]?.[0]; + assert.isFunction(requestHandler); + assert.isFunction(checkHandler); + + const requestAllows = (permission: string): boolean => { + let granted: boolean | undefined; + requestHandler(null, permission, (value: boolean) => { + granted = value; + }); + assert.isDefined(granted); + return granted; + }; + + for (const permission of [ + "clipboard-read", + "clipboard-sanitized-write", + "notifications", + "geolocation", + ]) { + assert.isTrue(requestAllows(permission), `request handler should allow ${permission}`); + assert.isTrue( + checkHandler(null, permission) as boolean, + `check handler should allow ${permission}`, + ); + } + + // `clipboard-write` is not a real Electron permission — the async write API + // uses `clipboard-sanitized-write` — so the stale name must not be granted, + // and unrelated permissions stay denied. + for (const permission of ["clipboard-write", "midi"]) { + assert.isFalse(requestAllows(permission), `request handler should deny ${permission}`); + assert.isFalse( + checkHandler(null, permission) as boolean, + `check handler should deny ${permission}`, + ); + } + }).pipe(Effect.provide(layer)), + ); + it.effect("preserves partition scope and the platform failure chain", () => { const nativeCause = new Error("native digest failed"); const platformCause = PlatformError.systemError({ diff --git a/apps/desktop/src/preview/BrowserSession.ts b/apps/desktop/src/preview/BrowserSession.ts index afa8dafe976f..aa0b0743e933 100644 --- a/apps/desktop/src/preview/BrowserSession.ts +++ b/apps/desktop/src/preview/BrowserSession.ts @@ -11,6 +11,20 @@ import * as SynchronizedRef from "effect/SynchronizedRef"; const PREVIEW_PARTITION_PREFIX = "persist:t3code-preview-"; +// Permissions granted to preview web content. `clipboard-sanitized-write` is the +// Electron permission behind `navigator.clipboard.writeText()` — note it is NOT +// `clipboard-write`, which is not a valid Electron permission name. Async +// clipboard writes are gated by the permission *check* handler (not only the +// request handler), so both handlers must allow it; otherwise built-in "Copy" +// buttons — e.g. the Next.js / Vercel error overlay — fail with +// `Failed to execute 'writeText' on 'Clipboard': Write permission denied`. +const ALLOWED_PREVIEW_PERMISSIONS: ReadonlySet = new Set([ + "clipboard-read", + "clipboard-sanitized-write", + "notifications", + "geolocation", +]); + export class BrowserSessionPartitionDerivationError extends Schema.TaggedErrorClass()( "BrowserSessionPartitionDerivationError", { @@ -120,9 +134,11 @@ export const make = Effect.gen(function* BrowserSessionMake() { .replace(/\s*t3code\/[\d.]+/, ""); browserSession.setUserAgent(userAgent); browserSession.setPermissionRequestHandler((_webContents, permission, callback) => { - const allowed = ["clipboard-read", "clipboard-write", "notifications", "geolocation"]; - callback(allowed.includes(permission)); + callback(ALLOWED_PREVIEW_PERMISSIONS.has(permission)); }); + browserSession.setPermissionCheckHandler((_webContents, permission) => + ALLOWED_PREVIEW_PERMISSIONS.has(permission), + ); const next = new Map(sessions); next.set(partition, browserSession); return [browserSession, next] as const; diff --git a/apps/mobile/src/Stack.tsx b/apps/mobile/src/Stack.tsx index 0023340ce4b9..4dee5681a9d0 100644 --- a/apps/mobile/src/Stack.tsx +++ b/apps/mobile/src/Stack.tsx @@ -15,7 +15,6 @@ import { DynamicColorIOS, Platform, Pressable, ScrollView, StyleSheet } from "re import { useResolveClassNames } from "uniwind"; import { AppText as Text } from "./components/AppText"; -import { renderCompactBrandTitle } from "./components/CompactBrandTitle"; import { ArchivedThreadsRouteScreen } from "./features/archive/ArchivedThreadsRouteScreen"; import { useAgentNotificationNavigation } from "./features/agent-awareness/notificationNavigation"; import { ClerkSettingsSheetDetentProvider } from "./features/cloud/ClerkSettingsSheetDetent"; @@ -60,6 +59,7 @@ import { EMPTY_INCOMING_SHARE_PRESENTATION_STATE, transitionIncomingSharePresentation, } from "./features/sharing/incoming-share-presentation"; +import { NATIVE_LIQUID_GLASS_SUPPORTED } from "./native/native-glass"; import { nativeHeaderScrollEdgeEffects } from "./native/StackHeader"; import { useThreadOutboxDrain } from "./state/use-thread-outbox-drain"; @@ -81,19 +81,24 @@ type AppScreenOptions = NativeStackNavigationOptions & { // Shared header presets. Screens only override genuinely dynamic values (titles, // subtitles, toolbar items, search callbacks) via NativeStackScreenOptions. // -// GLASS: transparent header over the screen's primary scroll view, with the iOS 26 -// scroll-edge blur sampling the content (Home, Thread, Files tree, settings sheet). +// GLASS: transparent header over the screen's primary scroll view on supported +// iOS versions. Pre-glass iOS gets the same solid material as internal-scroll +// surfaces so content is laid out below the bar instead of underlapping it. const GLASS_HEADER_OPTIONS: AppScreenOptions = { headerBackButtonDisplayMode: "minimal", headerBackTitle: "", headerLargeTitle: false, headerShadowVisible: false, headerShown: true, - headerStyle: Platform.OS === "ios" ? { backgroundColor: "transparent" } : undefined, + headerStyle: NATIVE_LIQUID_GLASS_SUPPORTED + ? { backgroundColor: "transparent" } + : SHEET_BACKGROUND_COLOR !== undefined + ? { backgroundColor: SHEET_BACKGROUND_COLOR as unknown as string } + : undefined, headerTitleStyle: { fontSize: 18, fontWeight: "800" }, - headerTransparent: Platform.OS === "ios", - scrollEdgeEffects: Platform.OS === "ios" ? HEADER_SCROLL_EDGE_EFFECTS : undefined, - unstable_navigationItemStyle: Platform.OS === "ios" ? "editor" : undefined, + headerTransparent: NATIVE_LIQUID_GLASS_SUPPORTED, + scrollEdgeEffects: NATIVE_LIQUID_GLASS_SUPPORTED ? HEADER_SCROLL_EDGE_EFFECTS : undefined, + unstable_navigationItemStyle: NATIVE_LIQUID_GLASS_SUPPORTED ? "editor" : undefined, }; // SOLID: opaque sheet-colored header for surfaces whose content scrolls internally @@ -384,8 +389,7 @@ export const RootStack = createNativeStackNavigator({ ...GLASS_HEADER_OPTIONS, contentStyle: { backgroundColor: "transparent" }, headerBackVisible: false, - headerTitle: renderCompactBrandTitle, - title: "T3 Code", + title: "Threads", }, }), Thread: createNativeStackScreen({ diff --git a/apps/mobile/src/components/CompactBrandTitle.tsx b/apps/mobile/src/components/CompactBrandTitle.tsx deleted file mode 100644 index 2ecf34aa40cd..000000000000 --- a/apps/mobile/src/components/CompactBrandTitle.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import { View } from "react-native"; - -import { AppText as Text } from "./AppText"; -import { T3Wordmark } from "./T3Wordmark"; -import { useThemeColor } from "../lib/useThemeColor"; - -/** - * Compact brand lockup sized for native navigation bars. - */ -export function CompactBrandTitle() { - const iconColor = useThemeColor("--color-icon"); - const mutedColor = useThemeColor("--color-foreground-muted"); - const subtleColor = useThemeColor("--color-subtle"); - - return ( - - - - Code - - - - Alpha - - - - ); -} - -export function renderCompactBrandTitle() { - return ; -} diff --git a/apps/mobile/src/features/files/FileTreeBrowser.tsx b/apps/mobile/src/features/files/FileTreeBrowser.tsx index b29121201f56..dd7a12711949 100644 --- a/apps/mobile/src/features/files/FileTreeBrowser.tsx +++ b/apps/mobile/src/features/files/FileTreeBrowser.tsx @@ -1,20 +1,14 @@ import type { ProjectEntry } from "@t3tools/contracts"; import { SymbolView } from "../../components/AppSymbol"; import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react"; -import { - ActivityIndicator, - FlatList, - Platform, - Pressable, - RefreshControl, - View, -} from "react-native"; +import { ActivityIndicator, FlatList, Pressable, RefreshControl, View } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { AppText as Text } from "../../components/AppText"; import { PierreEntryIcon } from "../../components/PierreEntryIcon"; import { cn } from "../../lib/cn"; import { useThemeColor } from "../../lib/useThemeColor"; +import { NATIVE_LIQUID_GLASS_SUPPORTED } from "../../native/native-glass"; import { buildFileTree, defaultExpandedTreePaths, @@ -129,7 +123,7 @@ export function FileTreeBrowser(props: { const insets = useSafeAreaInsets(); // Native transparent-header height ≈ safe-area top + nav bar (~44). Matches the // observed adjustedContentInset bottom (~102) seen in the native trace. - const headerInset = Platform.OS === "ios" ? insets.top + 44 : 0; + const headerInset = NATIVE_LIQUID_GLASS_SUPPORTED ? insets.top + 44 : 0; const iconColor = String(useThemeColor("--color-icon-muted")); const { onPreviewFile, onSelectFile, selectedPath: controlledSelectedPath } = props; const controlledSelectedPathRef = useRef(controlledSelectedPath); @@ -249,9 +243,11 @@ export function FileTreeBrowser(props: { className="flex-1" data={visibleNodes} keyExtractor={(item) => item.node.path} - contentInsetAdjustmentBehavior={Platform.OS === "ios" ? "automatic" : "never"} + contentInsetAdjustmentBehavior={NATIVE_LIQUID_GLASS_SUPPORTED ? "automatic" : "never"} scrollIndicatorInsets={ - Platform.OS === "ios" ? { top: headerInset, left: 0, right: 0, bottom: 0 } : undefined + NATIVE_LIQUID_GLASS_SUPPORTED + ? { top: headerInset, left: 0, right: 0, bottom: 0 } + : undefined } keyboardDismissMode="on-drag" keyboardShouldPersistTaps="handled" diff --git a/apps/mobile/src/features/home/HomeRouteScreen.tsx b/apps/mobile/src/features/home/HomeRouteScreen.tsx index cd9467c774e8..49cf06d85ec7 100644 --- a/apps/mobile/src/features/home/HomeRouteScreen.tsx +++ b/apps/mobile/src/features/home/HomeRouteScreen.tsx @@ -4,7 +4,6 @@ import { useNavigation } from "@react-navigation/native"; import { useMemo, useState } from "react"; import { NativeHeaderToolbar, NativeStackScreenOptions } from "../../native/StackHeader"; -import { renderCompactBrandTitle } from "../../components/CompactBrandTitle"; import { useProjects, useThreadShells } from "../../state/entities"; import { usePendingNewTasks } from "../../state/use-pending-new-tasks"; import { useWorkspaceState } from "../../state/workspace"; @@ -87,9 +86,7 @@ export function HomeRouteScreen() { > <> {/* Restore the compact title in case the split branch blanked it. */} - + @@ -399,11 +400,20 @@ export function HomeScreen(props: HomeScreenProps) { onAction={!props.catalogState.hasReadyEnvironment ? props.onAddConnection : undefined} variant="plain" /> - {emptyState.loading ? ( + {emptyState.loading && !shouldShowConnectionStatus ? ( ) : null} + {shouldShowConnectionStatus && Platform.OS === "ios" ? ( + + + + ) : null} {connectionStatus} @@ -460,8 +470,8 @@ export function HomeScreen(props: HomeScreenProps) { ListHeaderComponent={listHeader} ListEmptyComponent={listEmpty} style={{ flex: 1 }} - automaticallyAdjustsScrollIndicatorInsets={Platform.OS === "ios"} - contentInsetAdjustmentBehavior={Platform.OS === "ios" ? "automatic" : "never"} + automaticallyAdjustsScrollIndicatorInsets={NATIVE_LIQUID_GLASS_SUPPORTED} + contentInsetAdjustmentBehavior={NATIVE_LIQUID_GLASS_SUPPORTED ? "automatic" : "never"} showsVerticalScrollIndicator={false} keyboardDismissMode="on-drag" keyboardShouldPersistTaps="handled" diff --git a/apps/mobile/src/features/home/WorkspaceConnectionStatus.test.ts b/apps/mobile/src/features/home/WorkspaceConnectionStatus.test.ts index 767f0e3dd3f8..8c3c873cc9e8 100644 --- a/apps/mobile/src/features/home/WorkspaceConnectionStatus.test.ts +++ b/apps/mobile/src/features/home/WorkspaceConnectionStatus.test.ts @@ -67,4 +67,21 @@ describe("workspace connection status", () => { expect(shouldShowWorkspaceConnectionStatus(state)).toBe(true); expect(workspaceConnectionStatusLabel(state)).toBe("Could not reach Julius’s Mac mini"); }); + + it("shows shell catch-up while cached threads remain visible", () => { + const state = workspaceState({ hasPendingShellSnapshot: true }); + + expect(shouldShowWorkspaceConnectionStatus(state)).toBe(true); + expect(workspaceConnectionStatusLabel(state)).toBe("Syncing threads..."); + }); + + it("distinguishes initial shell loading from cached catch-up", () => { + const state = workspaceState({ + hasLoadedShellSnapshot: false, + hasPendingShellSnapshot: true, + }); + + expect(shouldShowWorkspaceConnectionStatus(state)).toBe(true); + expect(workspaceConnectionStatusLabel(state)).toBe("Loading threads..."); + }); }); diff --git a/apps/mobile/src/features/home/WorkspaceConnectionStatus.tsx b/apps/mobile/src/features/home/WorkspaceConnectionStatus.tsx index 8acdacfbbb37..1e986ad1a506 100644 --- a/apps/mobile/src/features/home/WorkspaceConnectionStatus.tsx +++ b/apps/mobile/src/features/home/WorkspaceConnectionStatus.tsx @@ -12,7 +12,10 @@ export function WorkspaceConnectionStatus(props: { readonly variant?: "floating" | "sidebar"; }) { const iconColor = useThemeColor("--color-icon-muted"); - const isReconnecting = props.state.connectingEnvironments.length > 0; + const isSynchronizing = + props.state.networkStatus !== "offline" && + props.state.connectionError === null && + (props.state.connectingEnvironments.length > 0 || props.state.hasPendingShellSnapshot); const variant = props.variant ?? "floating"; return ( @@ -37,7 +40,7 @@ export function WorkspaceConnectionStatus(props: { : undefined } > - {isReconnecting ? ( + {isSynchronizing ? ( ) : ( diff --git a/apps/mobile/src/features/home/workspace-connection-status.ts b/apps/mobile/src/features/home/workspace-connection-status.ts index 7d2c6d840d49..d8eed4383b18 100644 --- a/apps/mobile/src/features/home/workspace-connection-status.ts +++ b/apps/mobile/src/features/home/workspace-connection-status.ts @@ -5,6 +5,7 @@ export function shouldShowWorkspaceConnectionStatus(state: WorkspaceState): bool state.networkStatus === "offline" || state.connectionError !== null || state.hasConnectingEnvironment || + state.hasPendingShellSnapshot || (state.hasLoadedShellSnapshot && !state.hasReadyEnvironment) ); } @@ -18,5 +19,8 @@ export function workspaceConnectionStatusLabel(state: WorkspaceState): string { return `Reconnecting ${state.connectingEnvironments.length} environments`; } if (state.connectionError !== null) return state.connectionError; + if (state.hasPendingShellSnapshot) { + return state.hasLoadedShellSnapshot ? "Syncing threads..." : "Loading threads..."; + } return "Not connected"; } diff --git a/apps/mobile/src/features/threads/ThreadDetailScreen.tsx b/apps/mobile/src/features/threads/ThreadDetailScreen.tsx index 31ad56609833..32527b0b719b 100644 --- a/apps/mobile/src/features/threads/ThreadDetailScreen.tsx +++ b/apps/mobile/src/features/threads/ThreadDetailScreen.tsx @@ -28,6 +28,7 @@ import type { StatusTone } from "../../components/StatusPill"; import type { DraftComposerImageAttachment } from "../../lib/composerImages"; import { CHAT_CONTENT_MAX_WIDTH, type LayoutVariant } from "../../lib/layout"; import { scopedThreadKey } from "../../lib/scopedEntities"; +import { NATIVE_LIQUID_GLASS_SUPPORTED } from "../../native/native-glass"; import type { PendingApproval, PendingUserInput, @@ -197,7 +198,13 @@ const WorkingDurationPill = memo(function WorkingDurationPill(props: { entering={FadeInDown.duration(200)} exiting={FadeOut.duration(140)} > - + diff --git a/apps/mobile/src/features/threads/ThreadNavigationSidebar.tsx b/apps/mobile/src/features/threads/ThreadNavigationSidebar.tsx index 6e0e243aad66..f7ee4eaa74fb 100644 --- a/apps/mobile/src/features/threads/ThreadNavigationSidebar.tsx +++ b/apps/mobile/src/features/threads/ThreadNavigationSidebar.tsx @@ -17,6 +17,7 @@ import Svg, { Defs, LinearGradient, Rect, Stop } from "react-native-svg"; import { AppText as Text } from "../../components/AppText"; import { ControlPillMenu } from "../../components/ControlPill"; import { SymbolView } from "../../components/AppSymbol"; +import { NATIVE_LIQUID_GLASS_SUPPORTED } from "../../native/native-glass"; import { NativeStackScreenOptions } from "../../native/StackHeader"; import { scopedProjectKey, scopedThreadKey } from "../../lib/scopedEntities"; import { useThemeColor } from "../../lib/useThemeColor"; @@ -571,8 +572,10 @@ function ThreadNavigationSidebarPane( itemsAreEqual={homeListItemsAreEqual} keyExtractor={(item) => item.key} renderItem={renderListItem} - automaticallyAdjustsScrollIndicatorInsets - contentInsetAdjustmentBehavior="automatic" + automaticallyAdjustsScrollIndicatorInsets={NATIVE_LIQUID_GLASS_SUPPORTED} + contentInsetAdjustmentBehavior={ + NATIVE_LIQUID_GLASS_SUPPORTED ? "automatic" : "never" + } contentContainerStyle={[ styles.threadListContent, { diff --git a/apps/mobile/src/features/threads/ThreadRouteScreen.tsx b/apps/mobile/src/features/threads/ThreadRouteScreen.tsx index e60f03bb8c36..7fb4740ddcef 100644 --- a/apps/mobile/src/features/threads/ThreadRouteScreen.tsx +++ b/apps/mobile/src/features/threads/ThreadRouteScreen.tsx @@ -23,6 +23,7 @@ import { } from "../../components/AndroidScreenHeader"; import { LoadingScreen } from "../../components/LoadingScreen"; import { scopedThreadKey } from "../../lib/scopedEntities"; +import { NATIVE_LIQUID_GLASS_SUPPORTED } from "../../native/native-glass"; import { connectionTone } from "../connection/connectionTone"; import { @@ -278,7 +279,7 @@ function ThreadRouteContent( ); /* ─── Native header theming ──────────────────────────────────────── */ - const usesNativeHeaderGlass = Platform.OS === "ios"; + const usesNativeHeaderGlass = NATIVE_LIQUID_GLASS_SUPPORTED; const headerSubtitle = [ selectedThreadProject?.title ?? null, selectedEnvironmentConnection?.environmentLabel ?? null, diff --git a/apps/mobile/src/features/threads/sidebar-navigation-shell.tsx b/apps/mobile/src/features/threads/sidebar-navigation-shell.tsx index a94c033fa4dc..f0e3f89c07dc 100644 --- a/apps/mobile/src/features/threads/sidebar-navigation-shell.tsx +++ b/apps/mobile/src/features/threads/sidebar-navigation-shell.tsx @@ -11,7 +11,7 @@ import { import type { ReactNode } from "react"; import { Platform, useColorScheme } from "react-native"; -import { renderCompactBrandTitle } from "../../components/CompactBrandTitle"; +import { NATIVE_LIQUID_GLASS_SUPPORTED } from "../../native/native-glass"; import { nativeHeaderScrollEdgeEffects } from "../../native/StackHeader"; const SCROLL_EDGE_EFFECTS = nativeHeaderScrollEdgeEffects(Platform.OS, Platform.Version); @@ -34,13 +34,12 @@ const SIDEBAR_SCREEN_OPTIONS: SidebarScreenOptions = { headerLargeTitle: false, headerShadowVisible: false, headerShown: true, - headerStyle: { backgroundColor: "transparent" }, - headerTitle: renderCompactBrandTitle, + headerStyle: NATIVE_LIQUID_GLASS_SUPPORTED ? { backgroundColor: "transparent" } : undefined, headerTitleStyle: { fontSize: 18, fontWeight: "800" }, - headerTransparent: true, - scrollEdgeEffects: SCROLL_EDGE_EFFECTS, - title: "T3 Code", - unstable_navigationItemStyle: "editor", + headerTransparent: NATIVE_LIQUID_GLASS_SUPPORTED, + scrollEdgeEffects: NATIVE_LIQUID_GLASS_SUPPORTED ? SCROLL_EDGE_EFFECTS : undefined, + title: "Threads", + unstable_navigationItemStyle: NATIVE_LIQUID_GLASS_SUPPORTED ? "editor" : undefined, }; const SidebarStack = createNativeStackNavigator(); diff --git a/apps/mobile/src/lib/native-glass-capability.test.ts b/apps/mobile/src/lib/native-glass-capability.test.ts new file mode 100644 index 000000000000..43f865c77c30 --- /dev/null +++ b/apps/mobile/src/lib/native-glass-capability.test.ts @@ -0,0 +1,18 @@ +import { describe, expect, it } from "vite-plus/test"; + +import { supportsNativeLiquidGlass } from "./native-glass-capability"; + +describe("supportsNativeLiquidGlass", () => { + it("uses native liquid glass when iOS reports the capability", () => { + expect(supportsNativeLiquidGlass("ios", true)).toBe(true); + }); + + it("keeps pre-glass iOS on the solid fallback", () => { + expect(supportsNativeLiquidGlass("ios", false)).toBe(false); + }); + + it("does not enable iOS liquid-glass layout behavior on other platforms", () => { + expect(supportsNativeLiquidGlass("android", true)).toBe(false); + expect(supportsNativeLiquidGlass("web", true)).toBe(false); + }); +}); diff --git a/apps/mobile/src/lib/native-glass-capability.ts b/apps/mobile/src/lib/native-glass-capability.ts new file mode 100644 index 000000000000..61c8547b5073 --- /dev/null +++ b/apps/mobile/src/lib/native-glass-capability.ts @@ -0,0 +1,6 @@ +export function supportsNativeLiquidGlass( + platform: string, + nativeCapabilityAvailable: boolean, +): boolean { + return platform === "ios" && nativeCapabilityAvailable; +} diff --git a/apps/mobile/src/native/native-glass.ts b/apps/mobile/src/native/native-glass.ts new file mode 100644 index 000000000000..40b28076d360 --- /dev/null +++ b/apps/mobile/src/native/native-glass.ts @@ -0,0 +1,9 @@ +import { isLiquidGlassSupported } from "@callstack/liquid-glass"; +import { Platform } from "react-native"; + +import { supportsNativeLiquidGlass } from "../lib/native-glass-capability"; + +export const NATIVE_LIQUID_GLASS_SUPPORTED = supportsNativeLiquidGlass( + Platform.OS, + isLiquidGlassSupported, +); diff --git a/apps/server/src/bin.test.ts b/apps/server/src/bin.test.ts index 16b7a7f715a4..999547b71d80 100644 --- a/apps/server/src/bin.test.ts +++ b/apps/server/src/bin.test.ts @@ -6,10 +6,16 @@ import * as NodePath from "node:path"; import * as NodeHttpServer from "@effect/platform-node/NodeHttpServer"; import * as NodeServices from "@effect/platform-node/NodeServices"; -import { EnvironmentOrchestrationHttpApi } from "@t3tools/contracts"; +import { + CommandId, + EnvironmentOrchestrationHttpApi, + ProviderInstanceId, + ThreadId, +} from "@t3tools/contracts"; import * as NetService from "@t3tools/shared/Net"; import { assert, it } from "@effect/vitest"; import * as Effect from "effect/Effect"; +import * as DateTime from "effect/DateTime"; import * as Layer from "effect/Layer"; import * as HttpRouter from "effect/unstable/http/HttpRouter"; import * as HttpServer from "effect/unstable/http/HttpServer"; @@ -22,6 +28,7 @@ import { Command } from "effect/unstable/cli"; import { cli, makeCli } from "./bin.ts"; import * as ServerConfig from "./config.ts"; import * as ProjectionSnapshotQuery from "./orchestration/Services/ProjectionSnapshotQuery.ts"; +import * as OrchestrationEngine from "./orchestration/Services/OrchestrationEngine.ts"; import { OrchestrationLayerLive } from "./orchestration/runtimeLayer.ts"; import { orchestrationHttpApiLayer } from "./orchestration/http.ts"; import { layerConfig as SqlitePersistenceLayerLive } from "./persistence/Layers/Sqlite.ts"; @@ -460,6 +467,63 @@ it.layer(NodeServices.layer)("bin cli parsing", (it) => { }), ); + it.effect("force removes projects that still contain threads", () => + Effect.gen(function* () { + const baseDir = NodeFS.mkdtempSync( + NodePath.join(NodeOS.tmpdir(), "t3-cli-projects-force-remove-test-"), + ); + const workspaceRoot = NodeFS.mkdtempSync( + NodePath.join(NodeOS.tmpdir(), "t3-cli-projects-force-remove-workspace-"), + ); + + yield* runCliWithRuntime(["project", "add", workspaceRoot, "--base-dir", baseDir]); + const afterAdd = yield* readPersistedSnapshot(baseDir); + const project = afterAdd.projects.find( + (candidate) => candidate.workspaceRoot === workspaceRoot && candidate.deletedAt === null, + ); + assert.isTrue(project !== undefined); + + const config = yield* makeCliTestServerConfig(baseDir); + yield* Effect.gen(function* () { + const engine = yield* OrchestrationEngine.OrchestrationEngineService; + yield* engine.dispatch({ + type: "thread.create", + commandId: CommandId.make("cmd-cli-force-remove-thread"), + threadId: ThreadId.make("thread-cli-force-remove"), + projectId: project!.id, + title: "Thread", + modelSelection: { + instanceId: ProviderInstanceId.make("codex"), + model: "gpt-5-codex", + }, + interactionMode: "default", + runtimeMode: "approval-required", + branch: null, + worktreePath: null, + createdAt: DateTime.formatIso(yield* DateTime.now), + }); + }).pipe(Effect.provide(makeProjectPersistenceLayer(config))); + + yield* runCliWithRuntime([ + "project", + "remove", + project!.id, + "--force", + "--base-dir", + baseDir, + ]); + const afterRemove = yield* readPersistedSnapshot(baseDir); + assert.isTrue( + (afterRemove.projects.find((candidate) => candidate.id === project!.id)?.deletedAt ?? + null) !== null, + ); + assert.isTrue( + (afterRemove.threads.find((thread) => thread.id === "thread-cli-force-remove")?.deletedAt ?? + null) !== null, + ); + }), + ); + it.effect("routes project commands through a running server when runtime state is present", () => Effect.gen(function* () { const baseDir = NodeFS.mkdtempSync( diff --git a/apps/server/src/cli/project.ts b/apps/server/src/cli/project.ts index 710d39c4c290..25733a5e35b5 100644 --- a/apps/server/src/cli/project.ts +++ b/apps/server/src/cli/project.ts @@ -493,6 +493,10 @@ const projectRemoveCommand = Command.make("remove", { project: Argument.string("project").pipe( Argument.withDescription("Project id or workspace root to remove."), ), + force: Flag.boolean("force").pipe( + Flag.withDescription("Delete the project and all of its threads."), + Flag.withDefault(false), + ), }).pipe( Command.withDescription("Remove a project."), Command.withHandler((flags) => @@ -515,6 +519,7 @@ const projectRemoveCommand = Command.make("remove", { type: "project.delete", commandId: CommandId.make(yield* projectCommandUuid), projectId: project.id, + force: flags.force, }); return `Removed project ${project.id} (${project.title}).`; }), diff --git a/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.approval.test.ts b/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.approval.test.ts new file mode 100644 index 000000000000..05370781c0d0 --- /dev/null +++ b/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.approval.test.ts @@ -0,0 +1,33 @@ +import { + EventId, + ProviderDriverKind, + RuntimeRequestId, + ThreadId, + type ProviderRuntimeEvent, +} from "@t3tools/contracts"; +import { describe, expect, it } from "vite-plus/test"; + +import { runtimeEventToActivities } from "./ProviderRuntimeIngestion.ts"; + +describe("runtimeEventToActivities approval details", () => { + it("preserves complete multiline command details", () => { + const detail = `bun run release -- ${"long-argument ".repeat(20)}\nsecond line`; + const event = { + type: "request.opened", + eventId: EventId.make("evt-request-opened"), + provider: ProviderDriverKind.make("codex"), + createdAt: "2026-07-18T00:00:00.000Z", + threadId: ThreadId.make("thread-1"), + requestId: RuntimeRequestId.make("approval-1"), + payload: { + requestType: "command_execution_approval", + detail, + }, + } satisfies ProviderRuntimeEvent; + + const [activity] = runtimeEventToActivities(event); + + expect(activity?.kind).toBe("approval.requested"); + expect((activity?.payload as Record | undefined)?.detail).toBe(detail); + }); +}); diff --git a/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts b/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts index 001ba3889496..20611e1ee755 100644 --- a/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts +++ b/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts @@ -448,6 +448,51 @@ describe("ProviderRuntimeIngestion", () => { expect(thread.session?.lastError).toBeNull(); }); + it("clears active turn when provider session becomes ready", async () => { + const harness = await createHarness(); + const now = "2026-01-01T00:00:00.000Z"; + + harness.emit({ + type: "turn.started", + eventId: asEventId("evt-turn-started-session-ready"), + provider: ProviderDriverKind.make("codex"), + createdAt: now, + threadId: asThreadId("thread-1"), + turnId: asTurnId("turn-session-ready"), + }); + + await waitForThread( + harness.readModel, + (thread) => + thread.session?.status === "running" && + thread.session?.activeTurnId === "turn-session-ready", + 10_000, + ); + + harness.emit({ + type: "session.state.changed", + eventId: asEventId("evt-session-state-ready-with-active-turn"), + provider: ProviderDriverKind.make("codex"), + threadId: asThreadId("thread-1"), + createdAt: "2026-01-01T00:00:01.000Z", + payload: { + state: "ready", + }, + }); + + const thread = await waitForThread( + harness.readModel, + (entry) => + entry.session?.status === "ready" && + entry.session?.activeTurnId === null && + entry.session?.lastError === null, + 10_000, + ); + expect(thread.session?.status).toBe("ready"); + expect(thread.session?.activeTurnId).toBeNull(); + expect(thread.session?.lastError).toBeNull(); + }); + it("does not clear active turn when session/thread started arrives mid-turn", async () => { const harness = await createHarness(); const now = "2026-01-01T00:00:00.000Z"; @@ -466,6 +511,7 @@ describe("ProviderRuntimeIngestion", () => { (thread) => thread.session?.status === "running" && thread.session?.activeTurnId === "turn-midturn-lifecycle", + 10_000, ); harness.emit({ @@ -502,6 +548,7 @@ describe("ProviderRuntimeIngestion", () => { await waitForThread( harness.readModel, (thread) => thread.session?.status === "ready" && thread.session?.activeTurnId === null, + 10_000, ); }); @@ -2947,6 +2994,196 @@ describe("ProviderRuntimeIngestion", () => { ).toBe("# Plan title"); }); + it("titles task activities with the task description, including on completion", async () => { + const harness = await createHarness(); + const now = "2026-01-01T00:00:00.000Z"; + + harness.emit({ + type: "task.started", + eventId: asEventId("evt-named-task-started"), + provider: ProviderDriverKind.make("claudeAgent"), + createdAt: now, + threadId: asThreadId("thread-1"), + turnId: asTurnId("turn-named-task"), + payload: { + taskId: "named-task-1", + description: "Typecheck mobile app", + taskType: "local_bash", + }, + }); + + harness.emit({ + type: "task.progress", + eventId: asEventId("evt-named-task-progress"), + provider: ProviderDriverKind.make("claudeAgent"), + createdAt: now, + threadId: asThreadId("thread-1"), + turnId: asTurnId("turn-named-task"), + payload: { + taskId: "named-task-1", + description: "Typecheck mobile app", + summary: "Running tsc across the mobile workspace.", + }, + }); + + harness.emit({ + type: "task.completed", + eventId: asEventId("evt-named-task-completed"), + provider: ProviderDriverKind.make("claudeAgent"), + createdAt: now, + threadId: asThreadId("thread-1"), + turnId: asTurnId("turn-named-task"), + payload: { + taskId: "named-task-1", + status: "completed", + summary: "Typecheck finished without errors.", + }, + }); + + const thread = await waitForThread(harness.readModel, (entry) => + entry.activities.some( + (activity: ProviderRuntimeTestActivity) => activity.id === "evt-named-task-completed", + ), + ); + + const progress = thread.activities.find( + (activity: ProviderRuntimeTestActivity) => activity.id === "evt-named-task-progress", + ); + const completed = thread.activities.find( + (activity: ProviderRuntimeTestActivity) => activity.id === "evt-named-task-completed", + ); + + const progressPayload = + progress?.payload && typeof progress.payload === "object" + ? (progress.payload as Record) + : undefined; + const completedPayload = + completed?.payload && typeof completed.payload === "object" + ? (completed.payload as Record) + : undefined; + + expect(progress?.summary).toBe("Typecheck mobile app"); + expect(progressPayload?.title).toBe("Typecheck mobile app"); + expect(completed?.summary).toBe("Task completed"); + expect(completedPayload?.title).toBe("Typecheck mobile app"); + expect(completedPayload?.summary).toBe("Typecheck finished without errors."); + expect(completedPayload?.detail).toBe("Typecheck finished without errors."); + }); + + it("titles task completion from task.started when no progress event carried the name", async () => { + const harness = await createHarness(); + const now = "2026-01-01T00:00:00.000Z"; + + harness.emit({ + type: "task.started", + eventId: asEventId("evt-fast-task-started"), + provider: ProviderDriverKind.make("claudeAgent"), + createdAt: now, + threadId: asThreadId("thread-1"), + turnId: asTurnId("turn-fast-task"), + payload: { + taskId: "fast-task-1", + description: "wait for codex review to finish", + taskType: "local_bash", + }, + }); + + harness.emit({ + type: "task.completed", + eventId: asEventId("evt-fast-task-completed"), + provider: ProviderDriverKind.make("claudeAgent"), + createdAt: now, + threadId: asThreadId("thread-1"), + turnId: asTurnId("turn-fast-task"), + payload: { + taskId: "fast-task-1", + status: "completed", + }, + }); + + const thread = await waitForThread(harness.readModel, (entry) => + entry.activities.some( + (activity: ProviderRuntimeTestActivity) => activity.id === "evt-fast-task-completed", + ), + ); + + const completed = thread.activities.find( + (activity: ProviderRuntimeTestActivity) => activity.id === "evt-fast-task-completed", + ); + const completedPayload = + completed?.payload && typeof completed.payload === "object" + ? (completed.payload as Record) + : undefined; + + expect(completedPayload?.title).toBe("wait for codex review to finish"); + }); + + it("titles task completion from persisted activities after the description cache is swept", async () => { + const harness = await createHarness(); + const now = "2026-01-01T00:00:00.000Z"; + + harness.emit({ + type: "task.progress", + eventId: asEventId("evt-swept-task-progress"), + provider: ProviderDriverKind.make("claudeAgent"), + createdAt: now, + threadId: asThreadId("thread-1"), + turnId: asTurnId("turn-swept-task"), + payload: { + taskId: "swept-task-1", + description: "Watch round-3 CI and bots", + summary: "Polling CI checks.", + }, + }); + + await waitForThread(harness.readModel, (entry) => + entry.activities.some( + (activity: ProviderRuntimeTestActivity) => activity.id === "evt-swept-task-progress", + ), + ); + + // session.exited sweeps the in-memory description cache; the completion + // that follows must recover the name from persisted activities. + harness.emit({ + type: "session.exited", + eventId: asEventId("evt-swept-task-session-exited"), + provider: ProviderDriverKind.make("claudeAgent"), + createdAt: now, + threadId: asThreadId("thread-1"), + payload: {}, + }); + + harness.emit({ + type: "task.completed", + eventId: asEventId("evt-swept-task-completed"), + provider: ProviderDriverKind.make("claudeAgent"), + createdAt: now, + threadId: asThreadId("thread-1"), + turnId: asTurnId("turn-swept-task"), + payload: { + taskId: "swept-task-1", + status: "completed", + summary: "CI is green.", + }, + }); + + const thread = await waitForThread(harness.readModel, (entry) => + entry.activities.some( + (activity: ProviderRuntimeTestActivity) => activity.id === "evt-swept-task-completed", + ), + ); + + const completed = thread.activities.find( + (activity: ProviderRuntimeTestActivity) => activity.id === "evt-swept-task-completed", + ); + const completedPayload = + completed?.payload && typeof completed.payload === "object" + ? (completed.payload as Record) + : undefined; + + expect(completedPayload?.title).toBe("Watch round-3 CI and bots"); + }); + it("projects structured user input request and resolution as thread activities", async () => { const harness = await createHarness(); const now = "2026-01-01T00:00:00.000Z"; diff --git a/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts b/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts index 3e5978f4846d..09566feb2b21 100644 --- a/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts +++ b/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts @@ -40,6 +40,42 @@ import { import { ServerSettingsService } from "../../serverSettings.ts"; const providerTurnKey = (threadId: ThreadId, turnId: TurnId) => `${threadId}:${turnId}`; +const providerTaskKey = (threadId: ThreadId, taskId: string) => `${threadId}:${taskId}`; + +// Fallback when the in-memory description cache no longer has the task name +// (server restart, session-exit sweep, TTL/capacity eviction): earlier +// task.started/task.progress activities for the task are persisted with it. +function findTaskTitleInActivities( + activities: ReadonlyArray | undefined, + taskId: string, +): string | undefined { + if (!activities) { + return undefined; + } + for (let index = activities.length - 1; index >= 0; index -= 1) { + const activity = activities[index]; + if (!activity || (activity.kind !== "task.started" && activity.kind !== "task.progress")) { + continue; + } + const payload = + activity.payload && typeof activity.payload === "object" + ? (activity.payload as { taskId?: unknown; title?: unknown; detail?: unknown }) + : undefined; + if (payload?.taskId !== taskId) { + continue; + } + const title = + typeof payload.title === "string" + ? payload.title + : activity.kind === "task.started" && typeof payload.detail === "string" + ? payload.detail + : undefined; + if (title && title.trim().length > 0) { + return title; + } + } + return undefined; +} interface AssistantSegmentState { baseKey: string; @@ -53,6 +89,8 @@ const BUFFERED_MESSAGE_TEXT_BY_MESSAGE_ID_CACHE_CAPACITY = 20_000; const BUFFERED_MESSAGE_TEXT_BY_MESSAGE_ID_TTL = Duration.minutes(120); const BUFFERED_PROPOSED_PLAN_BY_ID_CACHE_CAPACITY = 10_000; const BUFFERED_PROPOSED_PLAN_BY_ID_TTL = Duration.minutes(120); +const TASK_DESCRIPTION_BY_TASK_CACHE_CAPACITY = 10_000; +const TASK_DESCRIPTION_BY_TASK_TTL = Duration.minutes(120); const MAX_BUFFERED_ASSISTANT_CHARS = 24_000; const STRICT_PROVIDER_LIFECYCLE_GUARD = process.env.T3CODE_STRICT_PROVIDER_LIFECYCLE_GUARD !== "0"; @@ -245,6 +283,12 @@ function orchestrationSessionStatusFromRuntimeState( } } +function sessionStatusAllowsActiveTurn( + status: ReturnType, +): boolean { + return status === "starting" || status === "running"; +} + function requestKindFromCanonicalRequestType( requestType: string | undefined, ): "command" | "file-read" | "file-change" | undefined { @@ -262,8 +306,9 @@ function requestKindFromCanonicalRequestType( } } -function runtimeEventToActivities( +export function runtimeEventToActivities( event: ProviderRuntimeEvent, + taskTitle?: string, ): ReadonlyArray { const maybeSequence = (() => { const eventWithSequence = event as ProviderRuntimeEvent & { sessionSequence?: number }; @@ -295,7 +340,7 @@ function runtimeEventToActivities( requestId: toApprovalRequestId(event.requestId), ...(requestKind ? { requestKind } : {}), requestType: event.payload.requestType, - ...(event.payload.detail ? { detail: truncateDetail(event.payload.detail) } : {}), + ...(event.payload.detail ? { detail: event.payload.detail } : {}), }, turnId: toTurnId(event.turnId) ?? null, ...maybeSequence, @@ -473,9 +518,15 @@ function runtimeEventToActivities( createdAt: event.createdAt, tone: "info", kind: "task.progress", - summary: "Reasoning update", + summary: + event.payload.description.trim().length > 0 + ? truncateDetail(event.payload.description, 120) + : "Reasoning update", payload: { taskId: event.payload.taskId, + ...(event.payload.description.trim().length > 0 + ? { title: truncateDetail(event.payload.description, 120) } + : {}), detail: truncateDetail(event.payload.summary ?? event.payload.description), ...(event.payload.summary ? { summary: truncateDetail(event.payload.summary) } : {}), ...(event.payload.lastToolName ? { lastToolName: event.payload.lastToolName } : {}), @@ -503,7 +554,15 @@ function runtimeEventToActivities( payload: { taskId: event.payload.taskId, status: event.payload.status, - ...(event.payload.summary ? { detail: truncateDetail(event.payload.summary) } : {}), + ...(taskTitle ? { title: truncateDetail(taskTitle, 120) } : {}), + // summary + detail mirror task.progress: clients label the row from + // summary and keep detail for the preview/expanded body. + ...(event.payload.summary + ? { + summary: truncateDetail(event.payload.summary), + detail: truncateDetail(event.payload.summary), + } + : {}), ...(event.payload.usage !== undefined ? { usage: event.payload.usage } : {}), }, turnId: toTurnId(event.turnId) ?? null, @@ -666,6 +725,27 @@ const make = Effect.gen(function* () { lookup: () => Effect.succeed({ text: "", createdAt: "" }), }); + // Task names arrive on task.started/task.progress but not on task.completed, + // so remember them per task to title the completion activity. + const taskDescriptionByTaskKey = yield* Cache.make({ + capacity: TASK_DESCRIPTION_BY_TASK_CACHE_CAPACITY, + timeToLive: TASK_DESCRIPTION_BY_TASK_TTL, + lookup: () => Effect.succeed(""), + }); + + const rememberTaskDescription = (threadId: ThreadId, taskId: string, description: string) => + Cache.set(taskDescriptionByTaskKey, providerTaskKey(threadId, taskId), description); + + // Entries are left in place after completion so replayed or duplicate + // terminal events stay titled; TTL, capacity, and the session-exit sweep + // bound the cache. + const lookupTaskDescription = (threadId: ThreadId, taskId: string) => + Cache.getOption(taskDescriptionByTaskKey, providerTaskKey(threadId, taskId)).pipe( + Effect.map((description) => + Option.filter(description, (value) => value.length > 0).pipe(Option.getOrUndefined), + ), + ); + const resolveThreadDetail = Effect.fn("resolveThreadDetail")(function* (threadId: ThreadId) { return yield* projectionSnapshotQuery .getThreadDetailById(threadId) @@ -1090,6 +1170,7 @@ const make = Effect.gen(function* () { const turnKeys = Array.from(yield* Cache.keys(turnMessageIdsByTurnKey)); const assistantSegmentKeys = Array.from(yield* Cache.keys(assistantSegmentStateByTurnKey)); const proposedPlanKeys = Array.from(yield* Cache.keys(bufferedProposedPlanById)); + const taskDescriptionKeys = Array.from(yield* Cache.keys(taskDescriptionByTaskKey)); yield* Effect.forEach( turnKeys, (key) => @@ -1125,6 +1206,12 @@ const make = Effect.gen(function* () { : Effect.void, { concurrency: 1 }, ).pipe(Effect.asVoid); + yield* Effect.forEach( + taskDescriptionKeys, + (key) => + key.startsWith(prefix) ? Cache.invalidate(taskDescriptionByTaskKey, key) : Effect.void, + { concurrency: 1 }, + ).pipe(Effect.asVoid); }); const getSourceProposedPlanReferenceForPendingTurnStart = Effect.fn( @@ -1281,12 +1368,6 @@ const make = Effect.gen(function* () { event.type === "turn.started" || event.type === "turn.completed" ) { - const nextActiveTurnId = - event.type === "turn.started" - ? (eventTurnId ?? null) - : event.type === "turn.completed" || event.type === "session.exited" - ? null - : activeTurnId; const status = (() => { switch (event.type) { case "session.state.changed": @@ -1306,6 +1387,14 @@ const make = Effect.gen(function* () { return activeTurnId !== null ? "running" : "ready"; } })(); + const nextActiveTurnId = + event.type === "turn.started" + ? (eventTurnId ?? null) + : event.type === "turn.completed" || event.type === "session.exited" + ? null + : event.type === "session.state.changed" && !sessionStatusAllowsActiveTurn(status) + ? null + : activeTurnId; const lastError = event.type === "session.state.changed" && event.payload.state === "error" ? (event.payload.reason ?? thread.session?.lastError ?? "Provider session error") @@ -1654,7 +1743,22 @@ const make = Effect.gen(function* () { } } - const activities = runtimeEventToActivities(event); + if (event.type === "task.started" || event.type === "task.progress") { + const description = event.payload.description?.trim(); + if (description) { + yield* rememberTaskDescription(thread.id, event.payload.taskId, description); + } + } + let taskTitle: string | undefined; + if (event.type === "task.completed") { + taskTitle = yield* lookupTaskDescription(thread.id, event.payload.taskId); + if (!taskTitle) { + const threadDetail = yield* getLoadedThreadDetail(); + taskTitle = findTaskTitleInActivities(threadDetail?.activities, event.payload.taskId); + } + } + + const activities = runtimeEventToActivities(event, taskTitle); yield* Effect.forEach(activities, (activity) => providerCommandId(event, "thread-activity-append").pipe( Effect.flatMap((commandId) => diff --git a/apps/server/src/provider/Drivers/ClaudeExecutable.test.ts b/apps/server/src/provider/Drivers/ClaudeExecutable.test.ts new file mode 100644 index 000000000000..020fc48a4656 --- /dev/null +++ b/apps/server/src/provider/Drivers/ClaudeExecutable.test.ts @@ -0,0 +1,124 @@ +import { describe, expect, it } from "@effect/vitest"; +import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import { SpawnExecutableResolution } from "@t3tools/shared/shell"; +import * as Effect from "effect/Effect"; + +import { ClaudeExecutableFileCheck, resolveClaudeSdkExecutablePath } from "./ClaudeExecutable.ts"; + +const NPM_DIR = "C:\\Users\\dev\\AppData\\Roaming\\npm"; +const NPM_SHIM = `${NPM_DIR}\\claude.cmd`; +const NPM_PACKAGE_EXE = `${NPM_DIR}\\node_modules\\@anthropic-ai\\claude-code\\bin\\claude.exe`; +const NPM_PACKAGE_CLI = `${NPM_DIR}\\node_modules\\@anthropic-ai\\claude-code\\cli.js`; + +function withWindowsResolution(input: { + readonly resolvedCommand: string | undefined; + readonly existingFiles?: ReadonlyArray; +}) { + const existing = new Set(input.existingFiles ?? []); + return (effect: Effect.Effect) => + effect.pipe( + Effect.provideService(HostProcessPlatform, "win32"), + Effect.provideService(SpawnExecutableResolution, () => input.resolvedCommand), + Effect.provideService(ClaudeExecutableFileCheck, (filePath) => existing.has(filePath)), + ); +} + +describe("resolveClaudeSdkExecutablePath", () => { + it.effect("returns the configured path unchanged on non-Windows platforms", () => + Effect.gen(function* () { + expect( + yield* resolveClaudeSdkExecutablePath("claude", {}).pipe( + Effect.provideService(HostProcessPlatform, "darwin"), + Effect.provideService(SpawnExecutableResolution, () => { + throw new Error("must not resolve on non-Windows platforms"); + }), + ), + ).toBe("claude"); + }), + ); + + it.effect("returns the resolved absolute path for native Windows executables", () => + Effect.gen(function* () { + const nativeBinary = "C:\\Users\\dev\\.local\\bin\\claude.exe"; + expect( + yield* resolveClaudeSdkExecutablePath("claude", {}).pipe( + withWindowsResolution({ resolvedCommand: nativeBinary }), + ), + ).toBe(nativeBinary); + }), + ); + + it.effect("follows an npm launcher shim to the packaged native binary", () => + Effect.gen(function* () { + expect( + yield* resolveClaudeSdkExecutablePath("claude", {}).pipe( + withWindowsResolution({ + resolvedCommand: NPM_SHIM, + existingFiles: [NPM_PACKAGE_EXE, NPM_PACKAGE_CLI], + }), + ), + ).toBe(NPM_PACKAGE_EXE); + }), + ); + + it.effect("follows .bat and .ps1 launcher shims the same way", () => + Effect.gen(function* () { + for (const shim of [`${NPM_DIR}\\claude.bat`, `${NPM_DIR}\\claude.ps1`]) { + expect( + yield* resolveClaudeSdkExecutablePath("claude", {}).pipe( + withWindowsResolution({ + resolvedCommand: shim, + existingFiles: [NPM_PACKAGE_EXE], + }), + ), + ).toBe(NPM_PACKAGE_EXE); + } + }), + ); + + it.effect("normalizes mixed-case shim extensions before matching", () => + Effect.gen(function* () { + expect( + yield* resolveClaudeSdkExecutablePath("claude", {}).pipe( + withWindowsResolution({ + resolvedCommand: `${NPM_DIR}\\claude.CMD`, + existingFiles: [NPM_PACKAGE_EXE], + }), + ), + ).toBe(NPM_PACKAGE_EXE); + }), + ); + + it.effect("falls back to cli.js when the package ships no native binary", () => + Effect.gen(function* () { + expect( + yield* resolveClaudeSdkExecutablePath("claude", {}).pipe( + withWindowsResolution({ + resolvedCommand: NPM_SHIM, + existingFiles: [NPM_PACKAGE_CLI], + }), + ), + ).toBe(NPM_PACKAGE_CLI); + }), + ); + + it.effect("returns the configured path when a shim has no known package entry", () => + Effect.gen(function* () { + expect( + yield* resolveClaudeSdkExecutablePath("claude", {}).pipe( + withWindowsResolution({ resolvedCommand: NPM_SHIM }), + ), + ).toBe("claude"); + }), + ); + + it.effect("returns the configured path when command resolution finds nothing", () => + Effect.gen(function* () { + expect( + yield* resolveClaudeSdkExecutablePath("claude", {}).pipe( + withWindowsResolution({ resolvedCommand: undefined }), + ), + ).toBe("claude"); + }), + ); +}); diff --git a/apps/server/src/provider/Drivers/ClaudeExecutable.ts b/apps/server/src/provider/Drivers/ClaudeExecutable.ts new file mode 100644 index 000000000000..febfdb26f9e3 --- /dev/null +++ b/apps/server/src/provider/Drivers/ClaudeExecutable.ts @@ -0,0 +1,90 @@ +// @effect-diagnostics nodeBuiltinImport:off +import * as NodeFS from "node:fs"; +import * as NodePath from "node:path"; + +import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; +import { SpawnExecutableResolution } from "@t3tools/shared/shell"; +import * as Context from "effect/Context"; +import * as Effect from "effect/Effect"; + +/** + * Windows launcher-script extensions that Node cannot spawn without a shell + * (`spawn EINVAL` since Node 20.12) and that the Claude Agent SDK therefore + * cannot use as `pathToClaudeCodeExecutable`. + */ +const WINDOWS_SHIM_EXTENSIONS: ReadonlySet = new Set([".cmd", ".bat", ".ps1"]); + +/** + * Entry points of the npm `@anthropic-ai/claude-code` package relative to the + * global `node_modules` directory that sits next to the npm launcher shim. + * Newer package versions ship a native `bin/claude.exe`; older versions only + * ship `cli.js`, which the SDK runs with a JavaScript runtime. + */ +const NPM_PACKAGE_ENTRY_CANDIDATES = [ + ["node_modules", "@anthropic-ai", "claude-code", "bin", "claude.exe"], + ["node_modules", "@anthropic-ai", "claude-code", "cli.js"], +] as const; + +export type ExecutableFileCheck = (filePath: string) => boolean; + +function isExistingFile(filePath: string): boolean { + try { + return NodeFS.statSync(filePath).isFile(); + } catch { + return false; + } +} + +/** Injectable file-existence check so tests can run against a fake filesystem. */ +export const ClaudeExecutableFileCheck = Context.Reference( + "server/provider/Drivers/ClaudeExecutableFileCheck", + { + defaultValue: () => isExistingFile, + }, +); + +/** + * Resolves the configured Claude binary path into a value the Claude Agent + * SDK can spawn directly via `pathToClaudeCodeExecutable`. + * + * The SDK spawns the given path without a shell and without Windows PATH / + * PATHEXT resolution, so a bare command name like `claude` fails with + * "native binary not found" and an npm `claude.cmd` shim fails with + * `spawn EINVAL`. CLI probes avoid this via `resolveSpawnCommand`, which can + * fall back to `shell: true`; the SDK offers no such escape hatch. + * + * On Windows this resolves the command against PATH/PATHEXT and, when the + * result is an npm launcher shim, follows it to the real package entry + * (`bin/claude.exe`, or `cli.js` for older package versions). On other + * platforms the configured value is returned unchanged. + */ +export const resolveClaudeSdkExecutablePath = Effect.fn("resolveClaudeSdkExecutablePath")( + function* (binaryPath: string, environment: NodeJS.ProcessEnv): Effect.fn.Return { + const platform = yield* HostProcessPlatform; + if (platform !== "win32") { + return binaryPath; + } + + const resolveExecutable = yield* SpawnExecutableResolution; + const isFile = yield* ClaudeExecutableFileCheck; + const resolved = resolveExecutable(binaryPath, platform, environment) ?? binaryPath; + const extension = NodePath.win32.extname(resolved).toLowerCase(); + if (!WINDOWS_SHIM_EXTENSIONS.has(extension)) { + return resolved; + } + + const shimDirectory = NodePath.win32.dirname(resolved); + for (const entrySegments of NPM_PACKAGE_ENTRY_CANDIDATES) { + const candidate = NodePath.win32.join(shimDirectory, ...entrySegments); + if (isFile(candidate)) { + return candidate; + } + } + + yield* Effect.logWarning( + "Claude launcher shim resolved but no known package entry was found next to it; the Claude Agent SDK cannot spawn launcher scripts directly.", + { binaryPath, resolvedShimPath: resolved }, + ); + return binaryPath; + }, +); diff --git a/apps/server/src/provider/Layers/AmpProvider.ts b/apps/server/src/provider/Layers/AmpProvider.ts index 31a44976e4aa..7af3d6d5141c 100644 --- a/apps/server/src/provider/Layers/AmpProvider.ts +++ b/apps/server/src/provider/Layers/AmpProvider.ts @@ -98,7 +98,6 @@ export const checkAmpStatus = Effect.fn("checkAmpStatus")(function* ( const checkedAt = new Date().toISOString(); const allModels = providerModelsFromSettings( BUILT_IN_MODELS, - PROVIDER, ampSettings.customModels, DEFAULT_AMP_MODEL_CAPABILITIES, ); @@ -200,7 +199,6 @@ export const makePendingAmpProvider = ( const checkedAt = new Date().toISOString(); const models = providerModelsFromSettings( BUILT_IN_MODELS, - PROVIDER, ampSettings.customModels, DEFAULT_AMP_MODEL_CAPABILITIES, ); diff --git a/apps/server/src/provider/Layers/ClaudeAdapter.ts b/apps/server/src/provider/Layers/ClaudeAdapter.ts index 907254a41da3..4c5213ae43d3 100644 --- a/apps/server/src/provider/Layers/ClaudeAdapter.ts +++ b/apps/server/src/provider/Layers/ClaudeAdapter.ts @@ -70,6 +70,7 @@ import * as Stream from "effect/Stream"; import { resolveAttachmentPath } from "../../attachmentStore.ts"; import { ServerConfig } from "../../config.ts"; import * as McpProviderSession from "../../mcp/McpProviderSession.ts"; +import { resolveClaudeSdkExecutablePath } from "../Drivers/ClaudeExecutable.ts"; import { makeClaudeEnvironment } from "../Drivers/ClaudeHome.ts"; import { getClaudeModelCapabilities, @@ -1357,6 +1358,10 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( const claudeEnvironment = yield* makeClaudeEnvironment(claudeSettings, options?.environment).pipe( Effect.provideService(Path.Path, path), ); + const claudeSdkExecutablePath = yield* resolveClaudeSdkExecutablePath( + claudeSettings.binaryPath, + claudeEnvironment, + ); const nativeEventLogger = options?.nativeEventLogger ?? (options?.nativeEventLogPath !== undefined @@ -3415,7 +3420,7 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( const canUseTool: CanUseTool = (toolName, toolInput, callbackOptions) => runPromise(canUseToolEffect(toolName, toolInput, callbackOptions)); - const claudeBinaryPath = claudeSettings.binaryPath; + const claudeBinaryPath = claudeSdkExecutablePath; const extraArgs = parseCliArgs(claudeSettings.launchArgs).flags; const modelSelection = input.modelSelection?.instanceId === boundInstanceId ? input.modelSelection : undefined; diff --git a/apps/server/src/provider/Layers/ClaudeProvider.ts b/apps/server/src/provider/Layers/ClaudeProvider.ts index 2e35731c7671..25c5088c7b3c 100644 --- a/apps/server/src/provider/Layers/ClaudeProvider.ts +++ b/apps/server/src/provider/Layers/ClaudeProvider.ts @@ -2,7 +2,6 @@ import { type ClaudeSettings, type ModelCapabilities, type ModelSelection, - ProviderDriverKind, type ServerProviderModel, type ServerProviderSlashCommand, } from "@t3tools/contracts"; @@ -37,13 +36,13 @@ import { spawnAndCollect, type ServerProviderDraft, } from "../providerSnapshot.ts"; +import { resolveClaudeSdkExecutablePath } from "../Drivers/ClaudeExecutable.ts"; import { makeClaudeEnvironment } from "../Drivers/ClaudeHome.ts"; const DEFAULT_CLAUDE_MODEL_CAPABILITIES: ModelCapabilities = createModelCapabilities({ optionDescriptors: [], }); -const PROVIDER = ProviderDriverKind.make("claudeAgent"); const CLAUDE_PRESENTATION = { displayName: "Claude", showInteractionModeToggle: true, @@ -540,9 +539,19 @@ function claudeAuthMetadata(input: { return undefined; } +function apiProviderAuthMetadata( + apiProvider: string | undefined, +): { readonly type: string; readonly label: string } | undefined { + return apiProvider === "bedrock" ? { type: "bedrock", label: "Amazon Bedrock" } : undefined; +} + // ── SDK capability probe ──────────────────────────────────────────── -const CAPABILITIES_PROBE_TIMEOUT_MS = 8_000; +// Amazon Bedrock initializes far slower than first-party auth: the SDK boots the +// Bedrock backend and runs the `awsAuthRefresh` credential hook before returning +// account info. The previous 8s budget expired mid-init, so the probe returned +// `undefined` and left the provider unverified and unselectable in the picker. +const CAPABILITIES_PROBE_TIMEOUT_MS = 25_000; function nonEmptyProbeString(value: string): string | undefined { const candidate = value.trim(); @@ -553,6 +562,12 @@ type ClaudeCapabilitiesProbe = { readonly email: string | undefined; readonly subscriptionType: string | undefined; readonly tokenSource: string | undefined; + /** + * Active API backend reported by the SDK's `AccountInfo`. Anthropic OAuth + * login only applies when `"firstParty"`; for Amazon Bedrock (`"bedrock"`) + * the subscription/token fields are absent and auth is external AWS creds. + */ + readonly apiProvider: string | undefined; readonly slashCommands: ReadonlyArray; }; @@ -649,6 +664,10 @@ const probeClaudeCapabilities = ( const abort = new AbortController(); return Effect.gen(function* () { const claudeEnvironment = yield* makeClaudeEnvironment(claudeSettings, environment); + const executablePath = yield* resolveClaudeSdkExecutablePath( + claudeSettings.binaryPath, + claudeEnvironment, + ); return yield* Effect.tryPromise(async () => { const q = claudeQuery({ // Never yield — we only need initialization data, not a conversation. @@ -659,7 +678,7 @@ const probeClaudeCapabilities = ( })(), options: { persistSession: false, - pathToClaudeCodeExecutable: claudeSettings.binaryPath, + pathToClaudeCodeExecutable: executablePath, abortController: abort, settingSources: ["user", "project", "local"], allowedTools: [], @@ -674,12 +693,14 @@ const probeClaudeCapabilities = ( readonly email?: string; readonly subscriptionType?: string; readonly tokenSource?: string; + readonly apiProvider?: string; } | undefined; return { email: account?.email, subscriptionType: account?.subscriptionType, tokenSource: account?.tokenSource, + apiProvider: account?.apiProvider, slashCommands: parseClaudeInitializationCommands(init.commands), } satisfies ClaudeCapabilitiesProbe; }); @@ -729,7 +750,6 @@ export const checkClaudeProviderStatus = Effect.fn("checkClaudeProviderStatus")( const checkedAt = DateTime.formatIso(yield* DateTime.now); const allModels = providerModelsFromSettings( withClaudeSonnet5ContextWindowSelector(BUILT_IN_MODELS, resolvedEnvironment), - PROVIDER, claudeSettings.customModels, DEFAULT_CLAUDE_MODEL_CAPABILITIES, ); @@ -823,7 +843,6 @@ export const checkClaudeProviderStatus = Effect.fn("checkClaudeProviderStatus")( getBuiltInClaudeModelsForVersion(parsedVersion), resolvedEnvironment, ), - PROVIDER, claudeSettings.customModels, DEFAULT_CLAUDE_MODEL_CAPABILITIES, ); @@ -860,10 +879,11 @@ export const checkClaudeProviderStatus = Effect.fn("checkClaudeProviderStatus")( }); } - const authMetadata = claudeAuthMetadata({ - subscriptionType: capabilities.subscriptionType, - authMethod: capabilities.tokenSource, - }); + const authMetadata = + claudeAuthMetadata({ + subscriptionType: capabilities.subscriptionType, + authMethod: capabilities.tokenSource, + }) ?? apiProviderAuthMetadata(capabilities.apiProvider); return buildServerProvider({ presentation: CLAUDE_PRESENTATION, enabled: claudeSettings.enabled, @@ -894,7 +914,6 @@ export const makePendingClaudeProvider = ( const checkedAt = yield* nowIso; const models = providerModelsFromSettings( withClaudeSonnet5ContextWindowSelector(BUILT_IN_MODELS, environment), - PROVIDER, claudeSettings.customModels, DEFAULT_CLAUDE_MODEL_CAPABILITIES, ); diff --git a/apps/server/src/provider/Layers/CodexAdapter.test.ts b/apps/server/src/provider/Layers/CodexAdapter.test.ts index 57197bb83a74..68fb16b0401c 100644 --- a/apps/server/src/provider/Layers/CodexAdapter.test.ts +++ b/apps/server/src/provider/Layers/CodexAdapter.test.ts @@ -279,6 +279,7 @@ validationLayer("CodexAdapterLive validation", (it) => { NodeAssert.deepStrictEqual(validationRuntimeFactory.factory.mock.calls[0]?.[0], { binaryPath: "codex", cwd: process.cwd(), + launchArgs: "", model: "gpt-5.3-codex", providerInstanceId: ProviderInstanceId.make("codex"), serviceTier: "priority", @@ -359,6 +360,69 @@ sessionErrorLayer("CodexAdapterLive session errors", (it) => { }), ); + it.effect("passes configured launch args into the session runtime", () => { + const runtimeFactory = makeRuntimeFactory(); + const layer = Layer.effect( + CodexAdapter, + Effect.gen(function* () { + const codexConfig = decodeCodexSettings({ launchArgs: "--strict-config --enable foo" }); + return yield* makeCodexAdapter(codexConfig, { + makeRuntime: runtimeFactory.factory, + }); + }), + ).pipe( + Layer.provideMerge(ServerConfig.layerTest(process.cwd(), process.cwd())), + Layer.provideMerge(ServerSettingsService.layerTest()), + Layer.provideMerge(providerSessionDirectoryTestLayer), + Layer.provideMerge(NodeServices.layer), + ); + + return Effect.gen(function* () { + const adapter = yield* CodexAdapter; + yield* adapter.startSession({ + provider: ProviderDriverKind.make("codex"), + threadId: asThreadId("sess-launch-args"), + runtimeMode: "full-access", + }); + + const runtime = runtimeFactory.lastRuntime; + NodeAssert.ok(runtime); + NodeAssert.equal(runtime.options.launchArgs, "--strict-config --enable foo"); + }).pipe(Effect.provide(layer)); + }); + + it.effect("uses T3CODE_CODEX_LAUNCH_ARGS for the session runtime", () => { + const runtimeFactory = makeRuntimeFactory(); + const layer = Layer.effect( + CodexAdapter, + Effect.gen(function* () { + const codexConfig = decodeCodexSettings({ launchArgs: "--enable settings-feature" }); + return yield* makeCodexAdapter(codexConfig, { + environment: { T3CODE_CODEX_LAUNCH_ARGS: " --strict-config --enable env-feature " }, + makeRuntime: runtimeFactory.factory, + }); + }), + ).pipe( + Layer.provideMerge(ServerConfig.layerTest(process.cwd(), process.cwd())), + Layer.provideMerge(ServerSettingsService.layerTest()), + Layer.provideMerge(providerSessionDirectoryTestLayer), + Layer.provideMerge(NodeServices.layer), + ); + + return Effect.gen(function* () { + const adapter = yield* CodexAdapter; + yield* adapter.startSession({ + provider: ProviderDriverKind.make("codex"), + threadId: asThreadId("sess-launch-args-env"), + runtimeMode: "full-access", + }); + + const runtime = runtimeFactory.lastRuntime; + NodeAssert.ok(runtime); + NodeAssert.equal(runtime.options.launchArgs, "--strict-config --enable env-feature"); + }).pipe(Effect.provide(layer)); + }); + it.effect("maps codex model options for the adapter's bound custom instance id", () => { const customInstanceId = ProviderInstanceId.make("codex_personal"); const customRuntimeFactory = makeRuntimeFactory(); diff --git a/apps/server/src/provider/Layers/CodexAdapter.ts b/apps/server/src/provider/Layers/CodexAdapter.ts index 270126e934ba..38a5887cdc3e 100644 --- a/apps/server/src/provider/Layers/CodexAdapter.ts +++ b/apps/server/src/provider/Layers/CodexAdapter.ts @@ -61,6 +61,7 @@ import { type CodexSessionRuntimeShape, } from "./CodexSessionRuntime.ts"; import { type EventNdjsonLogger, makeEventNdjsonLogger } from "./EventNdjsonLogger.ts"; +import { resolveCodexLaunchArgs } from "./codexLaunchArgs.ts"; const isCodexAppServerProcessExitedError = Schema.is(CodexErrors.CodexAppServerProcessExitedError); const isCodexAppServerTransportError = Schema.is(CodexErrors.CodexAppServerTransportError); const isCodexSessionRuntimeThreadIdMissingError = Schema.is( @@ -267,8 +268,14 @@ function itemTitle(itemType: CanonicalItemType, item?: CodexLifecycleItem): stri } } -function itemDetail(item: CodexLifecycleItem): string | undefined { +function itemDetail(itemType: CanonicalItemType, item: CodexLifecycleItem): string | undefined { + const itemRecord = item as Record; + const action = itemRecord.action as Record | undefined; + const actionQueries = Array.isArray(action?.queries) ? action.queries : []; const candidates = [ + ...(itemType === "web_search" + ? [itemRecord.query, action?.query, ...actionQueries, action?.pattern, action?.url] + : []), "command" in item ? item.command : undefined, "title" in item ? item.title : undefined, "summary" in item ? item.summary : undefined, @@ -276,6 +283,7 @@ function itemDetail(item: CodexLifecycleItem): string | undefined { "path" in item ? item.path : undefined, "prompt" in item ? item.prompt : undefined, ]; + for (const candidate of candidates) { const trimmed = typeof candidate === "string" ? trimText(candidate) : undefined; if (!trimmed) continue; @@ -465,7 +473,7 @@ function mapItemLifecycle( return undefined; } - const detail = itemDetail(item); + const detail = itemDetail(itemType, item); const status = lifecycle === "item.started" ? "inProgress" @@ -839,7 +847,7 @@ function mapToRuntimeEvents( } const itemType = toCanonicalItemType(item.type); if (itemType === "plan") { - const detail = itemDetail(item); + const detail = itemDetail(itemType, item); if (!detail) { return []; } @@ -1392,6 +1400,7 @@ export const makeCodexAdapter = Effect.fn("makeCodexAdapter")(function* ( providerInstanceId: boundInstanceId, cwd: input.cwd ?? process.cwd(), binaryPath: codexConfig.binaryPath, + launchArgs: resolveCodexLaunchArgs(codexConfig.launchArgs, options?.environment), ...(options?.environment ? { environment: options.environment } : {}), ...(codexConfig.homePath ? { homePath: codexConfig.homePath } : {}), ...(isCodexResumeCursorSchema(input.resumeCursor) diff --git a/apps/server/src/provider/Layers/CodexProvider.ts b/apps/server/src/provider/Layers/CodexProvider.ts index a2182cfb73c5..9306087a0bc2 100644 --- a/apps/server/src/provider/Layers/CodexProvider.ts +++ b/apps/server/src/provider/Layers/CodexProvider.ts @@ -26,6 +26,7 @@ import { ServerSettingsError } from "@t3tools/contracts"; import { createModelCapabilities } from "@t3tools/shared/model"; import { resolveSpawnCommand } from "@t3tools/shared/shell"; +import { codexAppServerArgs, resolveCodexLaunchArgs } from "./codexLaunchArgs.ts"; import { AUTH_PROBE_TIMEOUT_MS, buildServerProvider, @@ -289,6 +290,7 @@ export function buildCodexInitializeParams(): CodexSchema.V1InitializeParams { const probeCodexAppServerProvider = Effect.fn("probeCodexAppServerProvider")(function* (input: { readonly binaryPath: string; readonly homePath?: string; + readonly launchArgs?: string; readonly cwd: string; readonly customModels?: ReadonlyArray; readonly environment?: NodeJS.ProcessEnv; @@ -303,10 +305,14 @@ const probeCodexAppServerProvider = Effect.fn("probeCodexAppServerProvider")(fun ...input.environment, ...(resolvedHomePath ? { CODEX_HOME: resolvedHomePath } : {}), }; - const spawnCommand = yield* resolveSpawnCommand(input.binaryPath, ["app-server"], { - env: environment, - extendEnv: true, - }); + const spawnCommand = yield* resolveSpawnCommand( + input.binaryPath, + codexAppServerArgs(input.launchArgs), + { + env: environment, + extendEnv: true, + }, + ); const child = yield* spawner .spawn( ChildProcess.make(spawnCommand.command, spawnCommand.args, { @@ -465,6 +471,7 @@ export const checkCodexProviderStatus = Effect.fn("checkCodexProviderStatus")(fu probe: (input: { readonly binaryPath: string; readonly homePath?: string; + readonly launchArgs?: string; readonly cwd: string; readonly customModels: ReadonlyArray; readonly environment?: NodeJS.ProcessEnv; @@ -503,6 +510,7 @@ export const checkCodexProviderStatus = Effect.fn("checkCodexProviderStatus")(fu const probeResult = yield* probe({ binaryPath: codexSettings.binaryPath, homePath: codexSettings.homePath, + launchArgs: resolveCodexLaunchArgs(codexSettings.launchArgs, resolvedEnvironment), cwd: process.cwd(), customModels: codexSettings.customModels, environment: resolvedEnvironment, diff --git a/apps/server/src/provider/Layers/CodexSessionRuntime.test.ts b/apps/server/src/provider/Layers/CodexSessionRuntime.test.ts index 1527072dae7a..119fa36303a5 100644 --- a/apps/server/src/provider/Layers/CodexSessionRuntime.test.ts +++ b/apps/server/src/provider/Layers/CodexSessionRuntime.test.ts @@ -13,6 +13,7 @@ import { CODEX_DEFAULT_MODE_DEVELOPER_INSTRUCTIONS, CODEX_PLAN_MODE_DEVELOPER_INSTRUCTIONS, } from "../CodexDeveloperInstructions.ts"; +import { codexSessionAppServerArgs } from "./codexLaunchArgs.ts"; import { buildTurnStartParams, hasConfiguredMcpServer, @@ -289,6 +290,33 @@ describe("hasConfiguredMcpServer", () => { }); }); +describe("codexSessionAppServerArgs", () => { + it("keeps the app-server subcommand when explicit args are provided", () => { + NodeAssert.deepStrictEqual(codexSessionAppServerArgs(["-c", "model=gpt-5"], undefined), [ + "app-server", + "-c", + "model=gpt-5", + ]); + }); + + it("keeps launch args when explicit app-server args are provided", () => { + NodeAssert.deepStrictEqual( + codexSessionAppServerArgs( + ["-c", "mcp_servers.t3-code.url=http://127.0.0.1/mcp"], + "--strict-config --enable foo", + ), + [ + "app-server", + "--strict-config", + "--enable", + "foo", + "-c", + "mcp_servers.t3-code.url=http://127.0.0.1/mcp", + ], + ); + }); +}); + describe("isRecoverableThreadResumeError", () => { it("matches missing thread errors", () => { NodeAssert.equal( diff --git a/apps/server/src/provider/Layers/CodexSessionRuntime.ts b/apps/server/src/provider/Layers/CodexSessionRuntime.ts index 4a320fa78a27..cdbfc53eb0da 100644 --- a/apps/server/src/provider/Layers/CodexSessionRuntime.ts +++ b/apps/server/src/provider/Layers/CodexSessionRuntime.ts @@ -36,6 +36,7 @@ import * as CodexRpc from "effect-codex-app-server/rpc"; import * as EffectCodexSchema from "effect-codex-app-server/schema"; import { buildCodexInitializeParams } from "./CodexProvider.ts"; +import { codexSessionAppServerArgs } from "./codexLaunchArgs.ts"; import { expandHomePath } from "../../pathExpansion.ts"; import { buildCodexDeveloperInstructions } from "../CodexDeveloperInstructions.ts"; const decodeV2TurnStartResponse = Schema.decodeUnknownEffect(EffectCodexSchema.V2TurnStartResponse); @@ -97,6 +98,7 @@ export interface CodexSessionRuntimeOptions { readonly providerInstanceId?: ProviderInstanceId; readonly binaryPath: string; readonly homePath?: string; + readonly launchArgs?: string; readonly environment?: NodeJS.ProcessEnv; readonly cwd: string; readonly runtimeMode: RuntimeMode; @@ -719,11 +721,11 @@ export const makeCodexSessionRuntime = ( ...(resolvedHomePath ? { CODEX_HOME: resolvedHomePath } : {}), }; const extendEnv = options.environment === undefined; - const spawnCommand = yield* resolveSpawnCommand( - options.binaryPath, - ["app-server", ...(options.appServerArgs ?? [])], - { env, extendEnv }, - ); + const appServerArgs = codexSessionAppServerArgs(options.appServerArgs, options.launchArgs); + const spawnCommand = yield* resolveSpawnCommand(options.binaryPath, appServerArgs, { + env, + extendEnv, + }); const child = yield* spawner .spawn( ChildProcess.make(spawnCommand.command, spawnCommand.args, { diff --git a/apps/server/src/provider/Layers/CopilotProvider.ts b/apps/server/src/provider/Layers/CopilotProvider.ts index b62a5fd32a39..1c9bb8fe6cb9 100644 --- a/apps/server/src/provider/Layers/CopilotProvider.ts +++ b/apps/server/src/provider/Layers/CopilotProvider.ts @@ -161,7 +161,6 @@ export const makePendingCopilotProvider = (settings: CopilotSettings): ServerPro const checkedAt = new Date().toISOString(); const models = providerModelsFromSettings( [], - PROVIDER, settings.customModels, DEFAULT_COPILOT_MODEL_CAPABILITIES, ); @@ -204,7 +203,6 @@ export const checkCopilotProviderStatus = Effect.fn("checkCopilotProviderStatus" const checkedAt = new Date().toISOString(); const models = providerModelsFromSettings( [], - PROVIDER, settings.customModels, DEFAULT_COPILOT_MODEL_CAPABILITIES, ); diff --git a/apps/server/src/provider/Layers/CursorProvider.ts b/apps/server/src/provider/Layers/CursorProvider.ts index 99039f08c6ec..2aec076b34b2 100644 --- a/apps/server/src/provider/Layers/CursorProvider.ts +++ b/apps/server/src/provider/Layers/CursorProvider.ts @@ -80,7 +80,6 @@ export function getCursorFallbackModels( ): ReadonlyArray { return providerModelsFromSettings( CURSOR_FALLBACK_MODELS, - PROVIDER, cursorSettings.customModels, EMPTY_CURSOR_CAPABILITIES, ); diff --git a/apps/server/src/provider/Layers/DroidProvider.ts b/apps/server/src/provider/Layers/DroidProvider.ts index e4cc5515eb48..8f48dd730030 100644 --- a/apps/server/src/provider/Layers/DroidProvider.ts +++ b/apps/server/src/provider/Layers/DroidProvider.ts @@ -235,7 +235,6 @@ const modelsWithSettingsFallback = ( ): ReadonlyArray => providerModelsFromSettings( sdkModels.length > 0 ? sdkModels : FALLBACK_MODELS, - PROVIDER, settings.customModels, DROID_FALLBACK_MODEL_CAPABILITIES, ); diff --git a/apps/server/src/provider/Layers/GeminiCliProvider.ts b/apps/server/src/provider/Layers/GeminiCliProvider.ts index e5bc24904969..202fc1b4df69 100644 --- a/apps/server/src/provider/Layers/GeminiCliProvider.ts +++ b/apps/server/src/provider/Layers/GeminiCliProvider.ts @@ -109,7 +109,6 @@ export const checkGeminiCliStatus = Effect.fn("checkGeminiCliStatus")(function* const checkedAt = new Date().toISOString(); const allModels = providerModelsFromSettings( BUILT_IN_MODELS, - PROVIDER, config.customModels, DEFAULT_GEMINI_MODEL_CAPABILITIES, ); @@ -215,7 +214,6 @@ export const makePendingGeminiCliProvider = ( const checkedAt = new Date().toISOString(); const models = providerModelsFromSettings( BUILT_IN_MODELS, - PROVIDER, config.customModels, DEFAULT_GEMINI_MODEL_CAPABILITIES, ); diff --git a/apps/server/src/provider/Layers/GrokProvider.ts b/apps/server/src/provider/Layers/GrokProvider.ts index 33f61ad97f6d..934eecdb5ae6 100644 --- a/apps/server/src/provider/Layers/GrokProvider.ts +++ b/apps/server/src/provider/Layers/GrokProvider.ts @@ -1,7 +1,6 @@ import { type GrokSettings, type ModelCapabilities, - ProviderDriverKind, type ServerProvider, type ServerProviderModel, } from "@t3tools/contracts"; @@ -38,7 +37,6 @@ const GROK_PRESENTATION = { showInteractionModeToggle: false, requiresNewThreadForModelChange: true, } as const; -const PROVIDER = ProviderDriverKind.make("grok"); const EMPTY_CAPABILITIES: ModelCapabilities = createModelCapabilities({ optionDescriptors: [], }); @@ -98,12 +96,7 @@ function grokModelsFromSettings( customModels: ReadonlyArray | undefined, builtInModels: ReadonlyArray = GROK_BUILT_IN_MODELS, ): ReadonlyArray { - return providerModelsFromSettings( - builtInModels, - PROVIDER, - customModels ?? [], - EMPTY_CAPABILITIES, - ); + return providerModelsFromSettings(builtInModels, customModels ?? [], EMPTY_CAPABILITIES); } function buildGrokDiscoveredModelsFromSessionModelState( diff --git a/apps/server/src/provider/Layers/KiloProvider.ts b/apps/server/src/provider/Layers/KiloProvider.ts index 44fc41b04413..af83ac59767f 100644 --- a/apps/server/src/provider/Layers/KiloProvider.ts +++ b/apps/server/src/provider/Layers/KiloProvider.ts @@ -131,7 +131,6 @@ export const checkKiloProviderStatus = Effect.fn("checkKiloProviderStatus")(func const checkedAt = new Date().toISOString(); const allModels = providerModelsFromSettings( [], - PROVIDER, kiloSettings.customModels, DEFAULT_KILO_MODEL_CAPABILITIES, ); @@ -218,7 +217,6 @@ export const checkKiloProviderStatus = Effect.fn("checkKiloProviderStatus")(func const discovered = yield* discoverKiloModels(kiloSettings); const readyModels = providerModelsFromSettings( kiloDiscoveredToServerModels(discovered), - PROVIDER, kiloSettings.customModels, DEFAULT_KILO_MODEL_CAPABILITIES, ); @@ -245,7 +243,6 @@ export const makePendingKiloProvider = (kiloSettings: KiloSettings): ServerProvi const checkedAt = new Date().toISOString(); const models = providerModelsFromSettings( [], - PROVIDER, kiloSettings.customModels, DEFAULT_KILO_MODEL_CAPABILITIES, ); diff --git a/apps/server/src/provider/Layers/OpenCodeAdapter.test.ts b/apps/server/src/provider/Layers/OpenCodeAdapter.test.ts index b227ff1ab66b..1385ccbaabec 100644 --- a/apps/server/src/provider/Layers/OpenCodeAdapter.test.ts +++ b/apps/server/src/provider/Layers/OpenCodeAdapter.test.ts @@ -5,8 +5,10 @@ import * as Context from "effect/Context"; import * as Effect from "effect/Effect"; import * as Exit from "effect/Exit"; import * as Fiber from "effect/Fiber"; +import * as FileSystem from "effect/FileSystem"; import * as Layer from "effect/Layer"; import * as Option from "effect/Option"; +import * as Path from "effect/Path"; import * as Schema from "effect/Schema"; import * as Scope from "effect/Scope"; import * as Stream from "effect/Stream"; @@ -31,6 +33,8 @@ import { } from "../opencodeRuntime.ts"; import { appendOpenCodeAssistantTextDelta, + isOpenCodeNotFound, + isSameOpenCodeDirectory, makeOpenCodeAdapter, mergeOpenCodeAssistantText, } from "./OpenCodeAdapter.ts"; @@ -54,6 +58,7 @@ const runtimeMock = { state: { startCalls: [] as string[], sessionCreateUrls: [] as string[], + sessionCreateInputs: [] as Array>, authHeaders: [] as Array, abortCalls: [] as string[], closeCalls: [] as string[], @@ -63,10 +68,17 @@ const runtimeMock = { closeError: null as Error | null, messages: [] as MessageEntry[], subscribedEvents: [] as unknown[], + sessionGetIds: [] as string[], + missingSessionIds: new Set(), + transientErrorSessionIds: new Set(), + sessionDirectoryById: new Map(), + sessionUpdateCalls: [] as Array<{ sessionID: string; permission: unknown }>, + forkCalls: [] as Array<{ sessionID: string; directory?: string }>, }, reset() { this.state.startCalls.length = 0; this.state.sessionCreateUrls.length = 0; + this.state.sessionCreateInputs.length = 0; this.state.authHeaders.length = 0; this.state.abortCalls.length = 0; this.state.closeCalls.length = 0; @@ -76,6 +88,12 @@ const runtimeMock = { this.state.closeError = null; this.state.messages = []; this.state.subscribedEvents = []; + this.state.sessionGetIds.length = 0; + this.state.missingSessionIds.clear(); + this.state.transientErrorSessionIds.clear(); + this.state.sessionDirectoryById.clear(); + this.state.sessionUpdateCalls.length = 0; + this.state.forkCalls.length = 0; }, }; @@ -100,10 +118,8 @@ const OpenCodeRuntimeTestDouble: OpenCodeRuntimeShape = { connectToOpenCodeServer: ({ serverUrl }) => Effect.gen(function* () { const url = serverUrl ?? "http://127.0.0.1:4301"; - // Unconditionally register a scope finalizer for test observability — - // preserves the `closeCalls` / `closeError` probes that the existing - // suites rely on. Production code never attaches a finalizer to an - // external server (it simply returns `Effect.succeed(...)`). + // Always register a finalizer so the closeCalls/closeError probes fire; + // production attaches none for external servers. yield* Effect.addFinalizer(() => Effect.sync(() => { runtimeMock.state.closeCalls.push(url); @@ -122,13 +138,42 @@ const OpenCodeRuntimeTestDouble: OpenCodeRuntimeShape = { createOpenCodeSdkClient: ({ baseUrl, serverPassword }) => ({ session: { - create: async () => { + create: async (input: Record) => { runtimeMock.state.sessionCreateUrls.push(baseUrl); + runtimeMock.state.sessionCreateInputs.push(input); runtimeMock.state.authHeaders.push( serverPassword ? `Basic ${btoa(`opencode:${serverPassword}`)}` : null, ); return { data: { id: `${baseUrl}/session` } }; }, + get: async ({ sessionID }: { sessionID: string }) => { + runtimeMock.state.sessionGetIds.push(sessionID); + // The real client is `throwOnError: true`: non-2xx rejects rather + // than resolving, so missing → 404 throw, transient → 500 throw. + if (runtimeMock.state.transientErrorSessionIds.has(sessionID)) { + throw new Error("opencode server error", { cause: { status: 500 } }); + } + if (runtimeMock.state.missingSessionIds.has(sessionID)) { + throw new Error(`Session not found: ${sessionID}`, { + cause: { status: 404, body: { name: "NotFoundError" } }, + }); + } + const directory = runtimeMock.state.sessionDirectoryById.get(sessionID); + return { data: { id: sessionID, ...(directory ? { directory } : {}) } }; + }, + update: async ({ sessionID, permission }: { sessionID: string; permission: unknown }) => { + runtimeMock.state.sessionUpdateCalls.push({ sessionID, permission }); + return { data: { id: sessionID } }; + }, + fork: async ({ sessionID, directory }: { sessionID: string; directory?: string }) => { + // Fork clones history into a new session bound to the directory. + const forkedId = `${sessionID}_fork`; + runtimeMock.state.forkCalls.push({ sessionID, ...(directory ? { directory } : {}) }); + if (directory) { + runtimeMock.state.sessionDirectoryById.set(forkedId, directory); + } + return { data: { id: forkedId, ...(directory ? { directory } : {}) } }; + }, abort: async ({ sessionID }: { sessionID: string }) => { runtimeMock.state.abortCalls.push(sessionID); }, @@ -176,6 +221,14 @@ const OpenCodeRuntimeTestDouble: OpenCodeRuntimeShape = { cause: null, }), ), + loadInventoryFromCli: () => + Effect.fail( + new OpenCodeRuntimeError({ + operation: "loadInventoryFromCli", + detail: "OpenCodeRuntimeTestDouble.loadInventoryFromCli not used in this test", + cause: null, + }), + ), }; const providerSessionDirectoryTestLayer = Layer.succeed(ProviderSessionDirectory, { @@ -248,6 +301,256 @@ it.layer(OpenCodeAdapterTestLayer)("OpenCodeAdapterLive", (it) => { }), ); + it.effect("returns a durable resume cursor for a freshly created session", () => + Effect.gen(function* () { + const adapter = yield* OpenCodeAdapter; + const threadId = asThreadId("thread-opencode-cursor"); + + const session = yield* adapter.startSession({ + provider: ProviderDriverKind.make("opencode"), + threadId, + runtimeMode: "full-access", + }); + + // Without a persisted cursor, a session is created and its id is + // surfaced as a resume cursor so the upper layer can persist it. + NodeAssert.deepEqual(runtimeMock.state.sessionGetIds, []); + NodeAssert.deepEqual(session.resumeCursor, { + schemaVersion: 1, + sessionId: "http://127.0.0.1:9999/session", + }); + + yield* adapter.stopSession(threadId); + }), + ); + + it.effect("resumes the persisted OpenCode session instead of creating a new one", () => + Effect.gen(function* () { + const adapter = yield* OpenCodeAdapter; + const threadId = asThreadId("thread-opencode-resume"); + + const session = yield* adapter.startSession({ + provider: ProviderDriverKind.make("opencode"), + threadId, + runtimeMode: "full-access", + resumeCursor: { schemaVersion: 1, sessionId: "ses_persisted" }, + }); + + // The adapter validates the persisted id with session.get and re-adopts + // it — no new session is minted (issue #3604). + NodeAssert.deepEqual(runtimeMock.state.sessionGetIds, ["ses_persisted"]); + NodeAssert.deepEqual(runtimeMock.state.sessionCreateUrls, []); + NodeAssert.deepEqual(session.resumeCursor, { + schemaVersion: 1, + sessionId: "ses_persisted", + }); + // Resume re-asserts the permission ruleset for the current runtimeMode. + NodeAssert.equal(runtimeMock.state.sessionUpdateCalls.length, 1); + NodeAssert.equal(runtimeMock.state.sessionUpdateCalls[0]?.sessionID, "ses_persisted"); + NodeAssert.equal(runtimeMock.state.sessionUpdateCalls[0]?.permission != null, true); + + yield* adapter.stopSession(threadId); + }), + ); + + it.effect("sends follow-up turns to the resumed session id", () => + Effect.gen(function* () { + const adapter = yield* OpenCodeAdapter; + const threadId = asThreadId("thread-opencode-resume-turn"); + + yield* adapter.startSession({ + provider: ProviderDriverKind.make("opencode"), + threadId, + runtimeMode: "full-access", + resumeCursor: { schemaVersion: 1, sessionId: "ses_persisted" }, + }); + + const result = yield* adapter.sendTurn({ + threadId, + input: "continue where we left off", + modelSelection: createModelSelection( + ProviderInstanceId.make("opencode"), + "anthropic/sonnet", + ), + }); + + // The prompt targets the resumed id, and the turn re-surfaces the cursor. + NodeAssert.deepEqual( + (runtimeMock.state.promptCalls[0] as { sessionID: string }).sessionID, + "ses_persisted", + ); + NodeAssert.deepEqual(result.resumeCursor, { + schemaVersion: 1, + sessionId: "ses_persisted", + }); + + yield* adapter.stopSession(threadId); + }), + ); + + it.effect("falls back to a fresh session when the persisted session is gone", () => + Effect.gen(function* () { + const adapter = yield* OpenCodeAdapter; + const threadId = asThreadId("thread-opencode-stale"); + runtimeMock.state.missingSessionIds.add("ses_stale"); + + const session = yield* adapter.startSession({ + provider: ProviderDriverKind.make("opencode"), + threadId, + runtimeMode: "full-access", + resumeCursor: { schemaVersion: 1, sessionId: "ses_stale" }, + }); + + // get probed the stale id, found nothing, then created a new session and + // emitted a fresh cursor rather than wedging the thread. + NodeAssert.deepEqual(runtimeMock.state.sessionGetIds, ["ses_stale"]); + NodeAssert.deepEqual(runtimeMock.state.sessionCreateUrls, ["http://127.0.0.1:9999"]); + NodeAssert.deepEqual(session.resumeCursor, { + schemaVersion: 1, + sessionId: "http://127.0.0.1:9999/session", + }); + + yield* adapter.stopSession(threadId); + }), + ); + + it.effect("ignores a malformed or wrong-version resume cursor", () => + Effect.gen(function* () { + const adapter = yield* OpenCodeAdapter; + const threadId = asThreadId("thread-opencode-badcursor"); + + const session = yield* adapter.startSession({ + provider: ProviderDriverKind.make("opencode"), + threadId, + runtimeMode: "full-access", + resumeCursor: { schemaVersion: 99, sessionId: "ses_persisted" }, + }); + + // A foreign/stale-shaped cursor is treated as "no resume": never probed, + // a fresh session is created. + NodeAssert.deepEqual(runtimeMock.state.sessionGetIds, []); + NodeAssert.deepEqual(runtimeMock.state.sessionCreateUrls, ["http://127.0.0.1:9999"]); + NodeAssert.deepEqual(session.resumeCursor, { + schemaVersion: 1, + sessionId: "http://127.0.0.1:9999/session", + }); + + yield* adapter.stopSession(threadId); + }), + ); + + it.effect("surfaces a non-not-found resume probe error instead of silently starting fresh", () => + Effect.gen(function* () { + const adapter = yield* OpenCodeAdapter; + const threadId = asThreadId("thread-opencode-transient"); + // session.get returns a 500 (not a 404) for this id. + runtimeMock.state.transientErrorSessionIds.add("ses_transient"); + + const exit = yield* Effect.exit( + adapter.startSession({ + provider: ProviderDriverKind.make("opencode"), + threadId, + runtimeMode: "full-access", + resumeCursor: { schemaVersion: 1, sessionId: "ses_transient" }, + }), + ); + + // A transient/transport/auth failure must propagate — NOT be masked as a + // brand-new empty session (the #3604 class of silent context loss). + NodeAssert.equal(Exit.isFailure(exit), true); + NodeAssert.deepEqual(runtimeMock.state.sessionGetIds, ["ses_transient"]); + NodeAssert.deepEqual(runtimeMock.state.sessionCreateUrls, []); + }), + ); + + it.effect("re-applies the current runtimeMode permissions when resuming", () => + Effect.gen(function* () { + const adapter = yield* OpenCodeAdapter; + const threadId = asThreadId("thread-opencode-perms"); + + yield* adapter.startSession({ + provider: ProviderDriverKind.make("opencode"), + // A different runtimeMode than the original create — resume must not + // leave the upstream session on stale permissions. + runtimeMode: "approval-required", + threadId, + resumeCursor: { schemaVersion: 1, sessionId: "ses_perms" }, + }); + + NodeAssert.deepEqual(runtimeMock.state.sessionGetIds, ["ses_perms"]); + NodeAssert.deepEqual(runtimeMock.state.sessionCreateUrls, []); + NodeAssert.equal(runtimeMock.state.sessionUpdateCalls.length, 1); + NodeAssert.equal(runtimeMock.state.sessionUpdateCalls[0]?.sessionID, "ses_perms"); + NodeAssert.equal(runtimeMock.state.sessionUpdateCalls[0]?.permission != null, true); + + yield* adapter.stopSession(threadId); + }), + ); + + it.effect( + "forks the resumed session into the requested directory instead of losing context", + () => + Effect.gen(function* () { + const adapter = yield* OpenCodeAdapter; + const threadId = asThreadId("thread-opencode-cwd"); + // The persisted session still exists but was created in another working dir + // (e.g. the thread moved from the project root into a git worktree). + runtimeMock.state.sessionDirectoryById.set("ses_otherdir", "/some/other/worktree"); + + const session = yield* adapter.startSession({ + provider: ProviderDriverKind.make("opencode"), + threadId, + runtimeMode: "full-access", + resumeCursor: { schemaVersion: 1, sessionId: "ses_otherdir" }, + }); + + // A cwd change must not mint an empty session: the adapter forks the + // persisted session into the requested cwd, carrying history forward. + NodeAssert.deepEqual(runtimeMock.state.sessionGetIds, ["ses_otherdir"]); + NodeAssert.deepEqual(runtimeMock.state.sessionCreateUrls, []); + NodeAssert.equal(runtimeMock.state.forkCalls.length, 1); + NodeAssert.equal(runtimeMock.state.forkCalls[0]?.sessionID, "ses_otherdir"); + NodeAssert.equal(typeof runtimeMock.state.forkCalls[0]?.directory, "string"); + // Permission ruleset re-asserted on the fork for the current runtimeMode. + NodeAssert.equal(runtimeMock.state.sessionUpdateCalls.length, 1); + NodeAssert.equal(runtimeMock.state.sessionUpdateCalls[0]?.sessionID, "ses_otherdir_fork"); + // Durable cursor now points at the history-complete fork in the new directory. + NodeAssert.deepEqual(session.resumeCursor, { + schemaVersion: 1, + sessionId: "ses_otherdir_fork", + }); + + yield* adapter.stopSession(threadId); + }), + ); + + it.effect("reuses the resumed session when the stored directory differs only lexically", () => + Effect.gen(function* () { + const adapter = yield* OpenCodeAdapter; + const threadId = asThreadId("thread-opencode-samedir"); + // Same working tree, different spelling (trailing slash) — must reuse, + // not fork. + runtimeMock.state.sessionDirectoryById.set("ses_samedir", `${process.cwd()}/`); + + const session = yield* adapter.startSession({ + provider: ProviderDriverKind.make("opencode"), + threadId, + runtimeMode: "full-access", + resumeCursor: { schemaVersion: 1, sessionId: "ses_samedir" }, + }); + + NodeAssert.deepEqual(runtimeMock.state.sessionGetIds, ["ses_samedir"]); + NodeAssert.deepEqual(runtimeMock.state.sessionCreateUrls, []); + NodeAssert.deepEqual(runtimeMock.state.forkCalls, []); + NodeAssert.deepEqual(session.resumeCursor, { + schemaVersion: 1, + sessionId: "ses_samedir", + }); + + yield* adapter.stopSession(threadId); + }), + ); + it.effect("fails sendTurn for missing sessions through the typed error channel", () => Effect.gen(function* () { const adapter = yield* OpenCodeAdapter; @@ -670,6 +973,88 @@ it.layer(OpenCodeAdapterTestLayer)("OpenCodeAdapterLive", (it) => { }), ); + it.effect("classifies a confirmed not-found across the shapes the SDK/runtime can produce", () => + Effect.sync(() => { + // The real production shape: runOpenCodeSdk wraps the thrown Error + // (cause = { body, status }) under OpenCodeRuntimeError. + const wrappedError = new Error("Session not found: ses_x", { + cause: { body: { name: "NotFoundError" }, status: 404 }, + }); + NodeAssert.equal( + isOpenCodeNotFound({ + _tag: "OpenCodeRuntimeError", + operation: "session.get", + detail: "Session not found: ses_x", + cause: wrappedError, + }), + true, + ); + + // 404 expressed only via response.status (the bot's flagged shape). + NodeAssert.equal(isOpenCodeNotFound({ cause: { response: { status: 404 } } }), true); + // 404 via a bare numeric status / statusCode. + NodeAssert.equal(isOpenCodeNotFound(new Error("x", { cause: { status: 404 } })), true); + NodeAssert.equal(isOpenCodeNotFound({ statusCode: 404 }), true); + // OpenCode NotFoundError body name with no status. + NodeAssert.equal(isOpenCodeNotFound({ body: { name: "NotFoundError" } }), true); + + // NOT a miss: only structured signals count, never free text. A non-404 + // error whose message/detail merely contains "not found" must propagate, + // not be misread as a missing session and silently start fresh. + NodeAssert.equal( + isOpenCodeNotFound(new Error("upstream provider not found", { cause: { status: 500 } })), + false, + ); + NodeAssert.equal(isOpenCodeNotFound({ detail: "status=500 body={...not found...}" }), false); + // An explicit non-404 status seals its subtree: a 500 whose serialized + // body echoes a NotFoundError name — or that is itself named + // *NotFound* — is a real failure, never a miss. + NodeAssert.equal(isOpenCodeNotFound({ status: 500, body: { name: "NotFoundError" } }), false); + NodeAssert.equal(isOpenCodeNotFound({ name: "UpstreamNotFoundError", status: 500 }), false); + // A "NotFound"-flavored name that isn't OpenCode's exact `NotFoundError` + // is not a confirmed miss even without a sealing status. + NodeAssert.equal(isOpenCodeNotFound({ name: "UpstreamNotFoundError" }), false); + NodeAssert.equal(isOpenCodeNotFound({ cause: { name: "ProviderNotFoundError" } }), false); + NodeAssert.equal( + isOpenCodeNotFound( + new Error("x", { cause: { status: 502, body: { name: "NotFoundError" } } }), + ), + false, + ); + // Other transient/auth/network failures must propagate too. + NodeAssert.equal(isOpenCodeNotFound(new Error("boom", { cause: { status: 500 } })), false); + NodeAssert.equal(isOpenCodeNotFound({ cause: { response: { status: 401 } } }), false); + NodeAssert.equal(isOpenCodeNotFound(new Error("network error (no response)")), false); + NodeAssert.equal(isOpenCodeNotFound(undefined), false); + }), + ); + + it.effect("treats lexically or physically identical directories as the same", () => + Effect.gen(function* () { + const fileSystem = yield* FileSystem.FileSystem; + const path = yield* Path.Path; + const sameDirectory = (left: string, right: string) => + isSameOpenCodeDirectory(fileSystem, path, left, right); + + // Lexical-only differences (trailing slash, dot segments) short-circuit + // without touching the filesystem — the paths need not exist. + NodeAssert.equal(yield* sameDirectory("/repo/project/", "/repo/project"), true); + NodeAssert.equal(yield* sameDirectory("/repo/nested/../project", "/repo/project"), true); + // Nonexistent paths degrade to the lexical comparison instead of failing. + NodeAssert.equal(yield* sameDirectory("/repo/project", "/repo/other"), false); + + // A symlinked cwd (the macOS `/tmp` → `/private/tmp` shape) resolves to + // the directory it points at, so the two spellings compare equal. + const base = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3-opencode-dir-" }); + const real = path.join(base, "real"); + const link = path.join(base, "link"); + yield* fileSystem.makeDirectory(real); + yield* fileSystem.symlink(real, link); + NodeAssert.equal(yield* sameDirectory(link, real), true); + NodeAssert.equal(yield* sameDirectory(link, path.join(base, "other")), false); + }).pipe(Effect.scoped), + ); + it.effect("appends raw assistant text deltas and reconciles part update snapshots", () => Effect.sync(() => { const firstUpdate = mergeOpenCodeAssistantText(undefined, "Hello"); @@ -765,6 +1150,47 @@ it.layer(OpenCodeAdapterTestLayer)("OpenCodeAdapterLive", (it) => { }), ); + it.effect("lets OpenCode own session title generation and emits title metadata updates", () => + Effect.gen(function* () { + const adapter = yield* OpenCodeAdapter; + const threadId = asThreadId("thread-opencode-title-sync"); + runtimeMock.state.subscribedEvents = [ + { + type: "session.updated", + properties: { + info: { + id: "http://127.0.0.1:9999/session", + title: "Investigate OpenCode title sync", + }, + }, + }, + ]; + + const eventsFiber = yield* adapter.streamEvents.pipe( + Stream.filter((event) => event.threadId === threadId), + Stream.take(3), + Stream.runCollect, + Effect.forkChild, + ); + + yield* adapter.startSession({ + provider: ProviderDriverKind.make("opencode"), + threadId, + runtimeMode: "full-access", + }); + + const events = Array.from(yield* Fiber.join(eventsFiber).pipe(Effect.timeout("1 second"))); + NodeAssert.equal(runtimeMock.state.sessionCreateInputs.length, 1); + NodeAssert.equal("title" in (runtimeMock.state.sessionCreateInputs[0] ?? {}), false); + + const metadataUpdated = events.find((event) => event.type === "thread.metadata.updated"); + NodeAssert.ok(metadataUpdated); + if (metadataUpdated.type === "thread.metadata.updated") { + NodeAssert.equal(metadataUpdated.payload.name, "Investigate OpenCode title sync"); + } + }), + ); + it.effect("writes provider-native observability records using the session thread id", () => Effect.gen(function* () { const nativeEvents: Array<{ diff --git a/apps/server/src/provider/Layers/OpenCodeAdapter.ts b/apps/server/src/provider/Layers/OpenCodeAdapter.ts index 956905e3a3cf..73c23b77e686 100644 --- a/apps/server/src/provider/Layers/OpenCodeAdapter.ts +++ b/apps/server/src/provider/Layers/OpenCodeAdapter.ts @@ -17,6 +17,8 @@ import * as Crypto from "effect/Crypto"; import * as DateTime from "effect/DateTime"; import * as Effect from "effect/Effect"; import * as Exit from "effect/Exit"; +import * as FileSystem from "effect/FileSystem"; +import * as Path from "effect/Path"; import * as Queue from "effect/Queue"; import * as Ref from "effect/Ref"; import * as Scope from "effect/Scope"; @@ -53,6 +55,114 @@ import * as Option from "effect/Option"; const PROVIDER = ProviderDriverKind.make("opencode"); +/** + * Version tag stamped into the OpenCode resume cursor. Bump if the cursor + * shape changes so stale-shaped cursors written by older builds are ignored + * rather than misread (mirrors GROK_RESUME_VERSION / CURSOR_RESUME_VERSION). + */ +const OPENCODE_RESUME_VERSION = 1 as const; + +/** + * Decode a persisted resume cursor into the upstream `ses_…` id. Anything + * that isn't a current-version cursor with a non-empty id means "no resume" + * rather than an error. Re-adopting the session id IS the resume mechanism — + * OpenCode scopes a conversation's history by session id. + */ +function parseOpenCodeResume(raw: unknown): { readonly sessionId: string } | undefined { + if (typeof raw !== "object" || raw === null || Array.isArray(raw)) { + return undefined; + } + const record = raw as Record; + if (record.schemaVersion !== OPENCODE_RESUME_VERSION) { + return undefined; + } + if (typeof record.sessionId !== "string" || record.sessionId.trim().length === 0) { + return undefined; + } + return { sessionId: record.sessionId.trim() }; +} + +/** + * Whether an error definitively reports a missing session. Only a confirmed + * miss may silently start a fresh session; any other failure (the SDK client + * is `throwOnError: true`, so `session.get` rejects on every non-2xx) must + * propagate, or a transient blip resets a live thread to an empty one — the + * #3604 silent context loss. Decides on structured signals only, never free + * text: a numeric 404 or the exact `NotFoundError` name, found via a bounded walk + * over `cause`/`body`/`error`/`data`. An explicit non-404 status seals its + * subtree so a wrapped "NotFound" name can't reclassify a real failure. + * Exported for unit testing. + */ +export function isOpenCodeNotFound(cause: unknown): boolean { + const seen = new Set(); + const queue: Array = [cause]; + for (let steps = 0; queue.length > 0 && steps < 32; steps += 1) { + const node = queue.shift(); + if (node === null || typeof node !== "object" || seen.has(node)) { + continue; + } + seen.add(node); + const record = node as Record; + + const response = record.response; + const statuses = [ + record.status, + record.statusCode, + response !== null && typeof response === "object" + ? (response as { readonly status?: unknown }).status + : undefined, + ].filter((status): status is number => typeof status === "number"); + if (statuses.includes(404)) { + return true; + } + if (statuses.length > 0) { + continue; + } + + const name = record.name; + if (typeof name === "string" && name.toLowerCase() === "notfounderror") { + return true; + } + + for (const key of ["cause", "body", "error", "data"] as const) { + if (record[key] !== undefined) { + queue.push(record[key]); + } + } + } + return false; +} + +/** + * Whether two directory spellings name the same location. Raw string + * equality misreads a trailing slash, `.`/`..` segment, or symlinked cwd + * (macOS `/tmp` → `/private/tmp`) as a cwd change, needlessly forking the + * session on every resume. Lexically equal paths short-circuit; otherwise + * both sides go through `realPath`, each falling back to its lexical form + * on failure (deleted directory, external-server path) — so the probe can + * only widen matches, never split them. Takes the services as arguments so + * adapter methods stay service-free. Exported for unit testing. + */ +export function isSameOpenCodeDirectory( + fileSystem: FileSystem.FileSystem, + path: Path.Path, + left: string, + right: string, +): Effect.Effect { + const lexicalLeft = path.resolve(left); + const lexicalRight = path.resolve(right); + if (lexicalLeft === lexicalRight) { + return Effect.succeed(true); + } + const canonicalize = (lexical: string) => + fileSystem.realPath(lexical).pipe(Effect.orElseSucceed(() => lexical)); + return Effect.zipWith( + canonicalize(lexicalLeft), + canonicalize(lexicalRight), + (canonicalLeft, canonicalRight) => canonicalLeft === canonicalRight, + ); +} + interface OpenCodeTurnSnapshot { readonly id: TurnId; readonly items: Array; @@ -65,6 +175,35 @@ type OpenCodeSubscribedEvent = ? TEvent : never; +function trimText(value: string | undefined | null): string | undefined { + const trimmed = value?.trim(); + return trimmed && trimmed.length > 0 ? trimmed : undefined; +} + +function openCodeEventSessionId(event: OpenCodeSubscribedEvent): string | undefined { + const properties = "properties" in event ? event.properties : undefined; + if (!properties || typeof properties !== "object") { + return undefined; + } + + const sessionID = (properties as { readonly sessionID?: unknown }).sessionID; + const sessionIDFromProperties = typeof sessionID === "string" ? sessionID : undefined; + if (sessionIDFromProperties) { + return sessionIDFromProperties; + } + + const info = (properties as { readonly info?: { readonly id?: unknown } }).info; + return info && typeof info.id === "string" ? info.id : undefined; +} + +function openCodeEventSessionTitle(event: OpenCodeSubscribedEvent): string | undefined { + if (event.type !== "session.updated") { + return undefined; + } + + return trimText(event.properties.info.title); +} + interface OpenCodeSessionContext { session: ProviderSession; readonly client: OpencodeClient; @@ -430,6 +569,10 @@ export function makeOpenCodeAdapter( const serverConfig = yield* ServerConfig; const openCodeRuntime = yield* OpenCodeRuntime; const crypto = yield* Crypto.Crypto; + const fileSystem = yield* FileSystem.FileSystem; + const path = yield* Path.Path; + const sameDirectory = (left: string, right: string) => + isSameOpenCodeDirectory(fileSystem, path, left, right); const nativeEventLogger = options?.nativeEventLogger ?? (options?.nativeEventLogPath !== undefined @@ -643,8 +786,7 @@ export function makeOpenCodeAdapter( context: OpenCodeSessionContext, event: OpenCodeSubscribedEvent, ) { - const payloadSessionId = - "properties" in event ? (event.properties as { sessionID?: unknown }).sessionID : undefined; + const payloadSessionId = openCodeEventSessionId(event); if (payloadSessionId !== context.openCodeSessionId) { return; } @@ -663,6 +805,26 @@ export function makeOpenCodeAdapter( }); switch (event.type) { + case "session.updated": { + const title = openCodeEventSessionTitle(event); + if (title) { + yield* emit({ + ...(yield* buildEventBase({ + threadId: context.session.threadId, + raw: event, + })), + type: "thread.metadata.updated", + payload: { + name: title, + metadata: { + sessionID: context.openCodeSessionId, + }, + }, + }); + } + break; + } + case "message.updated": { context.messageRoleById.set(event.properties.info.id, event.properties.info.role); if (event.properties.info.role === "assistant") { @@ -1028,6 +1190,7 @@ export function makeOpenCodeAdapter( const serverUrl = openCodeSettings.serverUrl; const serverPassword = openCodeSettings.serverPassword; const directory = input.cwd ?? serverConfig.cwd; + const resumeSessionId = parseOpenCodeResume(input.resumeCursor)?.sessionId; const existing = sessions.get(input.threadId); if (existing) { yield* stopOpenCodeContext(existing); @@ -1067,23 +1230,96 @@ export function makeOpenCodeAdapter( }), ); } - const openCodeSession = yield* runOpenCodeSdk("session.create", () => - client.session.create({ - title: `T3 Code ${input.threadId}`, - permission: buildOpenCodePermissionRules(input.runtimeMode), - }), - ); - if (!openCodeSession.data) { - return yield* new OpenCodeRuntimeError({ - operation: "session.create", - detail: "OpenCode session.create returned no session payload.", - }); - } + // Resume: re-adopt the session named by the durable cursor — + // OpenCode scopes history by session id. The probe recovers only + // a confirmed not-found (start fresh); transport/auth/server + // errors propagate instead of masking as a new empty session. + const resolved = yield* Effect.gen(function* () { + const adopted = resumeSessionId + ? yield* runOpenCodeSdk("session.get", () => + client.session.get({ sessionID: resumeSessionId }), + ).pipe( + Effect.map((response) => response.data), + Effect.catchIf( + (cause) => isOpenCodeNotFound(cause), + () => Effect.void, + ), + ) + : undefined; + + // Reuse in place only when the session still matches the + // requested cwd; on a cwd change it is forked below instead. + const reusable = + adopted && + (!adopted.directory || (yield* sameDirectory(adopted.directory, directory))) + ? adopted + : undefined; + + if (reusable) { + // Resume skips `session.create`, so re-assert the ruleset — + // a runtime-mode change would otherwise leave the session on + // its original permissions. + yield* runOpenCodeSdk("session.update", () => + client.session.update({ + sessionID: reusable.id, + permission: buildOpenCodePermissionRules(input.runtimeMode), + }), + ); + return { openCodeSession: reusable, created: false }; + } + + // The session lives under a different cwd (e.g. the thread + // moved into a git worktree). Fork it into the requested + // directory instead of minting an empty one — the fork carries + // the full history, so the follow-up keeps its context (#3604). + if (adopted) { + yield* Effect.logInfo( + `OpenCode session '${adopted.id}' was created under a different working directory; forking into '${directory}' to preserve conversation history.`, + ); + const forkedSession = yield* runOpenCodeSdk("session.fork", () => + client.session.fork({ sessionID: adopted.id, directory }), + ); + const forked = forkedSession.data; + if (!forked) { + return yield* new OpenCodeRuntimeError({ + operation: "session.fork", + detail: "OpenCode session.fork returned no session payload.", + }); + } + yield* runOpenCodeSdk("session.update", () => + client.session.update({ + sessionID: forked.id, + permission: buildOpenCodePermissionRules(input.runtimeMode), + }), + ); + return { openCodeSession: forked, created: true }; + } + + if (resumeSessionId) { + yield* Effect.logWarning( + `OpenCode session '${resumeSessionId}' no longer exists; starting a fresh session.`, + ); + } + const createdSession = yield* runOpenCodeSdk("session.create", () => + client.session.create({ + permission: buildOpenCodePermissionRules(input.runtimeMode), + }), + ); + if (!createdSession.data) { + return yield* new OpenCodeRuntimeError({ + operation: "session.create", + detail: "OpenCode session.create returned no session payload.", + }); + } + return { openCodeSession: createdSession.data, created: true }; + }); + return { sessionScope, server, client, - openCodeSession: openCodeSession.data, + openCodeSession: resolved.openCodeSession, + created: resolved.created, }; }).pipe(Effect.provideService(Scope.Scope, sessionScope)), ); @@ -1098,13 +1334,16 @@ export function makeOpenCodeAdapter( // and already inserted a session while we were awaiting async work. const raceWinner = sessions.get(input.threadId); if (raceWinner) { - // Another call won the race – clean up the session we just created - // (including the remote SDK session) and return the existing one. - yield* runOpenCodeSdk("session.abort", () => - started.client.session.abort({ - sessionID: started.openCodeSession.id, - }), - ).pipe(Effect.ignore); + // Another call won the race — clean up. Only abort the remote + // session if we created it here; a resumed one is shared upstream + // state the winner is now using. + if (started.created) { + yield* runOpenCodeSdk("session.abort", () => + started.client.session.abort({ + sessionID: started.openCodeSession.id, + }), + ).pipe(Effect.ignore); + } yield* Scope.close(started.sessionScope, Exit.void).pipe(Effect.ignore); return raceWinner.session; } @@ -1118,6 +1357,13 @@ export function makeOpenCodeAdapter( cwd: directory, ...(input.modelSelection ? { model: input.modelSelection.model } : {}), threadId: input.threadId, + // ProviderService persists this cursor and feeds it back into + // `startSession` after the in-memory session is lost (reaper / + // restart), so follow-ups continue the same conversation (#3604). + resumeCursor: { + schemaVersion: OPENCODE_RESUME_VERSION, + sessionId: started.openCodeSession.id, + }, createdAt, updatedAt: createdAt, }; @@ -1283,6 +1529,11 @@ export function makeOpenCodeAdapter( return { threadId: input.threadId, turnId, + // Re-surface the durable cursor on every turn so the persisted binding + // is refreshed alongside last-seen/runtime state (mirrors Grok/Codex). + ...(context.session.resumeCursor !== undefined + ? { resumeCursor: context.session.resumeCursor } + : {}), }; }); diff --git a/apps/server/src/provider/Layers/OpenCodeProvider.test.ts b/apps/server/src/provider/Layers/OpenCodeProvider.test.ts index b0e785512dc4..05160517bfeb 100644 --- a/apps/server/src/provider/Layers/OpenCodeProvider.test.ts +++ b/apps/server/src/provider/Layers/OpenCodeProvider.test.ts @@ -95,6 +95,13 @@ const OpenCodeRuntimeTestDouble: OpenCodeRuntimeShape = { }), ) : Effect.succeed(runtimeMock.state.inventory as OpenCodeInventory), + loadInventoryFromCli: () => + runtimeMock.state.inventoryError + ? Effect.succeed({ + providerList: { all: [], default: {}, connected: [] as string[] }, + agents: [], + } as OpenCodeInventory) + : Effect.succeed(runtimeMock.state.inventory as OpenCodeInventory), }; beforeEach(() => { @@ -197,11 +204,22 @@ it.layer(testLayer)("checkOpenCodeProviderStatus", (it) => { }), ); - it.effect("closes the local OpenCode server scope after provider refresh", () => + it.effect("does not spawn a local server for health check (uses CLI instead)", () => Effect.gen(function* () { yield* checkOpenCodeProviderStatus(makeOpenCodeSettings(), process.cwd()); - NodeAssert.equal(runtimeMock.state.closeCalls, 1); + NodeAssert.equal(runtimeMock.state.closeCalls, 0); + }), + ); + + it.effect("degrades gracefully on CLI failure for local installs", () => + Effect.gen(function* () { + runtimeMock.state.inventoryError = new Error("opencode models failed"); + const snapshot = yield* checkOpenCodeProviderStatus(makeOpenCodeSettings(), process.cwd()); + + NodeAssert.equal(snapshot.status, "warning"); + NodeAssert.equal(snapshot.installed, true); + NodeAssert.equal(snapshot.models.length, 0); }), ); }); diff --git a/apps/server/src/provider/Layers/OpenCodeProvider.ts b/apps/server/src/provider/Layers/OpenCodeProvider.ts index a8285e960fc1..21014e33f08b 100644 --- a/apps/server/src/provider/Layers/OpenCodeProvider.ts +++ b/apps/server/src/provider/Layers/OpenCodeProvider.ts @@ -1,5 +1,4 @@ import { - ProviderDriverKind, type ModelCapabilities, type OpenCodeSettings, type ServerProviderModel, @@ -25,7 +24,6 @@ import { } from "../opencodeRuntime.ts"; import type { Agent, ProviderListResponse } from "@opencode-ai/sdk/v2"; -const PROVIDER = ProviderDriverKind.make("opencode"); const OPENCODE_PRESENTATION = { displayName: "OpenCode", showInteractionModeToggle: false, @@ -259,7 +257,6 @@ export const makePendingOpenCodeProvider = ( const checkedAt = yield* Effect.map(DateTime.now, DateTime.formatIso); const models = providerModelsFromSettings( [], - PROVIDER, openCodeSettings.customModels, DEFAULT_OPENCODE_MODEL_CAPABILITIES, ); @@ -319,12 +316,7 @@ export const checkOpenCodeProviderStatus = Effect.fn("checkOpenCodeProviderStatu presentation: OPENCODE_PRESENTATION, enabled: openCodeSettings.enabled, checkedAt, - models: providerModelsFromSettings( - [], - PROVIDER, - customModels, - DEFAULT_OPENCODE_MODEL_CAPABILITIES, - ), + models: providerModelsFromSettings([], customModels, DEFAULT_OPENCODE_MODEL_CAPABILITIES), probe: { installed: failure.installed, version, @@ -340,12 +332,7 @@ export const checkOpenCodeProviderStatus = Effect.fn("checkOpenCodeProviderStatu presentation: OPENCODE_PRESENTATION, enabled: false, checkedAt, - models: providerModelsFromSettings( - [], - PROVIDER, - customModels, - DEFAULT_OPENCODE_MODEL_CAPABILITIES, - ), + models: providerModelsFromSettings([], customModels, DEFAULT_OPENCODE_MODEL_CAPABILITIES), probe: { installed: false, version: null, @@ -391,12 +378,7 @@ export const checkOpenCodeProviderStatus = Effect.fn("checkOpenCodeProviderStatu presentation: OPENCODE_PRESENTATION, enabled: openCodeSettings.enabled, checkedAt, - models: providerModelsFromSettings( - [], - PROVIDER, - customModels, - DEFAULT_OPENCODE_MODEL_CAPABILITIES, - ), + models: providerModelsFromSettings([], customModels, DEFAULT_OPENCODE_MODEL_CAPABILITIES), probe: { installed: true, version, @@ -409,26 +391,32 @@ export const checkOpenCodeProviderStatus = Effect.fn("checkOpenCodeProviderStatu } const inventoryExit = yield* Effect.exit( - Effect.scoped( - Effect.gen(function* () { - const server = yield* openCodeRuntime.connectToOpenCodeServer({ + (isExternalServer + ? Effect.scoped( + Effect.gen(function* () { + const server = yield* openCodeRuntime.connectToOpenCodeServer({ + binaryPath: openCodeSettings.binaryPath, + serverUrl: openCodeSettings.serverUrl, + environment: resolvedEnvironment, + }); + return yield* openCodeRuntime.loadOpenCodeInventory( + openCodeRuntime.createOpenCodeSdkClient({ + baseUrl: server.url, + directory: cwd, + ...(openCodeSettings.serverPassword + ? { serverPassword: openCodeSettings.serverPassword } + : {}), + }), + ); + }), + ) + : openCodeRuntime.loadInventoryFromCli({ binaryPath: openCodeSettings.binaryPath, - serverUrl: openCodeSettings.serverUrl, environment: resolvedEnvironment, - }); - return yield* openCodeRuntime.loadOpenCodeInventory( - openCodeRuntime.createOpenCodeSdkClient({ - baseUrl: server.url, - directory: cwd, - ...(isExternalServer && openCodeSettings.serverPassword - ? { serverPassword: openCodeSettings.serverPassword } - : {}), - }), - ); - }).pipe( - Effect.mapError( - (cause) => new OpenCodeProbeError({ cause, detail: openCodeRuntimeErrorDetail(cause) }), - ), + }) + ).pipe( + Effect.mapError( + (cause) => new OpenCodeProbeError({ cause, detail: openCodeRuntimeErrorDetail(cause) }), ), ), ); @@ -438,7 +426,6 @@ export const checkOpenCodeProviderStatus = Effect.fn("checkOpenCodeProviderStatu const models = providerModelsFromSettings( flattenOpenCodeModels(inventoryExit.value), - PROVIDER, customModels, DEFAULT_OPENCODE_MODEL_CAPABILITIES, ); diff --git a/apps/server/src/provider/Layers/ProviderInstanceRegistryLive.test.ts b/apps/server/src/provider/Layers/ProviderInstanceRegistryLive.test.ts index 547e7bd92c57..ba39ec04a7f2 100644 --- a/apps/server/src/provider/Layers/ProviderInstanceRegistryLive.test.ts +++ b/apps/server/src/provider/Layers/ProviderInstanceRegistryLive.test.ts @@ -61,6 +61,7 @@ const makeCodexConfig = (overrides: Partial): CodexSettings => ({ binaryPath: "codex", homePath: "", shadowHomePath: "", + launchArgs: "", customModels: [], ...overrides, }); diff --git a/apps/server/src/provider/Layers/ProviderRegistry.test.ts b/apps/server/src/provider/Layers/ProviderRegistry.test.ts index 886eff5ef1b8..259eb794e7d1 100644 --- a/apps/server/src/provider/Layers/ProviderRegistry.test.ts +++ b/apps/server/src/provider/Layers/ProviderRegistry.test.ts @@ -60,6 +60,7 @@ const encodedDefaultServerSettings = encodeServerSettings(DEFAULT_SERVER_SETTING const defaultClaudeSettings: ClaudeSettings = Schema.decodeSync(ClaudeSettings)({}); const defaultCodexSettings: CodexSettings = Schema.decodeSync(CodexSettings)({}); +const decodeCodexSettings = Schema.decodeSync(CodexSettings); const disabledCodexSettings: CodexSettings = Schema.decodeSync(CodexSettings)({ enabled: false, }); @@ -105,6 +106,7 @@ type TestClaudeCapabilities = { readonly email: string | undefined; readonly subscriptionType: string | undefined; readonly tokenSource: string | undefined; + readonly apiProvider: string | undefined; readonly slashCommands: ReadonlyArray; }; @@ -114,6 +116,7 @@ function claudeCapabilities(overrides: Partial = {}) { email: undefined, subscriptionType: undefined, tokenSource: undefined, + apiProvider: undefined, slashCommands: [], ...overrides, }); @@ -351,6 +354,21 @@ it.layer(Layer.mergeAll(NodeServices.layer, ServerSettingsModule.layerTest(), Te }), ); + it.effect("passes configured launch args to the Codex provider probe", () => + Effect.gen(function* () { + let observedLaunchArgs: string | undefined; + const settings = decodeCodexSettings({ launchArgs: "--strict-config --enable foo" }); + + const status = yield* checkCodexProviderStatus(settings, (input) => { + observedLaunchArgs = input.launchArgs; + return Effect.succeed(makeCodexProbeSnapshot()); + }); + + assert.strictEqual(status.status, "ready"); + assert.strictEqual(observedLaunchArgs, "--strict-config --enable foo"); + }), + ); + it.effect("returns unauthenticated when app-server requires OpenAI auth", () => Effect.gen(function* () { const status = yield* checkCodexProviderStatus(defaultCodexSettings, () => @@ -1523,6 +1541,30 @@ it.layer(Layer.mergeAll(NodeServices.layer, ServerSettingsModule.layerTest(), Te ), ); + it.effect("returns ready and labels Bedrock-backed Claude as authenticated", () => + Effect.gen(function* () { + // Bedrock authenticates via external AWS credentials, so the SDK init + // reports only `apiProvider` with no subscription or token. + const status = yield* checkClaudeProviderStatus( + defaultClaudeSettings, + claudeCapabilities({ apiProvider: "bedrock" }), + ); + assert.strictEqual(status.status, "ready"); + assert.strictEqual(status.installed, true); + assert.strictEqual(status.auth.status, "authenticated"); + assert.strictEqual(status.auth.type, "bedrock"); + assert.strictEqual(status.auth.label, "Amazon Bedrock"); + }).pipe( + Effect.provide( + mockSpawnerLayer((args) => { + const joined = args.join(" "); + if (joined === "--version") return { stdout: "1.0.0\n", stderr: "", code: 0 }; + throw new Error(`Unexpected args: ${joined}`); + }), + ), + ), + ); + it.effect("includes Claude Fable 5 on supported Claude Code versions", () => Effect.gen(function* () { const status = yield* checkClaudeProviderStatus( diff --git a/apps/server/src/provider/Layers/codexLaunchArgs.test.ts b/apps/server/src/provider/Layers/codexLaunchArgs.test.ts new file mode 100644 index 000000000000..115ac28eaf94 --- /dev/null +++ b/apps/server/src/provider/Layers/codexLaunchArgs.test.ts @@ -0,0 +1,59 @@ +import * as NodeAssert from "node:assert/strict"; + +import { describe, it } from "vite-plus/test"; + +import { + codexAppServerArgs, + codexExecLaunchArgs, + resolveCodexLaunchArgs, +} from "./codexLaunchArgs.ts"; + +describe("resolveCodexLaunchArgs", () => { + it("uses T3CODE_CODEX_LAUNCH_ARGS before configured settings", () => { + NodeAssert.equal( + resolveCodexLaunchArgs(" --strict-config ", { T3CODE_CODEX_LAUNCH_ARGS: "--enable foo" }), + "--enable foo", + ); + }); + + it("uses configured settings when T3CODE_CODEX_LAUNCH_ARGS is empty", () => { + NodeAssert.equal( + resolveCodexLaunchArgs(" --strict-config ", { T3CODE_CODEX_LAUNCH_ARGS: " " }), + "--strict-config", + ); + }); + + it("ignores whitespace-only environment values", () => { + NodeAssert.equal(resolveCodexLaunchArgs("", { T3CODE_CODEX_LAUNCH_ARGS: " " }), ""); + }); +}); + +describe("codexAppServerArgs", () => { + it("returns the app-server command for empty launch args", () => { + NodeAssert.deepStrictEqual(codexAppServerArgs(""), ["app-server"]); + }); + + it("appends parsed launch args after app-server", () => { + NodeAssert.deepStrictEqual(codexAppServerArgs("--strict-config --enable foo"), [ + "app-server", + "--strict-config", + "--enable", + "foo", + ]); + }); +}); + +describe("codexExecLaunchArgs", () => { + it("keeps shared codex flags and omits app-server-only flags", () => { + NodeAssert.deepStrictEqual( + codexExecLaunchArgs('--strict-config --enable foo --listen off --config model="gpt 5"'), + ["--strict-config", "--enable", "foo", "--config", "model=gpt 5"], + ); + }); + + it("does not pair value-taking flags with adjacent flags", () => { + NodeAssert.deepStrictEqual(codexExecLaunchArgs("--config --strict-config --enable --disable"), [ + "--strict-config", + ]); + }); +}); diff --git a/apps/server/src/provider/Layers/codexLaunchArgs.ts b/apps/server/src/provider/Layers/codexLaunchArgs.ts new file mode 100644 index 000000000000..771a4f0b6ed6 --- /dev/null +++ b/apps/server/src/provider/Layers/codexLaunchArgs.ts @@ -0,0 +1,48 @@ +import { tokenizeCliArgs } from "@t3tools/shared/cliArgs"; + +export const T3CODE_CODEX_LAUNCH_ARGS_ENV = "T3CODE_CODEX_LAUNCH_ARGS"; + +export const resolveCodexLaunchArgs = ( + launchArgs?: string, + environment: NodeJS.ProcessEnv = process.env, +) => environment[T3CODE_CODEX_LAUNCH_ARGS_ENV]?.trim() || launchArgs?.trim() || ""; + +export const codexLaunchArgv = (launchArgs?: string): ReadonlyArray => + tokenizeCliArgs(launchArgs); + +export const codexAppServerArgs = (launchArgs?: string) => [ + "app-server", + ...codexLaunchArgv(launchArgs), +]; + +export const codexExecLaunchArgs = (launchArgs?: string) => { + const args = codexLaunchArgv(launchArgs); + const execArgs: Array = []; + + for (let index = 0; index < args.length; index++) { + const arg = args[index]; + if (arg === undefined) continue; + + if (arg === "--strict-config" || arg.startsWith("--config=") || arg.startsWith("-c=")) { + execArgs.push(arg); + } else if (arg === "--config" || arg === "-c" || arg === "--enable" || arg === "--disable") { + const value = args[index + 1]; + if (value !== undefined && !value.startsWith("-")) { + execArgs.push(arg, value); + index++; + } + } else if (arg.startsWith("--enable=") || arg.startsWith("--disable=")) { + execArgs.push(arg); + } + } + + return execArgs; +}; + +export const codexSessionAppServerArgs = ( + appServerArgs: ReadonlyArray | undefined, + launchArgs: string | undefined, +) => { + const launchAppServerArgs = codexAppServerArgs(launchArgs); + return appServerArgs ? [...launchAppServerArgs, ...appServerArgs] : launchAppServerArgs; +}; diff --git a/apps/server/src/provider/cursor/CursorSdkMappings.ts b/apps/server/src/provider/cursor/CursorSdkMappings.ts index 6a8994c7e282..aa925407f3c3 100644 --- a/apps/server/src/provider/cursor/CursorSdkMappings.ts +++ b/apps/server/src/provider/cursor/CursorSdkMappings.ts @@ -263,12 +263,7 @@ export function buildCursorDiscoveredModelsFromSdkModels( }); const builtInModels = discovered.length > 0 ? discovered : CURSOR_FALLBACK_MODELS; - return providerModelsFromSettings( - builtInModels, - PROVIDER, - customModels, - EMPTY_CURSOR_CAPABILITIES, - ); + return providerModelsFromSettings(builtInModels, customModels, EMPTY_CURSOR_CAPABILITIES); } export function toCursorToolItemType(toolName: string): ToolLifecycleItemType { diff --git a/apps/server/src/provider/opencodeRuntime.cliParsers.test.ts b/apps/server/src/provider/opencodeRuntime.cliParsers.test.ts new file mode 100644 index 000000000000..6208f04507e7 --- /dev/null +++ b/apps/server/src/provider/opencodeRuntime.cliParsers.test.ts @@ -0,0 +1,229 @@ +import * as NodeAssert from "node:assert/strict"; + +import { describe, it } from "vite-plus/test"; + +import { parseModelsCliOutput, parseAgentListCliOutput } from "./opencodeRuntime.ts"; + +describe("parseModelsCliOutput", () => { + it("parses a single model from a single provider", () => { + const stdout = [ + "anthropic/claude-sonnet-4-5", + JSON.stringify({ + id: "claude-sonnet-4-5", + providerID: "anthropic", + name: "Claude Sonnet 4.5", + capabilities: { temperature: true, reasoning: true, toolcall: true }, + cost: { input: 3, output: 15 }, + limit: { context: 200000, output: 8192 }, + status: "active", + options: {}, + headers: {}, + release_date: "2025-01-01", + }), + ].join("\n"); + + const result = parseModelsCliOutput(stdout); + NodeAssert.equal(result.providers.size, 1); + NodeAssert.equal(result.connected.length, 1); + NodeAssert.equal(result.connected[0], "anthropic"); + + const provider = result.providers.get("anthropic")!; + NodeAssert.ok(provider); + NodeAssert.equal(provider.id, "anthropic"); + NodeAssert.equal(provider.name, "anthropic"); + NodeAssert.equal(Object.keys(provider.models).length, 1); + + const model = provider.models["claude-sonnet-4-5"]!; + NodeAssert.ok(model); + NodeAssert.equal(model.id, "claude-sonnet-4-5"); + NodeAssert.equal(model.providerID, "anthropic"); + NodeAssert.equal(model.name, "Claude Sonnet 4.5"); + }); + + it("parses multiple models from multiple providers", () => { + const stdout = [ + "anthropic/claude-sonnet-4-5", + JSON.stringify({ id: "claude-sonnet-4-5", providerID: "anthropic", name: "Sonnet 4.5" }), + "anthropic/claude-haiku-4-5", + JSON.stringify({ id: "claude-haiku-4-5", providerID: "anthropic", name: "Haiku 4.5" }), + "openai/gpt-4o", + JSON.stringify({ id: "gpt-4o", providerID: "openai", name: "GPT-4o" }), + ].join("\n"); + + const result = parseModelsCliOutput(stdout); + NodeAssert.equal(result.providers.size, 2); + NodeAssert.equal(result.connected.length, 2); + NodeAssert.equal([...result.connected].sort().join(","), "anthropic,openai"); + NodeAssert.equal(Object.keys(result.providers.get("anthropic")!.models).length, 2); + NodeAssert.equal(Object.keys(result.providers.get("openai")!.models).length, 1); + }); + + it("handles empty input", () => { + const result = parseModelsCliOutput(""); + NodeAssert.equal(result.providers.size, 0); + NodeAssert.equal(result.connected.length, 0); + }); + + it("skips unparseable JSON blocks", () => { + const stdout = [ + "anthropic/claude-sonnet-4-5", + "this is not valid json {{{", + "anthropic/claude-haiku-4-5", + JSON.stringify({ id: "claude-haiku-4-5", providerID: "anthropic", name: "Haiku 4.5" }), + ].join("\n"); + + const result = parseModelsCliOutput(stdout); + NodeAssert.equal(result.providers.size, 1); + const provider = result.providers.get("anthropic")!; + NodeAssert.equal(Object.keys(provider.models).length, 1); + NodeAssert.ok(provider.models["claude-haiku-4-5"]); + }); + + it("handles Windows-style CRLF line endings", () => { + const stdout = + "anthropic/claude-sonnet-4-5\r\n" + + JSON.stringify({ id: "claude-sonnet-4-5", providerID: "anthropic", name: "Sonnet" }) + + "\r\n"; + + const result = parseModelsCliOutput(stdout); + NodeAssert.equal(result.providers.size, 1); + NodeAssert.ok(result.providers.get("anthropic")!.models["claude-sonnet-4-5"]); + }); + + it("handles model JSON with variants and nested fields", () => { + const stdout = [ + "opencode/gpt-5.4", + JSON.stringify({ + id: "gpt-5.4", + providerID: "opencode", + name: "GPT-5.4", + family: "gpt", + capabilities: { + temperature: true, + reasoning: true, + attachment: false, + toolcall: true, + input: { text: true, audio: false, image: false, video: false, pdf: false }, + output: { text: true, audio: false, image: false, video: false, pdf: false }, + interleaved: false, + }, + cost: { input: 0, output: 0, cache: { read: 0, write: 0 } }, + limit: { context: 200000, input: 160000, output: 32000 }, + status: "active", + options: {}, + headers: {}, + release_date: "2025-01-01", + variants: { none: {}, low: {}, medium: {}, high: {} }, + }), + ].join("\n"); + + const result = parseModelsCliOutput(stdout); + const model = result.providers.get("opencode")!.models["gpt-5.4"]!; + NodeAssert.ok(model); + NodeAssert.ok(model.capabilities); + NodeAssert.equal(model.capabilities!.reasoning, true); + NodeAssert.ok(model.variants); + NodeAssert.equal(model.variants!["medium"] !== undefined, true); + }); +}); + +describe("parseAgentListCliOutput", () => { + it("parses a single agent", () => { + const stdout = [ + "build (primary)", + " " + JSON.stringify([{ permission: "*", action: "allow", pattern: "*" }]), + ].join("\n"); + + const result = parseAgentListCliOutput(stdout); + NodeAssert.equal(result.length, 1); + NodeAssert.equal(result[0]!.name, "build"); + NodeAssert.equal(result[0]!.mode, "primary"); + NodeAssert.equal(result[0]!.permission.length, 1); + }); + + it("parses multiple agents", () => { + const stdout = [ + "build (primary)", + " " + JSON.stringify([{ permission: "*", action: "allow", pattern: "*" }]), + "explore (subagent)", + " " + JSON.stringify([{ permission: "read", action: "allow", pattern: "*" }]), + "plan (primary)", + " " + JSON.stringify([{ permission: "edit", action: "ask", pattern: "*.md" }]), + ].join("\n"); + + const result = parseAgentListCliOutput(stdout); + NodeAssert.equal(result.length, 3); + NodeAssert.equal(result[0]!.name, "build"); + NodeAssert.equal(result[0]!.mode, "primary"); + NodeAssert.equal(result[1]!.name, "explore"); + NodeAssert.equal(result[1]!.mode, "subagent"); + NodeAssert.equal(result[2]!.name, "plan"); + NodeAssert.equal(result[2]!.mode, "primary"); + }); + + it("handles empty input", () => { + const result = parseAgentListCliOutput(""); + NodeAssert.equal(result.length, 0); + }); + + it("skips agents with unparseable permission JSON", () => { + const stdout = [ + "build (primary)", + " not valid json {", + "explore (subagent)", + " " + JSON.stringify([{ permission: "read", action: "allow", pattern: "*" }]), + ].join("\n"); + + const result = parseAgentListCliOutput(stdout); + NodeAssert.equal(result.length, 1); + NodeAssert.equal(result[0]!.name, "explore"); + }); + + it("handles real-world permission blocks with nested paths", () => { + const permissions = [ + { permission: "*", action: "allow", pattern: "*" }, + { + permission: "external_directory", + pattern: "C:\\Users\\test\\.local\\*", + action: "allow", + }, + { permission: "read", pattern: "*.env", action: "ask" }, + ]; + const stdout = ["build (primary)", " " + JSON.stringify(permissions)].join("\n"); + + const result = parseAgentListCliOutput(stdout); + NodeAssert.equal(result.length, 1); + NodeAssert.equal(result[0]!.permission.length, 3); + NodeAssert.equal(result[0]!.permission[0]!.action, "allow"); + NodeAssert.equal(result[0]!.permission[2]!.action, "ask"); + }); + + it("handles agent names with spaces", () => { + const stdout = [ + "code reviewer (subagent)", + " " + JSON.stringify([{ permission: "read", action: "allow", pattern: "*" }]), + "my custom agent (primary)", + " " + JSON.stringify([{ permission: "edit", action: "ask", pattern: "*.ts" }]), + ].join("\n"); + + const result = parseAgentListCliOutput(stdout); + NodeAssert.equal(result.length, 2); + NodeAssert.equal(result[0]!.name, "code reviewer"); + NodeAssert.equal(result[0]!.mode, "subagent"); + NodeAssert.equal(result[1]!.name, "my custom agent"); + NodeAssert.equal(result[1]!.mode, "primary"); + }); + + it("marks known hidden agents", () => { + const stdout = [ + "compaction (primary)", + " " + JSON.stringify([{ permission: "*", action: "allow", pattern: "*" }]), + "build (primary)", + " " + JSON.stringify([{ permission: "*", action: "allow", pattern: "*" }]), + ].join("\n"); + + const result = parseAgentListCliOutput(stdout); + NodeAssert.equal(result[0]!.hidden, true); + NodeAssert.equal(result[1]!.hidden, false); + }); +}); diff --git a/apps/server/src/provider/opencodeRuntime.ts b/apps/server/src/provider/opencodeRuntime.ts index 46d0b3019bd6..b853662b037d 100644 --- a/apps/server/src/provider/opencodeRuntime.ts +++ b/apps/server/src/provider/opencodeRuntime.ts @@ -5,6 +5,7 @@ import { createOpencodeClient, type Agent, type FilePartInput, + type Model, type OpencodeClient, type PermissionRuleset, type ProviderListResponse, @@ -147,6 +148,10 @@ export interface OpenCodeRuntimeShape { readonly loadOpenCodeInventory: ( client: OpencodeClient, ) => Effect.Effect; + readonly loadInventoryFromCli: (input: { + readonly binaryPath: string; + readonly environment?: NodeJS.ProcessEnv; + }) => Effect.Effect; } function parseServerUrlFromOutput(output: string): string | null { @@ -160,6 +165,113 @@ function parseServerUrlFromOutput(output: string): string | null { return null; } +const SLUG_LINE_RE = /^(\S+\/\S+)\s*$/; +const AGENT_HEADER_RE = /^(.+)\s+\((\S+)\)\s*$/; + +// Agents that are always hidden in OpenCode but the CLI "agent list" command +// does not expose the hidden flag. Keep in sync with OpenCode agent +// definitions (in the OpenCode repo: packages/opencode/src/agent/agent.ts). +const KNOWN_HIDDEN_AGENTS = new Set(["compaction", "summary", "title"]); + +/** @internal */ +export function parseModelsCliOutput(stdout: string): { + readonly providers: ReadonlyMap< + string, + { readonly id: string; readonly name: string; readonly models: { [key: string]: Model } } + >; + readonly connected: ReadonlyArray; +} { + const providers = new Map< + string, + { id: string; name: string; models: { [key: string]: Model } } + >(); + const lines = stdout.split("\n"); + let currentSlug: string | null = null; + const jsonLines: Array = []; + + const flushModel = () => { + if (currentSlug !== null && jsonLines.length > 0) { + const jsonStr = jsonLines.join("\n").trim(); + if (jsonStr.length > 0) { + try { + const model = JSON.parse(jsonStr) as Model; + const separator = currentSlug.indexOf("/"); + if (separator > 0) { + const providerID = currentSlug.slice(0, separator); + const modelID = currentSlug.slice(separator + 1); + let provider = providers.get(providerID); + if (!provider) { + provider = { id: providerID, name: providerID, models: {} }; + providers.set(providerID, provider); + } + provider.models[modelID] = model; + } + } catch { + // Skip unparseable model JSON + } + } + } + currentSlug = null; + jsonLines.length = 0; + }; + + for (const line of lines) { + const slugMatch = SLUG_LINE_RE.exec(line); + if (slugMatch) { + flushModel(); + currentSlug = slugMatch[1]!; + } else if (currentSlug !== null) { + jsonLines.push(line); + } + } + flushModel(); + + return { providers, connected: [...providers.keys()] }; +} + +/** @internal */ +export function parseAgentListCliOutput(stdout: string): ReadonlyArray { + const agents: Array = []; + const lines = stdout.split("\n"); + let currentHeader: { name: string; mode: string } | null = null; + const blockLines: Array = []; + + const flushAgent = () => { + if (currentHeader !== null) { + const jsonStr = blockLines.join("\n").trim(); + if (jsonStr.length > 0) { + try { + const permission = JSON.parse(jsonStr); + agents.push({ + name: currentHeader.name, + mode: currentHeader.mode as Agent["mode"], + hidden: KNOWN_HIDDEN_AGENTS.has(currentHeader.name), + permission, + options: {}, + }); + } catch { + // Skip unparseable agent + } + } + } + currentHeader = null; + blockLines.length = 0; + }; + + for (const line of lines) { + const match = AGENT_HEADER_RE.exec(line); + if (match) { + flushAgent(); + currentHeader = { name: match[1]!, mode: match[2]! }; + } else if (currentHeader !== null) { + blockLines.push(line); + } + } + flushAgent(); + + return agents; +} + export function parseOpenCodeModelSlug( slug: string | null | undefined, ): ParsedOpenCodeModelSlug | null { @@ -542,12 +654,76 @@ const makeOpenCodeRuntime = Effect.gen(function* () { Effect.map(([providerList, agents]) => ({ providerList, agents })), ); + const loadInventoryFromCli: OpenCodeRuntimeShape["loadInventoryFromCli"] = (input) => + Effect.gen(function* () { + const env = input.environment !== undefined ? { environment: input.environment } : ({} as {}); + + const runModelsCli = () => + runOpenCodeCommand({ + binaryPath: input.binaryPath, + args: ["models", "--verbose"], + ...env, + }).pipe(Effect.exit); + const runAgentsCli = () => + runOpenCodeCommand({ binaryPath: input.binaryPath, args: ["agent", "list"], ...env }).pipe( + Effect.exit, + ); + + // First attempt — run both in parallel + let [modelsResult, agentsResult] = yield* Effect.all([runModelsCli(), runAgentsCli()], { + concurrency: "unbounded", + }); + + // Retry once after 1s on transient failures (e.g. SQLite "database is locked") + const needsModelsRetry = modelsResult._tag === "Failure" || modelsResult.value.code !== 0; + const needsAgentsRetry = agentsResult._tag === "Failure" || agentsResult.value.code !== 0; + if (needsModelsRetry || needsAgentsRetry) { + yield* Effect.sleep("1 second"); + const [m2, a2] = yield* Effect.all( + [ + needsModelsRetry ? runModelsCli() : Effect.succeed(modelsResult), + needsAgentsRetry ? runAgentsCli() : Effect.succeed(agentsResult), + ], + { concurrency: "unbounded" }, + ); + modelsResult = m2; + agentsResult = a2; + } + + // Degrade gracefully on failure — return empty inventory (warning status, not error) + let connected: string[] = []; + let allProviders: ProviderListResponse["all"] = []; + if (modelsResult._tag === "Success" && modelsResult.value.code === 0) { + const parsed = parseModelsCliOutput(modelsResult.value.stdout); + connected = [...parsed.connected]; + allProviders = [...parsed.providers.values()].map((p) => ({ + id: p.id, + name: p.name, + source: "config" as const, + env: [], + options: {}, + models: p.models, + })); + } + + let agents: ReadonlyArray = []; + if (agentsResult._tag === "Success" && agentsResult.value.code === 0) { + agents = parseAgentListCliOutput(agentsResult.value.stdout); + } + + return { + providerList: { all: allProviders, default: {}, connected }, + agents, + }; + }); + return { startOpenCodeServerProcess, connectToOpenCodeServer, runOpenCodeCommand, createOpenCodeSdkClient, loadOpenCodeInventory, + loadInventoryFromCli, } satisfies OpenCodeRuntimeShape; }); diff --git a/apps/server/src/provider/providerSnapshot.test.ts b/apps/server/src/provider/providerSnapshot.test.ts index abe138fdfb94..011572780666 100644 --- a/apps/server/src/provider/providerSnapshot.test.ts +++ b/apps/server/src/provider/providerSnapshot.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "@effect/vitest"; -import { ProviderDriverKind, type ModelCapabilities } from "@t3tools/contracts"; +import type { ModelCapabilities } from "@t3tools/contracts"; import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; import { createModelCapabilities } from "@t3tools/shared/model"; import * as Effect from "effect/Effect"; @@ -38,7 +38,6 @@ describe("providerModelsFromSettings", () => { it("applies the provided capabilities to custom models", () => { const models = providerModelsFromSettings( [], - ProviderDriverKind.make("opencode"), ["openai/gpt-5"], OPENCODE_CUSTOM_MODEL_CAPABILITIES, ); @@ -52,6 +51,25 @@ describe("providerModelsFromSettings", () => { }, ]); }); + + it("preserves a custom slug that collides with a provider alias", () => { + const capabilities = createModelCapabilities({ optionDescriptors: [] }); + const models = providerModelsFromSettings( + [ + { + slug: "claude-opus-4-8", + name: "Claude Opus 4.8", + isCustom: false, + capabilities, + }, + ], + [" opus "], + capabilities, + ); + + expect(models.map((model) => model.slug)).toEqual(["claude-opus-4-8", "opus"]); + expect(models[1]?.isCustom).toBe(true); + }); }); describe("ProviderCommandNotFoundError", () => { diff --git a/apps/server/src/provider/providerSnapshot.ts b/apps/server/src/provider/providerSnapshot.ts index dfe31ffdc442..e741a7a2c1d0 100644 --- a/apps/server/src/provider/providerSnapshot.ts +++ b/apps/server/src/provider/providerSnapshot.ts @@ -13,7 +13,7 @@ import * as PlatformError from "effect/PlatformError"; import * as Schema from "effect/Schema"; import * as Stream from "effect/Stream"; import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"; -import { normalizeModelSlug } from "@t3tools/shared/model"; +import { normalizeCustomModelSlug } from "@t3tools/shared/model"; import { isWindowsCommandNotFound } from "../processRunner.ts"; import { createProviderVersionAdvisory } from "./providerMaintenance.ts"; import { collectUint8StreamText } from "../stream/collectUint8StreamText.ts"; @@ -140,7 +140,6 @@ export function parseGenericCliVersion(output: string): string | null { export function providerModelsFromSettings( builtInModels: ReadonlyArray, - provider: ProviderDriverKind, customModels: ReadonlyArray, customModelCapabilities: ModelCapabilities, ): ReadonlyArray { @@ -149,7 +148,7 @@ export function providerModelsFromSettings( const customEntries: ServerProviderModel[] = []; for (const candidate of customModels) { - const normalized = normalizeModelSlug(candidate, provider); + const normalized = normalizeCustomModelSlug(candidate); if (!normalized || seen.has(normalized)) { continue; } diff --git a/apps/server/src/server.test.ts b/apps/server/src/server.test.ts index 99af8cbfd649..02527a2ae203 100644 --- a/apps/server/src/server.test.ts +++ b/apps/server/src/server.test.ts @@ -3720,6 +3720,8 @@ it.layer(NodeServices.layer)("server router seam", (it) => { assert.equal(response.environment.environmentId, testEnvironmentDescriptor.environmentId); assert.equal(response.auth.policy, "desktop-managed-local"); + assert.equal(response.shellResumeCompletionMarker, true); + assert.equal(response.threadResumeCompletionMarker, true); }).pipe(Effect.provide(NodeHttpServer.layerTest)), ); @@ -5610,6 +5612,114 @@ it.layer(NodeServices.layer)("server router seam", (it) => { }).pipe(Effect.provide(NodeHttpServer.layerTest)), ); + it.effect("marks an empty shell catch-up replay as synchronized when requested", () => + Effect.gen(function* () { + yield* buildAppUnderTest({ + layers: { + orchestrationEngine: { + readEvents: () => Stream.empty, + }, + }, + }); + + const wsUrl = yield* getWsServerUrl("/ws"); + const firstItem = yield* Effect.scoped( + withWsRpcClient(wsUrl, (client) => + client[ORCHESTRATION_WS_METHODS.subscribeShell]({ + afterSequence: 0, + requestCompletionMarker: true, + }).pipe(Stream.runHead), + ), + ); + + assert.deepEqual(Option.getOrThrow(firstItem), { kind: "synchronized" }); + }).pipe(Effect.provide(NodeHttpServer.layerTest)), + ); + + it.effect("marks a socket thread snapshot as synchronized when requested", () => + Effect.gen(function* () { + const thread = makeDefaultOrchestrationReadModel().threads[0]!; + yield* buildAppUnderTest({ + layers: { + projectionSnapshotQuery: { + getThreadDetailSnapshot: () => + Effect.succeed(Option.some({ snapshotSequence: 1, thread })), + }, + }, + }); + + const wsUrl = yield* getWsServerUrl("/ws"); + const items = yield* Effect.scoped( + withWsRpcClient(wsUrl, (client) => + client[ORCHESTRATION_WS_METHODS.subscribeThread]({ + threadId: defaultThreadId, + requestCompletionMarker: true, + }).pipe(Stream.take(2), Stream.runCollect), + ), + ); + + assert.equal(items[0]?.kind, "snapshot"); + assert.deepEqual(items[1], { kind: "synchronized" }); + }).pipe(Effect.provide(NodeHttpServer.layerTest)), + ); + + it.effect("buffers shell events published while the fallback snapshot loads", () => + Effect.gen(function* () { + const liveEvents = yield* PubSub.unbounded(); + const deletedEvent = { + sequence: 2, + eventId: EventId.make("event-shell-thread-deleted"), + aggregateKind: "thread", + aggregateId: defaultThreadId, + occurredAt: "2026-01-01T00:00:01.000Z", + commandId: null, + causationEventId: null, + correlationId: null, + metadata: {}, + type: "thread.deleted", + payload: { + threadId: defaultThreadId, + deletedAt: "2026-01-01T00:00:01.000Z", + }, + } satisfies Extract; + + yield* buildAppUnderTest({ + layers: { + orchestrationEngine: { + streamDomainEvents: Stream.fromPubSub(liveEvents), + subscribeDomainEvents: PubSub.subscribe(liveEvents), + }, + projectionSnapshotQuery: { + getShellSnapshot: () => + Effect.gen(function* () { + yield* Effect.sleep("25 millis"); + yield* PubSub.publish(liveEvents, deletedEvent); + return { + snapshotSequence: 1, + projects: [], + threads: [makeDefaultOrchestrationThreadShell()], + updatedAt: "2026-01-01T00:00:00.000Z", + }; + }), + }, + }, + }); + + const wsUrl = yield* getWsServerUrl("/ws"); + const items = yield* Effect.scoped( + withWsRpcClient(wsUrl, (client) => + client[ORCHESTRATION_WS_METHODS.subscribeShell]({ + requestCompletionMarker: true, + }).pipe(Stream.take(3), Stream.runCollect), + ), + ).pipe(Effect.timeout("2 seconds")); + + assert.equal(items[0]?.kind, "snapshot"); + assert.equal(items[1]?.kind, "thread-removed"); + assert.deepEqual(items[2], { kind: "synchronized" }); + }).pipe(Effect.provide(NodeHttpServer.layerTest), TestClock.withLive), + ); + it.effect("buffers thread events published while the initial snapshot loads", () => Effect.gen(function* () { const thread = makeDefaultOrchestrationReadModel().threads[0]!; diff --git a/apps/server/src/serverSettings.test.ts b/apps/server/src/serverSettings.test.ts index 504d99e18def..487ae9b45b8a 100644 --- a/apps/server/src/serverSettings.test.ts +++ b/apps/server/src/serverSettings.test.ts @@ -179,6 +179,7 @@ it.layer(NodeServices.layer)("server settings", (it) => { binaryPath: "/opt/homebrew/bin/codex", homePath: "/Users/julius/.codex", shadowHomePath: "", + launchArgs: "", customModels: [], }); assert.deepEqual(next.providers.claudeAgent, { @@ -420,6 +421,7 @@ it.layer(NodeServices.layer)("server settings", (it) => { binaryPath: "/opt/homebrew/bin/codex", homePath: "", shadowHomePath: "", + launchArgs: "", customModels: [], }); assert.deepEqual(next.providers.claudeAgent, { diff --git a/apps/server/src/textGeneration/CodexTextGeneration.test.ts b/apps/server/src/textGeneration/CodexTextGeneration.test.ts index 24054a958701..657118fff51c 100644 --- a/apps/server/src/textGeneration/CodexTextGeneration.test.ts +++ b/apps/server/src/textGeneration/CodexTextGeneration.test.ts @@ -35,6 +35,8 @@ function makeFakeCodexBinary( requireServiceTier?: string; requireReasoningEffort?: string; forbidReasoningEffort?: boolean; + requireArg?: string; + forbidArg?: string; stdinMustContain?: string; stdinMustNotContain?: string; }, @@ -50,6 +52,7 @@ function makeFakeCodexBinary( codexPath, [ "#!/bin/sh", + 'original_args="$*"', 'output_path=""', 'seen_image="0"', 'seen_service_tier=""', @@ -87,6 +90,22 @@ function makeFakeCodexBinary( " shift", "done", 'stdin_content="$(cat)"', + ...(input.requireArg !== undefined + ? [ + `case " $original_args " in *" ${input.requireArg} "*) ;; *)`, + ` printf "%s\\n" "missing arg: ${input.requireArg}" >&2`, + ` exit 8`, + "esac", + ] + : []), + ...(input.forbidArg !== undefined + ? [ + `case " $original_args " in *" ${input.forbidArg} "*)`, + ` printf "%s\\n" "forbidden arg: ${input.forbidArg}" >&2`, + ` exit 9`, + "esac", + ] + : []), ...(input.requireImage ? [ 'if [ "$seen_image" != "1" ]; then', @@ -166,8 +185,12 @@ function withFakeCodexEnv( requireServiceTier?: string; requireReasoningEffort?: string; forbidReasoningEffort?: boolean; + requireArg?: string; + forbidArg?: string; stdinMustContain?: string; stdinMustNotContain?: string; + launchArgs?: string; + environment?: NodeJS.ProcessEnv; }, effectFn: (textGeneration: TextGeneration.TextGeneration["Service"]) => Effect.Effect, ) { @@ -175,8 +198,8 @@ function withFakeCodexEnv( const fs = yield* FileSystem.FileSystem; const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3code-codex-text-" }); const codexPath = yield* makeFakeCodexBinary(tempDir, input); - const config = decodeCodexSettings({ binaryPath: codexPath }); - const textGeneration = yield* makeCodexTextGeneration(config); + const config = decodeCodexSettings({ binaryPath: codexPath, launchArgs: input.launchArgs }); + const textGeneration = yield* makeCodexTextGeneration(config, input.environment); return yield* effectFn(textGeneration); }).pipe(Effect.scoped); } @@ -237,6 +260,51 @@ it.layer(CodexTextGenerationTestLayer)("CodexTextGeneration", (it) => { ), ); + it.effect("passes exec-safe launch args into codex exec", () => + withFakeCodexEnv( + { + output: JSON.stringify({ + subject: "Add important change", + body: "", + }), + launchArgs: "--strict-config --listen off", + requireArg: "--strict-config", + forbidArg: "--listen", + }, + (textGeneration) => + textGeneration.generateCommitMessage({ + cwd: process.cwd(), + branch: "feature/codex-effect", + stagedSummary: "M README.md", + stagedPatch: "diff --git a/README.md b/README.md", + modelSelection: DEFAULT_TEST_MODEL_SELECTION, + }), + ), + ); + + it.effect("uses T3CODE_CODEX_LAUNCH_ARGS for codex exec over settings", () => + withFakeCodexEnv( + { + output: JSON.stringify({ + subject: "Add important change", + body: "", + }), + launchArgs: "--enable settings-feature", + environment: { T3CODE_CODEX_LAUNCH_ARGS: " --strict-config --listen off " }, + requireArg: "--strict-config", + forbidArg: "settings-feature", + }, + (textGeneration) => + textGeneration.generateCommitMessage({ + cwd: process.cwd(), + branch: "feature/codex-effect", + stagedSummary: "M README.md", + stagedPatch: "diff --git a/README.md b/README.md", + modelSelection: DEFAULT_TEST_MODEL_SELECTION, + }), + ), + ); + it.effect("defaults git text generation codex effort to low", () => withFakeCodexEnv( { diff --git a/apps/server/src/textGeneration/CodexTextGeneration.ts b/apps/server/src/textGeneration/CodexTextGeneration.ts index 0e68994fd3dd..6a5c0df43c7f 100644 --- a/apps/server/src/textGeneration/CodexTextGeneration.ts +++ b/apps/server/src/textGeneration/CodexTextGeneration.ts @@ -14,6 +14,7 @@ import { resolveSpawnCommand } from "@t3tools/shared/shell"; import { resolveAttachmentPath } from "../attachmentStore.ts"; import * as ServerConfig from "../config.ts"; import { expandHomePath } from "../pathExpansion.ts"; +import { codexExecLaunchArgs, resolveCodexLaunchArgs } from "../provider/Layers/codexLaunchArgs.ts"; import { TextGenerationError } from "@t3tools/contracts"; import * as TextGeneration from "./TextGeneration.ts"; import { @@ -174,6 +175,7 @@ export const makeCodexTextGeneration = Effect.fn("makeCodexTextGeneration")(func const outputPath = yield* writeTempFile(operation, "codex-output", ""); const runCodexCommand = Effect.fn("runCodexJson.runCodexCommand")(function* () { + const launchArgs = resolveCodexLaunchArgs(codexConfig.launchArgs, resolvedEnvironment); const reasoningEffort = getModelSelectionStringOptionValue(modelSelection, "reasoningEffort") ?? CODEX_GIT_TEXT_GENERATION_REASONING_EFFORT; @@ -182,6 +184,7 @@ export const makeCodexTextGeneration = Effect.fn("makeCodexTextGeneration")(func codexConfig.binaryPath || "codex", [ "exec", + ...codexExecLaunchArgs(launchArgs), "--ephemeral", "--skip-git-repo-check", "-s", diff --git a/apps/server/src/textGeneration/OpenCodeTextGeneration.test.ts b/apps/server/src/textGeneration/OpenCodeTextGeneration.test.ts index 558a8663b64d..1fcf9bc4c73a 100644 --- a/apps/server/src/textGeneration/OpenCodeTextGeneration.test.ts +++ b/apps/server/src/textGeneration/OpenCodeTextGeneration.test.ts @@ -107,6 +107,14 @@ const OpenCodeRuntimeTestDouble: OpenCodeRuntime.OpenCodeRuntimeShape = { cause: null, }), ), + loadInventoryFromCli: () => + Effect.fail( + new OpenCodeRuntime.OpenCodeRuntimeError({ + operation: "loadInventoryFromCli", + detail: "OpenCodeRuntimeTestDouble.loadInventoryFromCli not used in this test", + cause: null, + }), + ), }; const DEFAULT_TEST_MODEL_SELECTION = { diff --git a/apps/server/src/ws.ts b/apps/server/src/ws.ts index d56edc990c46..852749b6d22d 100644 --- a/apps/server/src/ws.ts +++ b/apps/server/src/ws.ts @@ -936,6 +936,8 @@ const makeWsRpcLayer = ( otlpMetricsEnabled: config.otlpMetricsUrl !== undefined, }, settings, + shellResumeCompletionMarker: true, + threadResumeCompletionMarker: true, }; }); @@ -1066,6 +1068,23 @@ const makeWsRpcLayer = ( observeRpcStreamEffect( ORCHESTRATION_WS_METHODS.subscribeShell, Effect.gen(function* () { + // Acquire the PubSub subscription synchronously before forking. + // `Stream.fromPubSub` defers subscribe until stream start, and + // `forkScoped` only schedules the fibre — so an event published + // between schedule and start would still drop without this. + const liveBuffer = yield* Queue.unbounded(); + const liveSubscription = yield* orchestrationEngine.subscribeDomainEvents; + yield* Effect.forkScoped( + Stream.fromSubscription(liveSubscription).pipe( + Stream.mapEffect(toShellStreamEvent), + Stream.flatMap((event) => + Option.isSome(event) ? Stream.succeed(event.value) : Stream.empty, + ), + Stream.runForEach((item) => Queue.offer(liveBuffer, item)), + ), + ); + const bufferedLiveStream = Stream.fromQueue(liveBuffer); + // When the client already holds a shell snapshot (cached, or loaded // over HTTP) it passes that snapshot's sequence, and we resume by // replaying shell events after it instead of re-sending the whole @@ -1077,51 +1096,33 @@ const makeWsRpcLayer = ( // page limit) since the shell filter runs after reading. if (input.afterSequence !== undefined) { const afterSequence = input.afterSequence; - return Stream.unwrap( - Effect.gen(function* () { - const liveBuffer = yield* Queue.unbounded(); - // Acquire the PubSub subscription synchronously before - // forking. `Stream.fromPubSub` defers subscribe until - // stream start, and `forkScoped` only schedules the fibre — - // so an event published between schedule and start would - // still drop without this. - const liveSubscription = yield* orchestrationEngine.subscribeDomainEvents; - yield* Effect.forkScoped( - Stream.fromSubscription(liveSubscription).pipe( - Stream.mapEffect(toShellStreamEvent), - Stream.flatMap((event) => - Option.isSome(event) ? Stream.succeed(event.value) : Stream.empty, - ), - Stream.runForEach((item) => Queue.offer(liveBuffer, item)), - ), - ); - const catchUpStream = orchestrationEngine - .readEvents(afterSequence, Number.MAX_SAFE_INTEGER) - .pipe( - Stream.mapEffect(toShellStreamEvent), - Stream.flatMap((event) => - Option.isSome(event) ? Stream.succeed(event.value) : Stream.empty, - ), - Stream.mapError( - (cause) => - new OrchestrationGetSnapshotError({ - message: "Failed to replay orchestration shell events", - cause, - }), - ), - ); - return Stream.concat(catchUpStream, Stream.fromQueue(liveBuffer)); - }), - ); + const catchUpStream = orchestrationEngine + .readEvents(afterSequence, Number.MAX_SAFE_INTEGER) + .pipe( + Stream.mapEffect(toShellStreamEvent), + Stream.flatMap((event) => + Option.isSome(event) ? Stream.succeed(event.value) : Stream.empty, + ), + Stream.mapError( + (cause) => + new OrchestrationGetSnapshotError({ + message: "Failed to replay orchestration shell events", + cause, + }), + ), + ); + const afterCatchUp = + input.requestCompletionMarker === true + ? Stream.concat( + Stream.fromEffect( + Queue.offer(liveBuffer, { kind: "synchronized" as const }), + ).pipe(Stream.drain), + bufferedLiveStream, + ) + : bufferedLiveStream; + return Stream.concat(catchUpStream, afterCatchUp); } - const liveStream = orchestrationEngine.streamDomainEvents.pipe( - Stream.mapEffect(toShellStreamEvent), - Stream.flatMap((event) => - Option.isSome(event) ? Stream.succeed(event.value) : Stream.empty, - ), - ); - const snapshot = yield* projectionSnapshotQuery.getShellSnapshot().pipe( Effect.tapError((cause) => Effect.logError("orchestration shell snapshot load failed", { cause }), @@ -1135,12 +1136,21 @@ const makeWsRpcLayer = ( ), ); + const afterSnapshot = + input.requestCompletionMarker === true + ? Stream.concat( + Stream.fromEffect( + Queue.offer(liveBuffer, { kind: "synchronized" as const }), + ).pipe(Stream.drain), + bufferedLiveStream, + ) + : bufferedLiveStream; return Stream.concat( Stream.make({ kind: "snapshot" as const, snapshot, }), - liveStream, + afterSnapshot, ); }), { "rpc.aggregate": "orchestration" }, @@ -1227,7 +1237,16 @@ const makeWsRpcLayer = ( }), ), ); - return Stream.concat(catchUpStream, bufferedLiveStream); + const afterCatchUp = + input.requestCompletionMarker === true + ? Stream.concat( + Stream.fromEffect( + Queue.offer(liveBuffer, { kind: "synchronized" as const }), + ).pipe(Stream.drain), + bufferedLiveStream, + ) + : bufferedLiveStream; + return Stream.concat(catchUpStream, afterCatchUp); } const snapshot = yield* projectionSnapshotQuery @@ -1249,12 +1268,21 @@ const makeWsRpcLayer = ( }); } + const afterSnapshot = + input.requestCompletionMarker === true + ? Stream.concat( + Stream.fromEffect( + Queue.offer(liveBuffer, { kind: "synchronized" as const }), + ).pipe(Stream.drain), + bufferedLiveStream, + ) + : bufferedLiveStream; return Stream.concat( Stream.make({ kind: "snapshot" as const, snapshot: snapshot.value, }), - bufferedLiveStream, + afterSnapshot, ); }), { "rpc.aggregate": "orchestration" }, diff --git a/apps/web/src/components/AppSidebarLayout.tsx b/apps/web/src/components/AppSidebarLayout.tsx index 587ec65cbc98..ee56858bc588 100644 --- a/apps/web/src/components/AppSidebarLayout.tsx +++ b/apps/web/src/components/AppSidebarLayout.tsx @@ -33,6 +33,12 @@ function SidebarControl() { useEffect(() => { const onKeyDown = (event: KeyboardEvent) => { if (event.defaultPrevented) return; + if ( + event.target instanceof HTMLElement && + event.target.closest("[data-keybinding-capture]") + ) { + return; + } if (resolveShortcutCommand(event, keybindings) !== "sidebar.toggle") return; event.preventDefault(); @@ -40,8 +46,9 @@ function SidebarControl() { toggleSidebar(); }; - window.addEventListener("keydown", onKeyDown); - return () => window.removeEventListener("keydown", onKeyDown); + // Capture before focused editors consume commands such as Mod+B for rich-text formatting. + window.addEventListener("keydown", onKeyDown, true); + return () => window.removeEventListener("keydown", onKeyDown, true); }, [keybindings, toggleSidebar]); return ( @@ -131,7 +138,8 @@ export function AppSidebarLayout({ children }: { children: ReactNode }) { className="border-r border-border bg-card text-foreground" resizable={{ minWidth: THREAD_SIDEBAR_MIN_WIDTH, - shouldAcceptWidth: ({ nextWidth, wrapper }) => + shouldAcceptWidth: ({ currentWidth, nextWidth, wrapper }) => + nextWidth <= currentWidth || wrapper.clientWidth - nextWidth >= THREAD_MAIN_CONTENT_MIN_WIDTH, storageKey: THREAD_SIDEBAR_WIDTH_STORAGE_KEY, }} diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index 80ddebd702b9..90d3b7600a04 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -145,6 +145,7 @@ import { stackedThreadToast, toastManager } from "./ui/toast"; import { decodeProjectScriptKeybindingRule } from "~/lib/projectScriptKeybindings"; import { type NewProjectScriptInput } from "./ProjectScriptsControl"; import { + buildProjectScript, commandForProjectScript, nextProjectScriptId, projectScriptIdFromCommand, @@ -2752,13 +2753,7 @@ function ChatViewContent(props: ChatViewProps) { input.name, activeProject.scripts.map((script) => script.id), ); - const nextScript: ProjectScript = { - id: nextId, - name: input.name, - command: input.command, - icon: input.icon, - runOnWorktreeCreate: input.runOnWorktreeCreate, - }; + const nextScript = buildProjectScript(nextId, input); const nextScripts = input.runOnWorktreeCreate ? [ ...activeProject.scripts.map((script) => @@ -2792,13 +2787,7 @@ function ChatViewContent(props: ChatViewProps) { return AsyncResult.failure(Cause.fail(new Error("Script not found."))); } - const updatedScript: ProjectScript = { - ...existingScript, - name: input.name, - command: input.command, - icon: input.icon, - runOnWorktreeCreate: input.runOnWorktreeCreate, - }; + const updatedScript = buildProjectScript(existingScript.id, input); const nextScripts = activeProject.scripts.map((script) => script.id === scriptId ? updatedScript diff --git a/apps/web/src/components/ComposerPromptEditor.tsx b/apps/web/src/components/ComposerPromptEditor.tsx index 585d46150a80..169126788ae8 100644 --- a/apps/web/src/components/ComposerPromptEditor.tsx +++ b/apps/web/src/components/ComposerPromptEditor.tsx @@ -28,7 +28,10 @@ import { KEY_ENTER_COMMAND, KEY_TAB_COMMAND, COMMAND_PRIORITY_HIGH, + COMMAND_PRIORITY_LOW, KEY_BACKSPACE_COMMAND, + BLUR_COMMAND, + FOCUS_COMMAND, $getRoot, HISTORY_MERGE_TAG, DecoratorNode, @@ -185,7 +188,7 @@ class ComposerMentionNode extends DecoratorNode { override createDOM(): HTMLElement { const dom = document.createElement("span"); - dom.className = "inline-flex align-middle leading-none"; + dom.className = "composer-inline-chip relative inline-flex align-middle leading-none"; return dom; } @@ -323,7 +326,7 @@ class ComposerSkillNode extends DecoratorNode { override createDOM(): HTMLElement { const dom = document.createElement("span"); - dom.className = "inline-flex align-middle leading-none"; + dom.className = "composer-inline-chip relative inline-flex align-middle leading-none"; return dom; } @@ -394,7 +397,7 @@ class ComposerTerminalContextNode extends DecoratorNode { override createDOM(): HTMLElement { const dom = document.createElement("span"); - dom.className = "inline-flex align-middle leading-none"; + dom.className = "composer-inline-chip relative inline-flex align-middle leading-none"; return dom; } @@ -1167,6 +1170,80 @@ function ComposerInlineTokenBackspacePlugin() { return null; } +/** + * Chips render as non-editable decorators, so the browser never paints the + * native text selection over them; without help, a selection spanning chips + * is only visible in the slivers between them. Mirror the selection onto the + * chips with a data attribute the stylesheet turns into a highlight overlay. + */ +function ComposerChipSelectionPlugin() { + const [editor] = useLexicalComposerContext(); + + useEffect(() => { + let selectedKeys = new Set(); + // Lexical keeps the range selection on blur without emitting an update, + // so focus is tracked separately; while blurred the native highlight is + // gone and the mirrored one has to go with it. + let hasFocus = editor.getRootElement() === document.activeElement; + + const applyKeys = (nextKeys: Set) => { + for (const key of selectedKeys) { + if (!nextKeys.has(key)) { + editor.getElementByKey(key)?.removeAttribute("data-composer-chip-selected"); + } + } + for (const key of nextKeys) { + editor.getElementByKey(key)?.setAttribute("data-composer-chip-selected", "true"); + } + selectedKeys = nextKeys; + }; + + const readSelectedKeys = () => { + const nextKeys = new Set(); + editor.getEditorState().read(() => { + const selection = $getSelection(); + if ($isRangeSelection(selection) && !selection.isCollapsed()) { + for (const node of selection.getNodes()) { + if (node instanceof DecoratorNode) { + nextKeys.add(node.getKey()); + } + } + } + }); + return nextKeys; + }; + + const unregisterUpdate = editor.registerUpdateListener(() => { + applyKeys(hasFocus ? readSelectedKeys() : new Set()); + }); + const unregisterFocus = editor.registerCommand( + FOCUS_COMMAND, + () => { + hasFocus = true; + applyKeys(readSelectedKeys()); + return false; + }, + COMMAND_PRIORITY_LOW, + ); + const unregisterBlur = editor.registerCommand( + BLUR_COMMAND, + () => { + hasFocus = false; + applyKeys(new Set()); + return false; + }, + COMMAND_PRIORITY_LOW, + ); + return () => { + unregisterUpdate(); + unregisterFocus(); + unregisterBlur(); + }; + }, [editor]); + + return null; +} + function ComposerInlineTokenPastePlugin() { const [editor] = useLexicalComposerContext(); @@ -1701,6 +1778,7 @@ function ComposerPromptEditorInner({ + diff --git a/apps/web/src/components/Sidebar.logic.test.ts b/apps/web/src/components/Sidebar.logic.test.ts index 5f6c234e5f69..1dd4e3401253 100644 --- a/apps/web/src/components/Sidebar.logic.test.ts +++ b/apps/web/src/components/Sidebar.logic.test.ts @@ -1,5 +1,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vite-plus/test"; import { + archiveSelectedThreadEntries, + buildMultiSelectThreadContextMenuItems, createThreadJumpHintVisibilityController, getSidebarThreadIdsToPrewarm, getVisibleSidebarThreadIds, @@ -38,6 +40,73 @@ import { const localEnvironmentId = EnvironmentId.make("environment-local"); +describe("archiveSelectedThreadEntries", () => { + const entries = [{ threadKey: "one" }, { threadKey: "two" }, { threadKey: "three" }] as const; + const success = { _tag: "Success" } as const; + const failure = { _tag: "Failure" } as const; + + it("records every entry after full success", async () => { + const outcome = await archiveSelectedThreadEntries({ + entries, + archive: async (_entry, onArchived) => { + onArchived(); + return success; + }, + }); + + expect(outcome).toEqual({ + archivedThreadKeys: ["one", "two", "three"], + mutationFailure: null, + followupFailures: [], + }); + }); + + it("stops at a mutation failure and retains prior successes", async () => { + const archive = vi.fn(async (entry: (typeof entries)[number], onArchived: () => void) => { + if (entry.threadKey === "two") return failure; + onArchived(); + return success; + }); + const outcome = await archiveSelectedThreadEntries({ entries, archive }); + + expect(archive).toHaveBeenCalledTimes(2); + expect(outcome).toEqual({ + archivedThreadKeys: ["one"], + mutationFailure: failure, + followupFailures: [], + }); + }); + + it("continues after a post-archive failure", async () => { + const archive = vi.fn(async (entry: (typeof entries)[number], onArchived: () => void) => { + onArchived(); + return entry.threadKey === "two" ? failure : success; + }); + const outcome = await archiveSelectedThreadEntries({ entries, archive }); + + expect(archive).toHaveBeenCalledTimes(3); + expect(outcome).toEqual({ + archivedThreadKeys: ["one", "two", "three"], + mutationFailure: null, + followupFailures: [failure], + }); + }); +}); + +describe("buildMultiSelectThreadContextMenuItems", () => { + it("offers bulk archive with the selected count", () => { + expect( + buildMultiSelectThreadContextMenuItems({ count: 3, hasRunningThread: false }), + ).toContainEqual({ id: "archive", label: "Archive (3)", disabled: false }); + }); + + it("disables bulk archive when a selected thread is running", () => { + expect( + buildMultiSelectThreadContextMenuItems({ count: 2, hasRunningThread: true }), + ).toContainEqual({ id: "archive", label: "Archive (2)", disabled: true }); + }); +}); + describe("resolveSidebarStageBadgeLabel", () => { it("returns Nightly for nightly primary server versions", () => { expect( diff --git a/apps/web/src/components/Sidebar.logic.ts b/apps/web/src/components/Sidebar.logic.ts index 91a61cc1558f..1a565efd8783 100644 --- a/apps/web/src/components/Sidebar.logic.ts +++ b/apps/web/src/components/Sidebar.logic.ts @@ -1,4 +1,5 @@ import * as React from "react"; +import type { ContextMenuItem } from "@t3tools/contracts"; import type { SidebarProjectSortOrder, SidebarThreadSortOrder } from "@t3tools/contracts/settings"; import { getThreadSortTimestamp, @@ -36,6 +37,55 @@ type ScopedSidebarThread = ThreadSortInput & { export type ThreadTraversalDirection = "previous" | "next"; +export async function archiveSelectedThreadEntries< + TEntry extends { readonly threadKey: string }, + TResult extends { readonly _tag: "Success" | "Failure" }, +>(input: { + entries: readonly TEntry[]; + archive: (entry: TEntry, onArchived: () => void) => Promise; +}): Promise<{ + archivedThreadKeys: readonly string[]; + mutationFailure: Extract | null; + followupFailures: readonly Extract[]; +}> { + const archivedThreadKeys: string[] = []; + const followupFailures: Extract[] = []; + + for (const entry of input.entries) { + let didArchive = false; + const result = await input.archive(entry, () => { + didArchive = true; + }); + if (didArchive || result._tag === "Success") { + archivedThreadKeys.push(entry.threadKey); + } + if (result._tag === "Success") continue; + const failure = result as Extract; + if (didArchive) { + followupFailures.push(failure); + continue; + } + return { archivedThreadKeys, mutationFailure: failure, followupFailures }; + } + + return { archivedThreadKeys, mutationFailure: null, followupFailures }; +} + +export function buildMultiSelectThreadContextMenuItems(input: { + count: number; + hasRunningThread: boolean; +}): readonly ContextMenuItem<"mark-unread" | "archive" | "delete">[] { + return [ + { id: "mark-unread", label: `Mark unread (${input.count})` }, + { + id: "archive", + label: `Archive (${input.count})`, + disabled: input.hasRunningThread, + }, + { id: "delete", label: `Delete (${input.count})`, destructive: true }, + ]; +} + export interface ThreadStatusPill { label: | "Working" diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx index 29f66dbbfba2..8665585a43da 100644 --- a/apps/web/src/components/Sidebar.tsx +++ b/apps/web/src/components/Sidebar.tsx @@ -187,6 +187,8 @@ import { import { useThreadSelectionStore } from "../threadSelectionStore"; import { useOpenAddProjectCommandPalette } from "../commandPaletteContext"; import { + archiveSelectedThreadEntries, + buildMultiSelectThreadContextMenuItems, getSidebarThreadIdsToPrewarm, resolveAdjacentThreadId, isContextMenuPointerDown, @@ -1779,24 +1781,69 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec const threadKeys = [...useThreadSelectionStore.getState().selectedThreadKeys]; if (threadKeys.length === 0) return; const count = threadKeys.length; + const selectedThreadEntries = threadKeys.flatMap((threadKey) => { + const threadRef = parseScopedThreadKey(threadKey); + const thread = threadRef ? readThreadShell(threadRef) : null; + return threadRef && thread ? [{ threadKey, threadRef, thread }] : []; + }); + const hasRunningThread = selectedThreadEntries.some( + ({ thread }) => thread.session?.status === "running" && thread.session.activeTurnId != null, + ); const clicked = await api.contextMenu.show( - [ - { id: "mark-unread", label: `Mark unread (${count})` }, - { id: "delete", label: `Delete (${count})`, destructive: true }, - ], + buildMultiSelectThreadContextMenuItems({ count, hasRunningThread }), position, ); if (clicked === "mark-unread") { - for (const threadKey of threadKeys) { - const thread = sidebarThreadByKeyRef.current.get(threadKey); - markThreadUnread(threadKey, thread?.latestTurn?.completedAt); + for (const { threadKey, thread } of selectedThreadEntries) { + markThreadUnread(threadKey, thread.latestTurn?.completedAt); } clearSelection(); return; } + if (clicked === "archive") { + if (appSettingsConfirmThreadArchive) { + const confirmed = await api.dialogs.confirm( + `Archive ${count} thread${count === 1 ? "" : "s"}?`, + ); + if (!confirmed) return; + } + + const archiveOutcome = await archiveSelectedThreadEntries({ + entries: selectedThreadEntries, + archive: ({ threadRef }, onArchived) => archiveThread(threadRef, { onArchived }), + }); + for (const failure of archiveOutcome.followupFailures) { + if (isAtomCommandInterrupted(failure)) continue; + const error = squashAtomCommandFailure(failure); + toastManager.add( + stackedThreadToast({ + type: "error", + title: "Thread archived, but navigation failed", + description: error instanceof Error ? error.message : "An error occurred.", + }), + ); + } + if (archiveOutcome.mutationFailure) { + removeFromSelection(archiveOutcome.archivedThreadKeys); + if (!isAtomCommandInterrupted(archiveOutcome.mutationFailure)) { + const error = squashAtomCommandFailure(archiveOutcome.mutationFailure); + toastManager.add( + stackedThreadToast({ + type: "error", + title: "Failed to archive threads", + description: error instanceof Error ? error.message : "An error occurred.", + }), + ); + } + return; + } + removeFromSelection(threadKeys); + return; + } + if (clicked !== "delete") return; if (appSettingsConfirmThreadDelete) { @@ -1810,10 +1857,8 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec } const deletedThreadKeys = new Set(threadKeys); - for (const threadKey of threadKeys) { - const thread = sidebarThreadByKeyRef.current.get(threadKey); - if (!thread) continue; - const result = await deleteThread(scopeThreadRef(thread.environmentId, thread.id), { + for (const { threadRef } of selectedThreadEntries) { + const result = await deleteThread(threadRef, { deletedThreadKeys, }); if (result._tag === "Failure") { @@ -1833,7 +1878,9 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec removeFromSelection(threadKeys); }, [ + appSettingsConfirmThreadArchive, appSettingsConfirmThreadDelete, + archiveThread, clearSelection, deleteThread, markThreadUnread, diff --git a/apps/web/src/components/chat/ComposerPendingApprovalPanel.test.tsx b/apps/web/src/components/chat/ComposerPendingApprovalPanel.test.tsx new file mode 100644 index 000000000000..fbaf81bc9fd6 --- /dev/null +++ b/apps/web/src/components/chat/ComposerPendingApprovalPanel.test.tsx @@ -0,0 +1,28 @@ +import { ApprovalRequestId } from "@t3tools/contracts"; +import { renderToStaticMarkup } from "react-dom/server"; +import { describe, expect, it } from "vite-plus/test"; + +import { ComposerPendingApprovalPanel } from "./ComposerPendingApprovalPanel"; + +describe("ComposerPendingApprovalPanel", () => { + it("renders complete multiline command details without hover or truncation", () => { + const detail = `bun run release -- ${"long-argument ".repeat(20)}\nsecond line`; + const markup = renderToStaticMarkup( + , + ); + + expect(markup).toContain('data-approval-detail="complete"'); + expect(markup).toContain('aria-label="Command"'); + expect(markup).toContain(detail); + expect(markup).not.toContain("truncate"); + expect(markup).not.toContain("line-clamp"); + }); +}); diff --git a/apps/web/src/components/chat/ComposerPendingApprovalPanel.tsx b/apps/web/src/components/chat/ComposerPendingApprovalPanel.tsx index 569fd108a4a8..dd966bf57952 100644 --- a/apps/web/src/components/chat/ComposerPendingApprovalPanel.tsx +++ b/apps/web/src/components/chat/ComposerPendingApprovalPanel.tsx @@ -16,6 +16,12 @@ export const ComposerPendingApprovalPanel = memo(function ComposerPendingApprova : approval.requestKind === "file-read" ? "File-read approval requested" : "File-change approval requested"; + const detailLabel = + approval.requestKind === "command" + ? "Command" + : approval.requestKind === "file-read" + ? "File to read" + : "File change"; return (
@@ -26,6 +32,18 @@ export const ComposerPendingApprovalPanel = memo(function ComposerPendingApprova 1/{pendingCount} ) : null}
+ {approval.detail ? ( +
+

{detailLabel}

+
+            {approval.detail}
+          
+
+ ) : null} ); }); diff --git a/apps/web/src/components/chat/MessagesTimeline.logic.ts b/apps/web/src/components/chat/MessagesTimeline.logic.ts index c6e277cce08b..3227bac2413b 100644 --- a/apps/web/src/components/chat/MessagesTimeline.logic.ts +++ b/apps/web/src/components/chat/MessagesTimeline.logic.ts @@ -64,6 +64,45 @@ export function resolveTimelineMinimapHasPersistentGutter(viewportWidth: number) return sideGutter >= TIMELINE_MINIMAP_PERSISTENT_GUTTER; } +export const TIMELINE_MINIMAP_HIT_STRIP_LEFT = 12; +export const TIMELINE_MINIMAP_HIT_STRIP_MAX_WIDTH = 40; +export const TIMELINE_MINIMAP_EXPANDED_HIT_STRIP_WIDTH = "22rem"; + +/** + * The minimap overlays the viewport's left edge while the content column is + * centered, so the side gutter between them shrinks under browser zoom or a + * narrow pane. A fixed-width hover strip would then sit on top of the message + * text and swallow its pointer events. Cap the strip's width so it never + * extends past the gutter into the content column; 0 disables the strip. + */ +export function resolveTimelineMinimapHitStripWidth(viewportWidth: number): number { + if (!Number.isFinite(viewportWidth) || viewportWidth <= 0) { + return 0; + } + + const contentWidth = Math.min(viewportWidth, TIMELINE_CONTENT_MAX_WIDTH); + const sideGutter = Math.max(0, (viewportWidth - contentWidth) / 2); + return Math.max( + 0, + Math.min( + TIMELINE_MINIMAP_HIT_STRIP_MAX_WIDTH, + Math.floor(sideGutter) - TIMELINE_MINIMAP_HIT_STRIP_LEFT, + ), + ); +} + +/** + * Once the preview is open, keep the full preview and the space leading to it + * interactive. The collapsed strip remains gutter-capped so it cannot block + * selecting message text. + */ +export function resolveTimelineMinimapInteractiveWidth( + collapsedWidth: number, + expanded: boolean, +): number | string { + return expanded ? TIMELINE_MINIMAP_EXPANDED_HIT_STRIP_WIDTH : collapsedWidth; +} + function computeElapsedMs(startIso: string, endIso: string): number | null { const start = Date.parse(startIso); const end = Date.parse(endIso); diff --git a/apps/web/src/components/chat/MessagesTimeline.test.tsx b/apps/web/src/components/chat/MessagesTimeline.test.tsx index 2dfa86530a45..c4894b734b0d 100644 --- a/apps/web/src/components/chat/MessagesTimeline.test.tsx +++ b/apps/web/src/components/chat/MessagesTimeline.test.tsx @@ -226,7 +226,9 @@ describe("MessagesTimeline", () => { resolveTimelineIsAtEnd, resolveTimelineMinimapHasPersistentGutter, resolveTimelineMinimapHeightStyle, + resolveTimelineMinimapHitStripWidth, resolveTimelineMinimapIndexFromPointer, + resolveTimelineMinimapInteractiveWidth, resolveTimelineMinimapTopPercent, } = await import("./MessagesTimeline.logic"); @@ -256,6 +258,28 @@ describe("MessagesTimeline", () => { expect(resolveTimelineMinimapHasPersistentGutter(832)).toBe(false); expect(resolveTimelineMinimapHasPersistentGutter(863)).toBe(false); expect(resolveTimelineMinimapHasPersistentGutter(864)).toBe(true); + + // No usable gutter (zoomed in / narrow pane): the strip must go inert + // instead of overlaying the centered content column. + expect(resolveTimelineMinimapHitStripWidth(768)).toBe(0); + expect(resolveTimelineMinimapHitStripWidth(792)).toBe(0); + // Partial gutter: strip shrinks to what fits between the viewport edge + // and the content column. + expect(resolveTimelineMinimapHitStripWidth(820)).toBe(14); + // Full gutter: unchanged 40px-wide strip. + expect(resolveTimelineMinimapHitStripWidth(872)).toBe(40); + expect(resolveTimelineMinimapHitStripWidth(1400)).toBe(40); + expect(resolveTimelineMinimapHitStripWidth(0)).toBe(0); + expect(resolveTimelineMinimapHitStripWidth(Number.NaN)).toBe(0); + + // The collapsed target stays narrow, but an open preview keeps its full + // 20rem width plus the 2rem offset from the minimap rail interactive. + expect(resolveTimelineMinimapInteractiveWidth(0, false)).toBe(0); + expect(resolveTimelineMinimapInteractiveWidth(14, false)).toBe(14); + expect(resolveTimelineMinimapInteractiveWidth(40, false)).toBe(40); + expect(resolveTimelineMinimapInteractiveWidth(0, true)).toBe("22rem"); + expect(resolveTimelineMinimapInteractiveWidth(14, true)).toBe("22rem"); + expect(resolveTimelineMinimapInteractiveWidth(40, true)).toBe("22rem"); }); it("anchors a sent attachment message using its measured height", async () => { @@ -301,7 +325,7 @@ describe("MessagesTimeline", () => { expect(markup).not.toContain('data-maintain-scroll-at-end="enabled"'); expect(markup).toContain('data-maintain-visible-content-position="object"'); expect(markup).toContain('data-maintain-visible-content-position-data="true"'); - expect(markup).toContain('data-maintain-visible-content-position-size="true"'); + expect(markup).toContain('data-maintain-visible-content-position-size="false"'); expect(onAnchorReady).toHaveBeenCalledOnce(); expect(onAnchorReady).toHaveBeenCalledWith(secondEntry.message.id, 1); expect(onAnchorSizeChanged).toHaveBeenCalledWith(secondEntry.message.id, 240); diff --git a/apps/web/src/components/chat/MessagesTimeline.tsx b/apps/web/src/components/chat/MessagesTimeline.tsx index 62e49075e559..73fc86312e51 100644 --- a/apps/web/src/components/chat/MessagesTimeline.tsx +++ b/apps/web/src/components/chat/MessagesTimeline.tsx @@ -31,7 +31,6 @@ import { workEntryIndicatesToolSuccess, workLogEntryIsToolLike, } from "../../session-logic"; -import { useAppSettings } from "../../appSettings"; import { type TurnDiffSummary } from "../../types"; import { summarizeTurnDiffStats } from "../../lib/turnDiffTree"; import { @@ -74,7 +73,9 @@ import { resolveTimelineIsAtEnd, resolveTimelineMinimapHasPersistentGutter, resolveTimelineMinimapHeightStyle, + resolveTimelineMinimapHitStripWidth, resolveTimelineMinimapIndexFromPointer, + resolveTimelineMinimapInteractiveWidth, resolveTimelineMinimapTopPercent, type StableMessagesTimelineRowsState, type MessagesTimelineRow, @@ -130,7 +131,6 @@ interface TimelineRowSharedState { workspaceRoot: string | undefined; skills: ReadonlyArray>; activeThreadEnvironmentId: EnvironmentId; - showCommandOutput: boolean; onRevertUserMessage: (messageId: MessageId) => void; onImageExpand: (preview: ExpandedImagePreview) => void; onOpenTurnDiff: (turnId: TurnId, filePath?: string) => void; @@ -149,8 +149,6 @@ const TimelineRowActivityCtx = createContext(null!); const TIMELINE_LIST_HEADER =
; const TIMELINE_LIST_FOOTER =
; const EMPTY_TIMELINE_SKILLS: ReadonlyArray> = []; -const TIMELINE_DISCLOSURE_SETTLE_MS = 220; -const TIMELINE_MINIMAP_PREVIEW_MAX_CHARS = 240; // --------------------------------------------------------------------------- // Props (public API) @@ -219,61 +217,24 @@ export const MessagesTimeline = memo(function MessagesTimeline({ onManualNavigation, hideEmptyPlaceholder = false, }: MessagesTimelineProps) { - const { settings } = useAppSettings(); - const showCommandOutput = settings.showCommandOutput; const [expandedTurnIds, setExpandedTurnIds] = useState>(new Set()); const [expandedWorkGroupIds, setExpandedWorkGroupIds] = useState>(new Set()); const [minimapStripMap] = useState(() => new Map()); - const [foldToggleSettling, setFoldToggleSettling] = useState(false); - const foldToggleSettlingFrameRef = useRef(null); - const foldToggleSettlingTimeoutRef = useRef(null); - - const suspendEndFollowingForDisclosure = useCallback(() => { - setFoldToggleSettling(true); - if (foldToggleSettlingFrameRef.current !== null) { - window.cancelAnimationFrame(foldToggleSettlingFrameRef.current); - } - if (foldToggleSettlingTimeoutRef.current !== null) { - window.clearTimeout(foldToggleSettlingTimeoutRef.current); - } - foldToggleSettlingFrameRef.current = window.requestAnimationFrame(() => { - foldToggleSettlingFrameRef.current = null; - foldToggleSettlingTimeoutRef.current = window.setTimeout(() => { - foldToggleSettlingTimeoutRef.current = null; - setFoldToggleSettling(false); - }, TIMELINE_DISCLOSURE_SETTLE_MS); - }); - }, []); - const onToggleTurnFold = useCallback( - (turnId: TurnId) => { - suspendEndFollowingForDisclosure(); - setExpandedTurnIds((existing) => { - const next = new Set(existing); - if (next.has(turnId)) { - next.delete(turnId); - } else { - next.add(turnId); - } - return next; - }); - }, - [suspendEndFollowingForDisclosure], - ); - useEffect(() => { - return () => { - if (foldToggleSettlingFrameRef.current !== null) { - window.cancelAnimationFrame(foldToggleSettlingFrameRef.current); - } - if (foldToggleSettlingTimeoutRef.current !== null) { - window.clearTimeout(foldToggleSettlingTimeoutRef.current); + const onToggleTurnFold = useCallback((turnId: TurnId) => { + setExpandedTurnIds((existing) => { + const next = new Set(existing); + if (next.has(turnId)) { + next.delete(turnId); + } else { + next.add(turnId); } - }; + return next; + }); }, []); const onToggleWorkGroup = useCallback( (groupId: string, anchorElement?: HTMLElement) => { const anchorBottomBeforeToggle = anchorElement?.getBoundingClientRect().bottom ?? null; - suspendEndFollowingForDisclosure(); flushSync(() => { setExpandedWorkGroupIds((existing) => { @@ -302,7 +263,7 @@ export const MessagesTimeline = memo(function MessagesTimeline({ list.scrollToOffset({ offset: currentScroll + delta, animated: false }); } }, - [listRef, suspendEndFollowingForDisclosure], + [listRef], ); // An in-session interrupt leaves its turn expanded so the user keeps their @@ -360,29 +321,12 @@ export const MessagesTimeline = memo(function MessagesTimeline({ ], ); const rows = useStableRows(rawRows); + const minimapItems = useMemo(() => deriveTimelineMinimapItems(rows), [rows]); const [timelineViewportElement, setTimelineViewportElement] = useState( null, ); const [minimapHasPersistentGutter, setMinimapHasPersistentGutter] = useState(false); - const minimapEligible = useMemo(() => { - if (!minimapHasPersistentGutter) { - return false; - } - let userRows = 0; - for (const row of rows) { - if (row.kind === "message" && row.message.role === "user") { - userRows += 1; - if (userRows >= TIMELINE_MINIMAP_MIN_ITEMS) { - return true; - } - } - } - return false; - }, [minimapHasPersistentGutter, rows]); - const minimapItems = useMemo( - () => (minimapEligible ? deriveTimelineMinimapItems(rows) : []), - [minimapEligible, rows], - ); + const [minimapHitStripWidth, setMinimapHitStripWidth] = useState(0); const handleAnchorReady = useCallback( (info: { anchorIndex: number | undefined }) => { if (anchorMessageId !== null && info.anchorIndex !== undefined) { @@ -454,6 +398,7 @@ export const MessagesTimeline = memo(function MessagesTimeline({ setMinimapHasPersistentGutter((current) => current === nextHasPersistentGutter ? current : nextHasPersistentGutter, ); + setMinimapHitStripWidth(resolveTimelineMinimapHitStripWidth(viewportWidth)); }; const frame = requestAnimationFrame(measure); @@ -477,7 +422,6 @@ export const MessagesTimeline = memo(function MessagesTimeline({ workspaceRoot, skills, activeThreadEnvironmentId, - showCommandOutput, onRevertUserMessage, onImageExpand, onOpenTurnDiff, @@ -492,7 +436,6 @@ export const MessagesTimeline = memo(function MessagesTimeline({ workspaceRoot, skills, activeThreadEnvironmentId, - showCommandOutput, onRevertUserMessage, onImageExpand, onOpenTurnDiff, @@ -548,7 +491,7 @@ export const MessagesTimeline = memo(function MessagesTimeline({ {...(anchoredEndSpace ? { anchoredEndSpace } : {})} contentInsetEndAdjustment={contentInsetEndAdjustment} maintainScrollAtEnd={ - anchoredEndSpace || foldToggleSettling + anchoredEndSpace ? false : { animated: false, @@ -561,7 +504,7 @@ export const MessagesTimeline = memo(function MessagesTimeline({ } maintainVisibleContentPosition={{ data: true, - size: true, + size: false, }} onScroll={handleScroll} className="scrollbar-gutter-both h-full min-h-0 overflow-x-hidden overscroll-y-contain px-3 [overflow-anchor:none] sm:px-5" @@ -572,6 +515,7 @@ export const MessagesTimeline = memo(function MessagesTimeline({ items={minimapItems} bottomInset={contentInsetEndAdjustment} hasPersistentGutter={minimapHasPersistentGutter} + hitStripWidth={minimapHitStripWidth} stripMap={minimapStripMap} onSelect={(item) => { onManualNavigation(); @@ -652,8 +596,7 @@ function resolveFinalAssistantTextForTurn( } function compactMinimapPreview(text: string | null | undefined) { - const compact = - text?.slice(0, TIMELINE_MINIMAP_PREVIEW_MAX_CHARS).replace(/\s+/g, " ").trim() ?? ""; + const compact = text?.replace(/\s+/g, " ").trim() ?? ""; return compact.length > 0 ? compact : null; } @@ -667,15 +610,21 @@ function resolveTimelineRowHeight(state: TimelinePositionState, rowIndex: number return typeof height === "number" && Number.isFinite(height) ? height : null; } +function timelineMinimapEventTargetsPreview(target: EventTarget): boolean { + return target instanceof Element && target.closest("[data-minimap-preview]") !== null; +} + function TimelineMinimap({ bottomInset, hasPersistentGutter, + hitStripWidth, items, stripMap, onSelect, }: { bottomInset: number; hasPersistentGutter: boolean; + hitStripWidth: number; items: ReadonlyArray; stripMap: Map; onSelect: (item: TimelineMinimapItem) => void; @@ -729,7 +678,7 @@ function TimelineMinimap({ [items.length], ); - if (!hasPersistentGutter || items.length < TIMELINE_MINIMAP_MIN_ITEMS) { + if (items.length < TIMELINE_MINIMAP_MIN_ITEMS) { return null; } @@ -738,8 +687,10 @@ function TimelineMinimap({ return ( @@ -1218,7 +1186,13 @@ function WorkGroupToggleTimelineRow({ row: Extract; }) { const ctx = use(TimelineRowCtx); - const labelNoun = row.onlyToolEntries ? "tool call" : "log entry"; + const labelNoun = row.onlyToolEntries + ? row.hiddenCount === 1 + ? "tool call" + : "tool calls" + : row.hiddenCount === 1 + ? "log entry" + : "log entries"; return ( @@ -1966,9 +1939,8 @@ const stopRowToggle = (e: { stopPropagation: () => void }) => e.stopPropagation( const SimpleWorkEntryRow = memo(function SimpleWorkEntryRow(props: { workEntry: TimelineWorkEntry; workspaceRoot: string | undefined; - showCommandOutput: boolean; }) { - const { workEntry, workspaceRoot, showCommandOutput } = props; + const { workEntry, workspaceRoot } = props; const activity = use(TimelineRowActivityCtx); const [expanded, setExpanded] = useState(false); const iconConfig = workToneIcon(workEntry.tone); @@ -1976,19 +1948,12 @@ const SimpleWorkEntryRow = memo(function SimpleWorkEntryRow(props: { const entryIconName = showWarningIndicator ? "x" : workEntryIconName(workEntry); const heading = toolWorkEntryHeading(workEntry); const rawPreview = workEntryPreview(workEntry, workspaceRoot); - // When showCommandOutput is off, suppress command/detail previews but still show changed-file previews. - const gatedPreview = showCommandOutput - ? rawPreview - : !workEntry.command && !workEntry.detail - ? rawPreview - : null; - // Suppress previews that are effectively the same label as the heading. const preview = - gatedPreview && - normalizeCompactToolLabel(gatedPreview).toLowerCase() === + rawPreview && + normalizeCompactToolLabel(rawPreview).toLowerCase() === normalizeCompactToolLabel(heading).toLowerCase() ? null - : gatedPreview; + : rawPreview; const displayText = preview ? `${heading} - ${preview}` : heading; const expandedBody = buildToolCallExpandedBody(workEntry, workspaceRoot); const canExpand = expandedBody !== null; diff --git a/apps/web/src/components/preview/PreviewView.test.tsx b/apps/web/src/components/preview/PreviewView.test.tsx new file mode 100644 index 000000000000..c0d503c75991 --- /dev/null +++ b/apps/web/src/components/preview/PreviewView.test.tsx @@ -0,0 +1,194 @@ +import { EnvironmentId, ThreadId } from "@t3tools/contracts"; +import { renderToStaticMarkup } from "react-dom/server"; +import { beforeEach, describe, expect, it, vi } from "vite-plus/test"; + +const mocks = vi.hoisted(() => ({ + navigate: vi.fn(async (_tabId: string, _url: string): Promise => undefined), + rememberPreviewUrl: vi.fn(), + readPreparedConnection: vi.fn(() => ({ httpBaseUrl: "http://172.25.85.75:3773" })), + submittedUrl: null as ((url: string) => void) | null, + emptyStateUrl: null as ((url: string) => void) | null, + showEmptyState: false, +})); + +vi.mock("~/state/session", () => ({ + readPreparedConnection: mocks.readPreparedConnection, +})); + +vi.mock("~/composerDraftStore", () => ({ + useComposerDraftStore: ( + select: (store: { addPreviewAnnotation: () => void; addImage: () => void }) => unknown, + ) => select({ addPreviewAnnotation: vi.fn(), addImage: vi.fn() }), +})); + +vi.mock("~/lib/previewAnnotation", () => ({ + previewAnnotationScreenshotFile: vi.fn(), +})); + +vi.mock("~/localApi", () => ({ + ensureLocalApi: vi.fn(), +})); + +vi.mock("~/previewStateStore", () => ({ + rememberPreviewUrl: mocks.rememberPreviewUrl, + updatePreviewServerSnapshot: vi.fn(), + useThreadPreviewState: () => ({ + activeTabId: "tab-1", + desktopByTabId: { + "tab-1": { + canGoBack: false, + canGoForward: false, + loading: false, + zoomFactor: 1, + controller: "none", + }, + }, + recentlySeenUrls: [], + sessions: mocks.showEmptyState + ? {} + : { + "tab-1": { + threadId: "thread-1", + tabId: "tab-1", + navStatus: { + _tag: "Success", + url: "http://example.com/", + title: "Example", + }, + canGoBack: false, + canGoForward: false, + updatedAt: "2026-07-13T00:00:00.000Z", + }, + }, + }), +})); + +vi.mock("~/state/environments", () => ({ + useEnvironment: () => ({ label: "WSL" }), + useEnvironmentHttpBaseUrl: () => "http://172.25.85.75:3773", +})); + +vi.mock("~/state/preview", () => ({ + previewEnvironment: { open: {}, resize: {} }, +})); + +vi.mock("~/state/use-atom-command", () => ({ + useAtomCommand: () => vi.fn(), +})); + +vi.mock("~/browser/browserRecording", () => ({ + startBrowserRecording: vi.fn(), + stopBrowserRecording: vi.fn(), + useActiveBrowserRecordingTabId: () => null, +})); + +vi.mock("~/browser/browserSurfaceStore", () => ({ + useBrowserSurfaceStore: ( + select: (state: { byTabId: Record }) => unknown, + ) => select({ byTabId: {} }), +})); + +vi.mock("~/components/ui/toast", () => ({ + stackedThreadToast: vi.fn(), + toastManager: { add: vi.fn() }, +})); + +vi.mock("./previewBridge", () => ({ + previewBridge: { navigate: mocks.navigate }, +})); + +vi.mock("./PreviewChromeRow", () => ({ + PreviewChromeRow: (props: { onSubmit: (url: string) => void }) => { + mocks.submittedUrl = props.onSubmit; + return null; + }, +})); + +vi.mock("./PreviewEmptyState", () => ({ + PreviewEmptyState: (props: { onOpenUrl: (url: string) => void }) => { + mocks.emptyStateUrl = props.onOpenUrl; + return null; + }, +})); +vi.mock("./PreviewMoreMenu", () => ({ PreviewMoreMenu: () => null })); +vi.mock("./PreviewUnreachable", () => ({ PreviewUnreachable: () => null })); +vi.mock("./ZoomIndicator", () => ({ ZoomIndicator: () => null })); +vi.mock("./AgentBrowserCursor", () => ({ AgentBrowserCursor: () => null })); +vi.mock("~/browser/BrowserSurfaceSlot", () => ({ BrowserSurfaceSlot: () => null })); +vi.mock("./useLoadingProgress", () => ({ useLoadingProgress: () => 0 })); +vi.mock("./usePreviewSession", () => ({ usePreviewSession: vi.fn() })); + +import { PreviewView } from "./PreviewView"; + +describe("PreviewView navigation", () => { + beforeEach(() => { + mocks.navigate.mockClear(); + mocks.rememberPreviewUrl.mockClear(); + mocks.readPreparedConnection.mockClear(); + mocks.submittedUrl = null; + mocks.emptyStateUrl = null; + mocks.showEmptyState = false; + }); + + it.each([ + [ + "https://localhost:8000/dashboard?mode=test#top", + "https://localhost:8000/dashboard?mode=test#top", + ], + ["localhost:5173/app", "http://localhost:5173/app"], + ])("preserves a direct localhost URL in a WSL environment", async (submitted, expected) => { + renderToStaticMarkup( + , + ); + + expect(mocks.submittedUrl).not.toBeNull(); + mocks.submittedUrl?.(submitted); + + await vi.waitFor(() => expect(mocks.navigate).toHaveBeenCalledWith("tab-1", expected)); + expect(mocks.rememberPreviewUrl).toHaveBeenCalledWith( + { + environmentId: "environment-1", + threadId: "thread-1", + }, + expected, + ); + }); + + it("maps an empty-state localhost server onto the WSL host", async () => { + mocks.showEmptyState = true; + renderToStaticMarkup( + , + ); + + expect(mocks.emptyStateUrl).not.toBeNull(); + mocks.emptyStateUrl?.("http://localhost:5173/app?mode=test#top"); + + await vi.waitFor(() => + expect(mocks.navigate).toHaveBeenCalledWith( + "tab-1", + "http://172.25.85.75:5173/app?mode=test#top", + ), + ); + expect(mocks.rememberPreviewUrl).toHaveBeenCalledWith( + { + environmentId: "environment-1", + threadId: "thread-1", + }, + "http://172.25.85.75:5173/app?mode=test#top", + ); + }); +}); diff --git a/apps/web/src/components/preview/PreviewView.tsx b/apps/web/src/components/preview/PreviewView.tsx index bb1c4d409ebd..5f7deeb0fcd7 100644 --- a/apps/web/src/components/preview/PreviewView.tsx +++ b/apps/web/src/components/preview/PreviewView.tsx @@ -7,6 +7,7 @@ import { type PreviewViewportSetting, type ScopedThreadRef, } from "@t3tools/contracts"; +import { normalizePreviewUrl } from "@t3tools/shared/preview"; import { useCallback, useEffect, useRef, useState } from "react"; import { useComposerDraftStore } from "~/composerDraftStore"; @@ -112,27 +113,44 @@ export function PreviewView({ threadRef, tabId: requestedTabId, configuredUrls, tabId ? (state.byTabId[tabId]?.rect ?? null) : null, ); + const navigateToResolvedUrl = useCallback( + async (resolvedUrl: string) => { + if (tabId && previewBridge) { + // Drive the webview imperatively; `usePreviewBridge` mirrors the + // resolved URL back to the server so other clients stay in sync. + await previewBridge.navigate(tabId, resolvedUrl); + rememberPreviewUrl(threadRef, resolvedUrl); + } else { + await openPreviewSession({ + openPreview: open, + threadRef, + url: resolvedUrl, + }); + } + }, + [open, tabId, threadRef], + ); + const handleSubmitUrl = useCallback( async (next: string) => { try { - const resolvedUrl = resolveDiscoveredServerUrl(threadRef.environmentId, next); - if (tabId && previewBridge) { - // Drive the webview imperatively; `usePreviewBridge` mirrors the - // resolved URL back to the server so other clients stay in sync. - await previewBridge.navigate(tabId, resolvedUrl); - rememberPreviewUrl(threadRef, resolvedUrl); - } else { - await openPreviewSession({ - openPreview: open, - threadRef, - url: resolvedUrl, - }); - } + await navigateToResolvedUrl(normalizePreviewUrl(next)); } catch { // Server-side `failed` event renders the unreachable view. } }, - [open, tabId, threadRef], + [navigateToResolvedUrl], + ); + + const handleOpenServerUrl = useCallback( + async (next: string) => { + try { + await navigateToResolvedUrl(resolveDiscoveredServerUrl(threadRef.environmentId, next)); + } catch { + // Server-side `failed` event renders the unreachable view. + } + }, + [navigateToResolvedUrl, threadRef.environmentId], ); const handleRefresh = useCallback(() => { @@ -613,7 +631,7 @@ export function PreviewView({ threadRef, tabId: requestedTabId, configuredUrls, environmentId={threadRef.environmentId} configuredUrls={configuredUrls} recentlySeenUrls={previewState.recentlySeenUrls} - onOpenUrl={(next) => void handleSubmitUrl(next)} + onOpenUrl={(next) => void handleOpenServerUrl(next)} /> ) : null} {snapshot && desktopOverlay ? ( diff --git a/apps/web/src/components/settings/KeybindingsSettings.tsx b/apps/web/src/components/settings/KeybindingsSettings.tsx index b7dbbd3575bc..67c33c9b9423 100644 --- a/apps/web/src/components/settings/KeybindingsSettings.tsx +++ b/apps/web/src/components/settings/KeybindingsSettings.tsx @@ -846,6 +846,7 @@ function KeybindingTableRow({ ) : (
{ - const normalized = driverKind ? normalizeModelSlug(input, driverKind) : input.trim() || null; + const normalized = normalizeCustomModelSlug(input); if (!normalized) { setError("Enter a model slug."); return; diff --git a/apps/web/src/components/settings/ProviderSettingsForm.test.ts b/apps/web/src/components/settings/ProviderSettingsForm.test.ts index 33331c149011..ea8712a87eb5 100644 --- a/apps/web/src/components/settings/ProviderSettingsForm.test.ts +++ b/apps/web/src/components/settings/ProviderSettingsForm.test.ts @@ -18,6 +18,7 @@ describe("ProviderSettingsForm helpers", () => { "binaryPath", "homePath", "shadowHomePath", + "launchArgs", ]); }); diff --git a/apps/web/src/hooks/useSettings.ts b/apps/web/src/hooks/useSettings.ts index 0a8cacb78f7c..f6793de5eaa8 100644 --- a/apps/web/src/hooks/useSettings.ts +++ b/apps/web/src/hooks/useSettings.ts @@ -14,7 +14,6 @@ import { useAtomValue } from "@effect/atom-react"; import { DEFAULT_SERVER_SETTINGS, type EnvironmentId, - ProviderDriverKind, ServerSettings, type ServerSettingsPatch, } from "@t3tools/contracts"; @@ -193,7 +192,6 @@ export function buildLegacyServerSettingsMigrationPatch( (model): model is string => typeof model === "string", ), new Set(), - ProviderDriverKind.make("copilot"), ) : undefined; const copilotPatch = { diff --git a/apps/web/src/hooks/useThreadActions.ts b/apps/web/src/hooks/useThreadActions.ts index 07655ad30d76..dbde5acce996 100644 --- a/apps/web/src/hooks/useThreadActions.ts +++ b/apps/web/src/hooks/useThreadActions.ts @@ -89,7 +89,7 @@ export function useThreadActions() { }, [router]); const archiveThread = useCallback( - async (target: ScopedThreadRef) => { + async (target: ScopedThreadRef, opts: { onArchived?: () => void } = {}) => { const resolved = resolveThreadTarget(target); if (!resolved) return AsyncResult.success(undefined); const { thread, threadRef } = resolved; @@ -115,6 +115,8 @@ export function useThreadActions() { if (archiveResult._tag === "Failure") { return archiveResult; } + refreshArchivedThreadsForEnvironment(threadRef.environmentId); + opts.onArchived?.(); if (shouldNavigateToDraft) { const navigationResult = await settlePromise(() => @@ -123,11 +125,9 @@ export function useThreadActions() { if (navigationResult._tag === "Failure") { return navigationResult; } - refreshArchivedThreadsForEnvironment(threadRef.environmentId); return archiveResult; } - refreshArchivedThreadsForEnvironment(threadRef.environmentId); return archiveResult; }, [archiveThreadMutation, getCurrentRouteThreadRef, resolveThreadTarget], diff --git a/apps/web/src/index.css b/apps/web/src/index.css index 4370209edfb5..413313457c48 100644 --- a/apps/web/src/index.css +++ b/apps/web/src/index.css @@ -1079,3 +1079,15 @@ label:has(> select#reasoning-effort) select { .dark .model-picker-list::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.15); } + +/* Composer chips are non-editable decorators, so the browser skips them when + painting text selection; this overlay stands in for the native highlight. */ +.composer-inline-chip[data-composer-chip-selected]::after { + content: ""; + position: absolute; + inset: 0; + border-radius: 6px; + background-color: Highlight; + opacity: 0.3; + pointer-events: none; +} diff --git a/apps/web/src/modelSelection.test.ts b/apps/web/src/modelSelection.test.ts index 361d8b7ed6f0..3b05cc1f991e 100644 --- a/apps/web/src/modelSelection.test.ts +++ b/apps/web/src/modelSelection.test.ts @@ -101,6 +101,39 @@ describe("instance-scoped model selection", () => { ).toBe("openai/gpt-5.5"); }); + it("preserves a custom slug that collides with a provider alias", () => { + const providers = [ + provider({ + provider: ProviderDriverKind.make("claudeAgent"), + instanceId: "claude_openrouter", + models: ["claude-opus-4-8"], + }), + ]; + const settings: UnifiedSettings = { + ...settingsWithProviderInstances(), + providerInstances: { + ...settingsWithProviderInstances().providerInstances, + [ProviderInstanceId.make("claude_openrouter")]: { + driver: ProviderDriverKind.make("claudeAgent"), + config: { customModels: ["opus"] }, + }, + }, + }; + const openrouter = deriveProviderInstanceEntries(providers)[0]!; + + expect( + getAppModelOptionsForInstance(settings, openrouter).map((option) => option.slug), + ).toEqual(["claude-opus-4-8", "opus"]); + expect( + resolveAppModelSelectionForInstance( + ProviderInstanceId.make("claude_openrouter"), + settings, + providers, + "opus", + ), + ).toBe("opus"); + }); + it("includes Grok custom models from the selected provider instance", () => { const providers = [provider({ provider: ProviderDriverKind.make("grok"), instanceId: "grok" })]; const settings: UnifiedSettings = { diff --git a/apps/web/src/modelSelection.ts b/apps/web/src/modelSelection.ts index af41962d51a8..c1e8cc61fe3c 100644 --- a/apps/web/src/modelSelection.ts +++ b/apps/web/src/modelSelection.ts @@ -10,7 +10,7 @@ import { } from "@t3tools/contracts"; import { createModelSelection, - normalizeModelSlug, + normalizeCustomModelSlug, resolveSelectableModel, } from "@t3tools/shared/model"; import { getComposerProviderState } from "./components/chat/composerProviderState"; @@ -118,13 +118,12 @@ function applyInstanceModelPreferences( export function normalizeCustomModelSlugs( models: Iterable, builtInModelSlugs: ReadonlySet, - provider: ProviderDriverKind = ProviderDriverKind.make("codex"), ): string[] { const normalizedModels: string[] = []; const seen = new Set(); for (const candidate of models) { - const normalized = normalizeModelSlug(candidate, provider); + const normalized = normalizeCustomModelSlug(candidate); if ( !normalized || normalized.length > MAX_CUSTOM_MODEL_LENGTH || @@ -164,7 +163,7 @@ export function getAppModelOptions( // see the user's authored custom models. const defaultInstanceId = defaultInstanceIdForDriver(provider); const customModels = readInstanceCustomModels(settings, defaultInstanceId, provider); - for (const slug of normalizeCustomModelSlugs(customModels, builtInModelSlugs, provider)) { + for (const slug of normalizeCustomModelSlugs(customModels, builtInModelSlugs)) { if (seen.has(slug)) { continue; } @@ -207,8 +206,7 @@ export function getAppModelOptionsForInstance( ); const customModels = readInstanceCustomModels(settings, entry.instanceId, entry.driverKind); - const normalizer = entry.driverKind; - for (const slug of normalizeCustomModelSlugs(customModels, builtInModelSlugs, normalizer)) { + for (const slug of normalizeCustomModelSlugs(customModels, builtInModelSlugs)) { if (seen.has(slug)) { continue; } diff --git a/apps/web/src/projectScripts.test.ts b/apps/web/src/projectScripts.test.ts index 3597b714c77b..1f7a6bfaa9ff 100644 --- a/apps/web/src/projectScripts.test.ts +++ b/apps/web/src/projectScripts.test.ts @@ -6,6 +6,7 @@ import { } from "@t3tools/shared/projectScripts"; import { + buildProjectScript, commandForProjectScript, nextProjectScriptId, primaryProjectScript, @@ -13,6 +14,46 @@ import { } from "./projectScripts"; describe("projectScripts helpers", () => { + it("builds scripts with preview settings", () => { + expect( + buildProjectScript("dev", { + name: "Dev server", + command: "pnpm dev", + icon: "debug", + runOnWorktreeCreate: false, + previewUrl: "http://localhost:5733", + autoOpenPreview: true, + }), + ).toEqual({ + id: "dev", + name: "Dev server", + command: "pnpm dev", + icon: "debug", + runOnWorktreeCreate: false, + previewUrl: "http://localhost:5733", + autoOpenPreview: true, + }); + }); + + it("omits preview settings when no preview URL is configured", () => { + expect( + buildProjectScript("test", { + name: "Test", + command: "pnpm test", + icon: "test", + runOnWorktreeCreate: false, + previewUrl: null, + autoOpenPreview: false, + }), + ).toEqual({ + id: "test", + name: "Test", + command: "pnpm test", + icon: "test", + runOnWorktreeCreate: false, + }); + }); + it("builds and parses script run commands", () => { const command = commandForProjectScript("lint"); expect(command).toBe("script.lint.run"); diff --git a/apps/web/src/projectScripts.ts b/apps/web/src/projectScripts.ts index f0aeead14118..e3efc9e3a334 100644 --- a/apps/web/src/projectScripts.ts +++ b/apps/web/src/projectScripts.ts @@ -7,6 +7,31 @@ import { import * as Schema from "effect/Schema"; const isScriptRunCommand = Schema.is(SCRIPT_RUN_COMMAND_PATTERN); +export interface ProjectScriptInput { + readonly name: ProjectScript["name"]; + readonly command: ProjectScript["command"]; + readonly icon: ProjectScript["icon"]; + readonly runOnWorktreeCreate: ProjectScript["runOnWorktreeCreate"]; + readonly previewUrl: Exclude | null; + readonly autoOpenPreview: boolean; +} + +export function buildProjectScript(id: string, input: ProjectScriptInput): ProjectScript { + return { + id, + name: input.name, + command: input.command, + icon: input.icon, + runOnWorktreeCreate: input.runOnWorktreeCreate, + ...(input.previewUrl === null + ? {} + : { + previewUrl: input.previewUrl, + autoOpenPreview: input.autoOpenPreview, + }), + }; +} + function normalizeScriptId(value: string): string { const cleaned = value .trim() diff --git a/packages/client-runtime/src/rpc/client.ts b/packages/client-runtime/src/rpc/client.ts index 92892431e450..c7c928b3c954 100644 --- a/packages/client-runtime/src/rpc/client.ts +++ b/packages/client-runtime/src/rpc/client.ts @@ -11,6 +11,7 @@ import { RpcClientError } from "effect/unstable/rpc"; import { EnvironmentSupervisor } from "../connection/supervisor.ts"; import type { WsRpcProtocolClient } from "../rpc/protocol.ts"; +import type { RpcSession } from "../rpc/session.ts"; export class EnvironmentRpcUnavailableError extends Schema.TaggedErrorClass()( "EnvironmentRpcUnavailableError", @@ -147,15 +148,18 @@ export function runStream( ); } -export function subscribe( +interface SubscriptionOptions { + readonly onExpectedFailure?: ( + cause: Cause.Cause>, + ) => Effect.Effect; + readonly retryExpectedFailureAfter?: Duration.Input; + readonly resubscribe?: Stream.Stream; +} + +export function subscribeDynamic( tag: TTag, - input: EnvironmentRpcInput, - options?: { - readonly onExpectedFailure?: ( - cause: Cause.Cause>, - ) => Effect.Effect; - readonly retryExpectedFailureAfter?: Duration.Input; - }, + makeInput: (session: RpcSession) => Effect.Effect>, + options?: SubscriptionOptions, ): Stream.Stream< EnvironmentRpcStreamValue, EnvironmentRpcStreamFailure, @@ -163,8 +167,18 @@ export function subscribe( > { return Stream.unwrap( EnvironmentSupervisor.pipe( - Effect.map((supervisor) => - SubscriptionRef.changes(supervisor.session).pipe( + Effect.map((supervisor) => { + const sessionChanges = SubscriptionRef.changes(supervisor.session); + const sessions = + options?.resubscribe === undefined + ? sessionChanges + : Stream.merge( + sessionChanges, + options.resubscribe.pipe( + Stream.mapEffect(() => SubscriptionRef.get(supervisor.session)), + ), + ); + return sessions.pipe( Stream.switchMap( Option.match({ onNone: () => Stream.empty, @@ -180,54 +194,64 @@ export function subscribe( EnvironmentRpcStreamFailure > => Stream.suspend(() => - method(input).pipe( - Stream.catchCause((cause) => { - const hasOnlyExpectedFailures = - cause.reasons.length > 0 && - cause.reasons.every((reason) => reason._tag === "Fail"); - const isTransportFailure = - hasOnlyExpectedFailures && - cause.reasons.every( - (reason) => reason._tag === "Fail" && isRpcClientError(reason.error), - ); - if (isTransportFailure) { - return Stream.fromEffect( - Effect.logWarning( - "Durable RPC subscription lost its transport; waiting for the next session.", - { - cause: Cause.pretty(cause), - method: tag, - environmentId: supervisor.target.environmentId, - }, - ), - ).pipe(Stream.drain); - } - if (hasOnlyExpectedFailures && options?.onExpectedFailure !== undefined) { - const handled = Stream.fromEffect(options.onExpectedFailure(cause)).pipe( - Stream.drain, - ); - if (options.retryExpectedFailureAfter === undefined) { - return handled; - } - return handled.pipe( - Stream.concat( - Stream.fromEffect( - Effect.sleep(options.retryExpectedFailureAfter), - ).pipe(Stream.drain), - ), - Stream.concat(subscribeToSession()), - ); - } - return Stream.failCause(cause); - }), + Stream.unwrap( + makeInput(session).pipe( + Effect.map((input) => + method(input).pipe( + Stream.catchCause((cause) => { + const hasOnlyExpectedFailures = + cause.reasons.length > 0 && + cause.reasons.every((reason) => reason._tag === "Fail"); + const isTransportFailure = + hasOnlyExpectedFailures && + cause.reasons.every( + (reason) => + reason._tag === "Fail" && isRpcClientError(reason.error), + ); + if (isTransportFailure) { + return Stream.fromEffect( + Effect.logWarning( + "Durable RPC subscription lost its transport; waiting for the next session.", + { + cause: Cause.pretty(cause), + method: tag, + environmentId: supervisor.target.environmentId, + }, + ), + ).pipe(Stream.drain); + } + if ( + hasOnlyExpectedFailures && + options?.onExpectedFailure !== undefined + ) { + const handled = Stream.fromEffect( + options.onExpectedFailure(cause), + ).pipe(Stream.drain); + if (options.retryExpectedFailureAfter === undefined) { + return handled; + } + return handled.pipe( + Stream.concat( + Stream.fromEffect( + Effect.sleep(options.retryExpectedFailureAfter), + ).pipe(Stream.drain), + ), + Stream.concat(subscribeToSession()), + ); + } + return Stream.failCause(cause); + }), + ), + ), + ), ), ); return subscribeToSession(); }, }), ), - ), - ), + ); + }), ), ).pipe( Stream.withSpan("EnvironmentRpc.subscribe", { @@ -236,6 +260,18 @@ export function subscribe( ); } +export function subscribe( + tag: TTag, + input: EnvironmentRpcInput, + options?: SubscriptionOptions, +): Stream.Stream< + EnvironmentRpcStreamValue, + EnvironmentRpcStreamFailure, + EnvironmentSupervisor +> { + return subscribeDynamic(tag, () => Effect.succeed(input), options); +} + export const config = Effect.gen(function* () { const session = yield* currentSession(); return yield* session.initialConfig; diff --git a/packages/client-runtime/src/state/shell-sync.test.ts b/packages/client-runtime/src/state/shell-sync.test.ts index b6eb4e9f7105..a4514d5f0e63 100644 --- a/packages/client-runtime/src/state/shell-sync.test.ts +++ b/packages/client-runtime/src/state/shell-sync.test.ts @@ -8,6 +8,7 @@ import { describe, expect, it } from "@effect/vitest"; import * as Effect from "effect/Effect"; import * as Option from "effect/Option"; import * as Queue from "effect/Queue"; +import * as Ref from "effect/Ref"; import * as Stream from "effect/Stream"; import * as SubscriptionRef from "effect/SubscriptionRef"; @@ -17,6 +18,7 @@ import { type PreparedConnection, } from "../connection/model.ts"; import * as EnvironmentSupervisor from "../connection/supervisor.ts"; +import * as ConnectionWakeups from "../connection/wakeups.ts"; import * as Persistence from "../platform/persistence.ts"; import * as RpcSession from "../rpc/session.ts"; import type { WsRpcProtocolClient } from "../rpc/protocol.ts"; @@ -48,7 +50,7 @@ const LIVE_SHELL_SNAPSHOT: OrchestrationShellSnapshot = { function session(client: WsRpcProtocolClient): RpcSession.RpcSession { return { client, - initialConfig: Effect.never, + initialConfig: Effect.succeed({ shellResumeCompletionMarker: true } as never), ready: Effect.void, probe: Effect.void, closed: Effect.never, @@ -112,6 +114,15 @@ describe("environment shell synchronization", () => { kind: "snapshot", snapshot: LIVE_SHELL_SNAPSHOT, }); + const synchronizing = yield* SubscriptionRef.changes(shellState).pipe( + Stream.filter((state) => state.status === "synchronizing" && Option.isSome(state.snapshot)), + Stream.runHead, + ); + expect(Option.getOrThrow(Option.getOrThrow(synchronizing).snapshot)).toEqual( + LIVE_SHELL_SNAPSHOT, + ); + + yield* Queue.offer(events, { kind: "synchronized" }); yield* SubscriptionRef.changes(shellState).pipe( Stream.filter((state) => state.status === "live"), Stream.runHead, @@ -137,21 +148,32 @@ describe("environment shell synchronization", () => { }), ); - it.effect("resumes a warm shell cache via afterSequence without an HTTP fetch", () => + it.effect("replaces a warm shell cache with an authoritative HTTP snapshot", () => Effect.gen(function* () { const cachedSnapshot: OrchestrationShellSnapshot = { snapshotSequence: 5, projects: [], - threads: [], + threads: [{ id: "stale-thread" } as never], updatedAt: "2026-06-06T00:00:00.000Z", }; + const httpSnapshot: OrchestrationShellSnapshot = { + ...cachedSnapshot, + snapshotSequence: 9, + threads: [], + updatedAt: "2026-06-07T00:00:00.000Z", + }; const events = yield* Queue.unbounded(); const capturedAfterSequence = yield* SubscriptionRef.make(undefined); + const capturedCompletionMarker = yield* Ref.make(undefined); const loaderCalls = yield* SubscriptionRef.make(0); const client = { - [ORCHESTRATION_WS_METHODS.subscribeShell]: (input: { readonly afterSequence?: number }) => + [ORCHESTRATION_WS_METHODS.subscribeShell]: (input: { + readonly afterSequence?: number; + readonly requestCompletionMarker?: boolean; + }) => Stream.unwrap( - SubscriptionRef.set(capturedAfterSequence, input.afterSequence).pipe( + Ref.set(capturedCompletionMarker, input.requestCompletionMarker).pipe( + Effect.andThen(SubscriptionRef.set(capturedAfterSequence, input.afterSequence)), Effect.as(Stream.fromQueue(events)), ), ), @@ -183,9 +205,11 @@ describe("environment shell synchronization", () => { }); const snapshotLoader = ShellSnapshotLoader.of({ load: () => - SubscriptionRef.update(loaderCalls, (count) => count + 1).pipe(Effect.as(Option.none())), + SubscriptionRef.update(loaderCalls, (count) => count + 1).pipe( + Effect.as(Option.some(httpSnapshot)), + ), }); - yield* makeEnvironmentShellState().pipe( + const shellState = yield* makeEnvironmentShellState().pipe( Effect.provideService(EnvironmentSupervisor.EnvironmentSupervisor, supervisor), Effect.provideService(Persistence.EnvironmentCacheStore, cache), Effect.provideService(ShellSnapshotLoader, snapshotLoader), @@ -197,8 +221,108 @@ describe("environment shell synchronization", () => { Stream.runHead, ); - expect(yield* SubscriptionRef.get(capturedAfterSequence)).toBe(5); - expect(yield* SubscriptionRef.get(loaderCalls)).toBe(0); + expect(yield* SubscriptionRef.get(capturedAfterSequence)).toBe(9); + expect(yield* Ref.get(capturedCompletionMarker)).toBe(true); + expect(yield* SubscriptionRef.get(loaderCalls)).toBe(1); + const synchronizing = yield* SubscriptionRef.get(shellState); + expect(synchronizing.status).toBe("synchronizing"); + expect(Option.getOrThrow(synchronizing.snapshot)).toEqual(httpSnapshot); + + yield* Queue.offer(events, { kind: "synchronized" }); + yield* SubscriptionRef.changes(shellState).pipe( + Stream.filter((value) => value.status === "live"), + Stream.runHead, + ); + }), + ); + + it.effect("refreshes the authoritative shell snapshot when the app becomes active", () => + Effect.gen(function* () { + const events = yield* Queue.unbounded(); + const wakeups = yield* Queue.unbounded(); + const loaderCalls = yield* Ref.make(0); + const subscriptionCount = yield* Ref.make(0); + const client = { + [ORCHESTRATION_WS_METHODS.subscribeShell]: () => + Stream.unwrap( + Ref.update(subscriptionCount, (count) => count + 1).pipe( + Effect.as(Stream.fromQueue(events)), + ), + ), + } as unknown as WsRpcProtocolClient; + const supervisorState = yield* SubscriptionRef.make(AVAILABLE_CONNECTION_STATE); + const supervisor = EnvironmentSupervisor.EnvironmentSupervisor.of({ + target: TARGET, + state: supervisorState, + session: yield* SubscriptionRef.make(Option.some(session(client))), + prepared: yield* SubscriptionRef.make(Option.some(PREPARED)), + connect: Effect.void, + disconnect: Effect.void, + retryNow: Effect.void, + } satisfies EnvironmentSupervisor.EnvironmentSupervisor["Service"]); + const cache = Persistence.EnvironmentCacheStore.of({ + loadShell: () => Effect.succeed(Option.some(LIVE_SHELL_SNAPSHOT)), + saveShell: () => Effect.void, + loadThread: () => Effect.succeed(Option.none()), + saveThread: () => Effect.void, + removeThread: () => Effect.void, + loadServerConfig: () => Effect.succeed(Option.none()), + saveServerConfig: () => Effect.void, + loadVcsRefs: () => Effect.succeed(Option.none()), + saveVcsRefs: () => Effect.void, + clear: () => Effect.void, + }); + const snapshotLoader = ShellSnapshotLoader.of({ + load: () => + Ref.updateAndGet(loaderCalls, (count) => count + 1).pipe( + Effect.map((count) => + Option.some({ ...LIVE_SHELL_SNAPSHOT, snapshotSequence: count * 10 }), + ), + ), + }); + const shellState = yield* makeEnvironmentShellState().pipe( + Effect.provideService(EnvironmentSupervisor.EnvironmentSupervisor, supervisor), + Effect.provideService(Persistence.EnvironmentCacheStore, cache), + Effect.provideService(ShellSnapshotLoader, snapshotLoader), + Effect.provideService( + ConnectionWakeups.ConnectionWakeups, + ConnectionWakeups.ConnectionWakeups.of({ changes: Stream.fromQueue(wakeups) }), + ), + ); + + yield* SubscriptionRef.changes(shellState).pipe( + Stream.filter( + (value) => + value.status === "synchronizing" && + Option.isSome(value.snapshot) && + value.snapshot.value.snapshotSequence === 10, + ), + Stream.runHead, + ); + yield* Queue.offer(events, { kind: "synchronized" }); + yield* SubscriptionRef.changes(shellState).pipe( + Stream.filter((value) => value.status === "live"), + Stream.runHead, + ); + + yield* Queue.offer(wakeups, "application-active"); + yield* SubscriptionRef.changes(shellState).pipe( + Stream.filter( + (value) => + value.status === "synchronizing" && + Option.isSome(value.snapshot) && + value.snapshot.value.snapshotSequence === 20, + ), + Stream.runHead, + ); + + for (let attempt = 0; attempt < 100; attempt += 1) { + if ((yield* Ref.get(subscriptionCount)) >= 2) break; + yield* Effect.yieldNow; + } + + expect(yield* Ref.get(loaderCalls)).toBe(2); + expect(yield* Ref.get(subscriptionCount)).toBe(2); }), ); }); diff --git a/packages/client-runtime/src/state/shell.ts b/packages/client-runtime/src/state/shell.ts index e6ff3ae3c23a..6ccb11797f53 100644 --- a/packages/client-runtime/src/state/shell.ts +++ b/packages/client-runtime/src/state/shell.ts @@ -9,6 +9,7 @@ import * as Cause from "effect/Cause"; import * as Effect from "effect/Effect"; import * as Option from "effect/Option"; import * as Queue from "effect/Queue"; +import * as Ref from "effect/Ref"; import * as Stream from "effect/Stream"; import * as SubscriptionRef from "effect/SubscriptionRef"; import { AsyncResult, Atom } from "effect/unstable/reactivity"; @@ -16,9 +17,10 @@ import { AsyncResult, Atom } from "effect/unstable/reactivity"; import { EnvironmentRegistry } from "../connection/registry.ts"; import { connectionProjectionPhase } from "../connection/model.ts"; import { EnvironmentSupervisor } from "../connection/supervisor.ts"; +import * as ConnectionWakeups from "../connection/wakeups.ts"; import { safeErrorLogAttributes } from "../errors/safeLog.ts"; import { EnvironmentCacheStore } from "../platform/persistence.ts"; -import { subscribe } from "../rpc/client.ts"; +import { subscribeDynamic } from "../rpc/client.ts"; import { ShellSnapshotLoader } from "./shellSnapshotHttp.ts"; import { applyShellStreamEvent } from "./shellReducer.ts"; import type { EnvironmentCatalogState } from "./connections.ts"; @@ -50,6 +52,7 @@ export const makeEnvironmentShellState = Effect.fn("EnvironmentShellState.make") const supervisor = yield* EnvironmentSupervisor; const cache = yield* EnvironmentCacheStore; const snapshotLoader = yield* ShellSnapshotLoader; + const wakeups = yield* Effect.serviceOption(ConnectionWakeups.ConnectionWakeups); const environmentId = supervisor.target.environmentId; const cachedSnapshot = yield* cache.loadShell(environmentId).pipe( Effect.catch((error) => @@ -67,6 +70,7 @@ export const makeEnvironmentShellState = Effect.fn("EnvironmentShellState.make") status: shellStatusForSnapshot(cachedSnapshot), error: Option.none(), }); + const awaitingCompletion = yield* Ref.make(false); const persistence = yield* Queue.sliding(1); const persist = Effect.fn("EnvironmentShellState.persist")(function* ( @@ -90,10 +94,14 @@ export const makeEnvironmentShellState = Effect.fn("EnvironmentShellState.make") Effect.forkScoped, ); - const setDisconnected = SubscriptionRef.update(state, (current) => ({ - ...current, - status: shellStatusForSnapshot(current.snapshot), - })); + const setDisconnected = Ref.set(awaitingCompletion, false).pipe( + Effect.andThen( + SubscriptionRef.update(state, (current) => ({ + ...current, + status: shellStatusForSnapshot(current.snapshot), + })), + ), + ); const setSynchronizing = SubscriptionRef.update(state, (current) => ({ ...current, status: "synchronizing" as const, @@ -102,12 +110,15 @@ export const makeEnvironmentShellState = Effect.fn("EnvironmentShellState.make") const setReady = SubscriptionRef.update(state, (current) => current.status === "live" ? current - : current.status === "synchronizing" && Option.isSome(current.snapshot) - ? { ...current, status: "live" as const, error: Option.none() } - : { ...current, status: "synchronizing" as const, error: Option.none() }, + : { + ...current, + status: "synchronizing" as const, + error: Option.none(), + }, ); const setStreamError = (error: unknown) => - Effect.logWarning("Could not synchronize the environment shell.").pipe( + Ref.set(awaitingCompletion, false).pipe( + Effect.andThen(Effect.logWarning("Could not synchronize the environment shell.")), Effect.annotateLogs({ environmentId, ...safeErrorLogAttributes(error), @@ -124,6 +135,16 @@ export const makeEnvironmentShellState = Effect.fn("EnvironmentShellState.make") const applyItem = Effect.fn("EnvironmentShellState.applyItem")(function* ( item: OrchestrationShellStreamItem, ) { + if (item.kind === "synchronized") { + yield* Ref.set(awaitingCompletion, false); + yield* SubscriptionRef.update(state, (current) => + Option.isSome(current.snapshot) + ? { ...current, status: "live" as const, error: Option.none() } + : current, + ); + return; + } + const current = yield* SubscriptionRef.get(state); const nextSnapshot = item.kind === "snapshot" @@ -139,60 +160,64 @@ export const makeEnvironmentShellState = Effect.fn("EnvironmentShellState.make") return; } + const waiting = yield* Ref.get(awaitingCompletion); yield* SubscriptionRef.set(state, { snapshot: Option.some(nextSnapshot), - status: "live", + status: waiting ? "synchronizing" : "live", error: Option.none(), }); yield* Queue.offer(persistence, nextSnapshot); }); - yield* Effect.forkScoped( - Effect.gen(function* () { - // Establish the base shell snapshot to resume from, minimizing bytes over - // the wire: - // - Warm cache: reuse the cached snapshot (zero network) and resume via - // `afterSequence` so we only receive shell events since the cached - // sequence. - // - Cold cache: load the full shell snapshot over HTTP (gzip-compressible, - // and off the socket), then resume via `afterSequence`. - // If no base can be established we fall back to the socket-embedded - // snapshot so the shell still synchronizes. Overlapping/replayed events are - // deduped by sequence in applyItem. - const base = Option.isSome(cachedSnapshot) - ? cachedSnapshot - : yield* Effect.gen(function* () { - const prepared = yield* SubscriptionRef.changes(supervisor.prepared).pipe( - Stream.filter(Option.isSome), - Stream.map((current) => current.value), - Stream.runHead, - ); - return Option.isSome(prepared) - ? yield* snapshotLoader.load(prepared.value) - : Option.none(); - }); + const foregroundResubscriptions = Option.match(wakeups, { + onNone: () => Stream.never, + onSome: (service) => + service.changes.pipe(Stream.filter((reason) => reason === "application-active")), + }); - if (Option.isSome(base)) { - // Apply the base snapshot while keeping status at "synchronizing" — the - // socket subscribe/catch-up hasn't attached yet so marking "live" here - // would be premature (setReady promotes to "live" once the connection is ready). - yield* SubscriptionRef.set(state, { - snapshot: Option.some(base.value), - status: "synchronizing", - error: Option.none(), - }); - yield* Queue.offer(persistence, base.value); - } + yield* setSynchronizing; + yield* Effect.forkScoped( + subscribeDynamic( + ORCHESTRATION_WS_METHODS.subscribeShell, + Effect.fn("EnvironmentShellState.makeSubscribeInput")(function* (session) { + const supportsCompletionMarker = yield* session.initialConfig.pipe( + Effect.map((config) => config.shellResumeCompletionMarker === true), + Effect.orElseSucceed(() => false), + ); + yield* Ref.set(awaitingCompletion, supportsCompletionMarker); + yield* setSynchronizing; - const subscribeInput = Option.match(base, { - onNone: () => ({}), - onSome: (snapshot) => ({ afterSequence: snapshot.snapshotSequence }), - }); + const prepared = yield* SubscriptionRef.get(supervisor.prepared).pipe( + Effect.flatMap( + Option.match({ + onSome: Effect.succeed, + onNone: () => + SubscriptionRef.changes(supervisor.prepared).pipe( + Stream.filter(Option.isSome), + Stream.map((value) => value.value), + Stream.runHead, + Effect.map(Option.getOrThrow), + ), + }), + ), + ); + const httpSnapshot = yield* snapshotLoader.load(prepared); + if (Option.isSome(httpSnapshot)) { + yield* applyItem({ kind: "snapshot", snapshot: httpSnapshot.value }); + return { + afterSequence: httpSnapshot.value.snapshotSequence, + ...(supportsCompletionMarker ? { requestCompletionMarker: true as const } : {}), + }; + } - yield* subscribe(ORCHESTRATION_WS_METHODS.subscribeShell, subscribeInput, { + return supportsCompletionMarker ? { requestCompletionMarker: true as const } : {}; + }), + { onExpectedFailure: (cause) => setStreamError(Cause.squash(cause)), - }).pipe(Stream.runForEach(applyItem)); - }), + retryExpectedFailureAfter: "250 millis", + resubscribe: foregroundResubscriptions, + }, + ).pipe(Stream.runForEach(applyItem)), ); yield* SubscriptionRef.changes(supervisor.state).pipe( Stream.runForEach((connectionState) => { diff --git a/packages/client-runtime/src/state/threads-sync.test.ts b/packages/client-runtime/src/state/threads-sync.test.ts index ea8ce6d30dab..a6102465dfd3 100644 --- a/packages/client-runtime/src/state/threads-sync.test.ts +++ b/packages/client-runtime/src/state/threads-sync.test.ts @@ -26,6 +26,7 @@ import { type PreparedConnection, type SupervisorConnectionState, } from "../connection/model.ts"; +import * as ConnectionWakeups from "../connection/wakeups.ts"; import * as EnvironmentSupervisor from "../connection/supervisor.ts"; import * as Persistence from "../platform/persistence.ts"; import * as RpcSession from "../rpc/session.ts"; @@ -98,10 +99,17 @@ const ACTIVE_THREAD: OrchestrationThread = { type TestThreadInput = OrchestrationThreadStreamItem | Error; -function testSession(client: WsRpcProtocolClient): RpcSession.RpcSession { +function testSession( + client: WsRpcProtocolClient, + options?: { readonly completionMarker?: boolean }, +): RpcSession.RpcSession { return { client, - initialConfig: Effect.never, + initialConfig: Effect.succeed( + options?.completionMarker === true + ? ({ threadResumeCompletionMarker: true } as never) + : ({} as never), + ), ready: Effect.void, probe: Effect.void, closed: Effect.never, @@ -122,6 +130,7 @@ function awaitThreadState( const makeHarness = Effect.fn("TestEnvironmentThreads.makeHarness")(function* (options?: { readonly cached?: OrchestrationThread; readonly httpSnapshot?: Option.Option; + readonly completionMarker?: boolean; }) { const inputs = yield* Queue.unbounded(); const observed = yield* Queue.unbounded(); @@ -130,8 +139,10 @@ const makeHarness = Effect.fn("TestEnvironmentThreads.makeHarness")(function* (o const subscriptionCount = yield* Ref.make(0); const loaderCalls = yield* Ref.make(0); const lastSubscribeAfterSequence = yield* Ref.make(undefined); + const lastRequestCompletionMarker = yield* Ref.make(undefined); const savedThreads = yield* Ref.make>([]); const removedThreads = yield* Ref.make>([]); + const wakeups = yield* Queue.unbounded(); const supervisorState = yield* SubscriptionRef.make( AVAILABLE_CONNECTION_STATE, ); @@ -142,16 +153,25 @@ const makeHarness = Effect.fn("TestEnvironmentThreads.makeHarness")(function* (o ), ); const client = { - [ORCHESTRATION_WS_METHODS.subscribeThread]: (input: { readonly afterSequence?: number }) => + [ORCHESTRATION_WS_METHODS.subscribeThread]: (input: { + readonly afterSequence?: number; + readonly requestCompletionMarker?: boolean; + }) => Stream.unwrap( Ref.updateAndGet(subscriptionCount, (count) => count + 1).pipe( Effect.andThen(Ref.set(lastSubscribeAfterSequence, input.afterSequence)), + Effect.andThen(Ref.set(lastRequestCompletionMarker, input.requestCompletionMarker)), Effect.as(streamFrom(inputs)), ), ), } as unknown as WsRpcProtocolClient; const supervisorSession = yield* SubscriptionRef.make>( - Option.some(testSession(client)), + Option.some( + testSession( + client, + options?.completionMarker === true ? { completionMarker: true } : undefined, + ), + ), ); const prepared = yield* SubscriptionRef.make>( Option.some(PREPARED), @@ -201,6 +221,10 @@ const makeHarness = Effect.fn("TestEnvironmentThreads.makeHarness")(function* (o Effect.provideService(EnvironmentSupervisor.EnvironmentSupervisor, supervisor), Effect.provideService(Persistence.EnvironmentCacheStore, cache), Effect.provideService(ThreadSnapshotLoader, snapshotLoader), + Effect.provideService( + ConnectionWakeups.ConnectionWakeups, + ConnectionWakeups.ConnectionWakeups.of({ changes: Stream.fromQueue(wakeups) }), + ), ); yield* SubscriptionRef.changes(threadState).pipe( Stream.runForEach((state) => @@ -217,11 +241,21 @@ const makeHarness = Effect.fn("TestEnvironmentThreads.makeHarness")(function* (o subscriptionCount, loaderCalls, lastSubscribeAfterSequence, + lastRequestCompletionMarker, supervisorState, supervisorSession, savedThreads, removedThreads, - replaceSession: SubscriptionRef.set(supervisorSession, Option.some(testSession(client))), + wakeups, + replaceSession: SubscriptionRef.set( + supervisorSession, + Option.some( + testSession( + client, + options?.completionMarker === true ? { completionMarker: true } : undefined, + ), + ), + ), }; }); @@ -233,6 +267,8 @@ const snapshot = (thread: OrchestrationThread): OrchestrationThreadStreamItem => }, }); +const synchronized = (): OrchestrationThreadStreamItem => ({ kind: "synchronized" }); + const titleUpdated = (title: string, sequence = 2): OrchestrationThreadStreamItem => ({ kind: "event", event: { @@ -418,6 +454,35 @@ describe("EnvironmentThreads", () => { }), ); + it.effect("does not resurrect a deleted thread when the app returns to the foreground", () => + Effect.gen(function* () { + const harness = yield* makeHarness({ + cached: BASE_THREAD, + completionMarker: true, + httpSnapshot: Option.some({ + snapshotSequence: 4, + thread: { ...BASE_THREAD, title: "Stale HTTP thread" }, + }), + }); + yield* Queue.offer(harness.inputs, snapshot(BASE_THREAD)); + yield* Queue.offer(harness.inputs, deleted()); + yield* awaitThreadState(harness.observed, (value) => value.status === "deleted"); + + expect(yield* Ref.get(harness.loaderCalls)).toBe(0); + yield* Queue.offer(harness.wakeups, "application-active"); + for (let attempt = 0; attempt < 100; attempt += 1) { + if ((yield* Ref.get(harness.subscriptionCount)) >= 2) break; + yield* Effect.yieldNow; + } + + const latest = yield* Ref.get(harness.latest); + expect(yield* Ref.get(harness.subscriptionCount)).toBe(2); + expect(yield* Ref.get(harness.loaderCalls)).toBe(0); + expect(latest.status).toBe("deleted"); + expect(Option.isNone(latest.data)).toBe(true); + }), + ); + it.effect("preserves data after a domain failure and resumes on a replacement session", () => Effect.gen(function* () { const harness = yield* makeHarness({ cached: BASE_THREAD }); @@ -532,4 +597,104 @@ describe("EnvironmentThreads", () => { expect((yield* Ref.get(harness.latest)).status).toBe("live"); }), ); + + it.effect("keeps replayed updates synchronizing until the completion marker arrives", () => + Effect.gen(function* () { + const harness = yield* makeHarness({ cached: BASE_THREAD, completionMarker: true }); + yield* awaitThreadState( + harness.observed, + (value) => value.status === "synchronizing" && Option.isSome(value.data), + ); + expect(yield* Ref.get(harness.lastRequestCompletionMarker)).toBe(true); + + yield* Queue.offer( + harness.inputs, + titleUpdated("Caught-up title", CACHED_SNAPSHOT_SEQUENCE + 1), + ); + const catchingUp = yield* awaitThreadState( + harness.observed, + (value) => + value.status === "synchronizing" && + Option.isSome(value.data) && + value.data.value.title === "Caught-up title", + ); + expect(catchingUp.status).toBe("synchronizing"); + + yield* Queue.offer(harness.inputs, synchronized()); + const live = yield* awaitThreadState( + harness.observed, + (value) => value.status === "live" && Option.isSome(value.data), + ); + expect(Option.getOrThrow(live.data).title).toBe("Caught-up title"); + }), + ); + + it.effect("resumes replacement sessions from the latest applied sequence", () => + Effect.gen(function* () { + const harness = yield* makeHarness({ cached: BASE_THREAD, completionMarker: true }); + yield* Queue.offer( + harness.inputs, + titleUpdated("Latest title", CACHED_SNAPSHOT_SEQUENCE + 1), + ); + yield* Queue.offer(harness.inputs, synchronized()); + yield* awaitThreadState( + harness.observed, + (value) => + value.status === "live" && + Option.isSome(value.data) && + value.data.value.title === "Latest title", + ); + + yield* harness.replaceSession; + for (let attempt = 0; attempt < 100; attempt += 1) { + if ((yield* Ref.get(harness.subscriptionCount)) >= 2) break; + yield* Effect.yieldNow; + } + + expect(yield* Ref.get(harness.subscriptionCount)).toBe(2); + expect(yield* Ref.get(harness.lastSubscribeAfterSequence)).toBe(CACHED_SNAPSHOT_SEQUENCE + 1); + expect((yield* Ref.get(harness.latest)).status).toBe("synchronizing"); + }), + ); + + it.effect("resubscribes on app foreground from the latest applied sequence", () => + Effect.gen(function* () { + const harness = yield* makeHarness({ cached: BASE_THREAD, completionMarker: true }); + yield* Queue.offer( + harness.inputs, + titleUpdated("Latest title", CACHED_SNAPSHOT_SEQUENCE + 1), + ); + yield* Queue.offer(harness.inputs, synchronized()); + yield* awaitThreadState( + harness.observed, + (value) => + value.status === "live" && + Option.isSome(value.data) && + value.data.value.title === "Latest title", + ); + + yield* Queue.offer(harness.wakeups, "application-active"); + const synchronizing = yield* awaitThreadState( + harness.observed, + (value) => value.status === "synchronizing" && Option.isSome(value.data), + ); + for (let attempt = 0; attempt < 100; attempt += 1) { + if ((yield* Ref.get(harness.subscriptionCount)) >= 2) break; + yield* Effect.yieldNow; + } + + expect(synchronizing.status).toBe("synchronizing"); + expect(yield* Ref.get(harness.subscriptionCount)).toBe(2); + expect(yield* Ref.get(harness.lastSubscribeAfterSequence)).toBe(CACHED_SNAPSHOT_SEQUENCE + 1); + expect(yield* Ref.get(harness.lastRequestCompletionMarker)).toBe(true); + expect(yield* Ref.get(harness.loaderCalls)).toBe(0); + + yield* Queue.offer(harness.inputs, synchronized()); + const live = yield* awaitThreadState( + harness.observed, + (value) => value.status === "live" && Option.isSome(value.data), + ); + expect(Option.getOrThrow(live.data).title).toBe("Latest title"); + }), + ); }); diff --git a/packages/client-runtime/src/state/threads.ts b/packages/client-runtime/src/state/threads.ts index 7830ca61c836..196229cc8b11 100644 --- a/packages/client-runtime/src/state/threads.ts +++ b/packages/client-runtime/src/state/threads.ts @@ -10,6 +10,7 @@ import * as Cause from "effect/Cause"; import * as Effect from "effect/Effect"; import * as Option from "effect/Option"; import * as Queue from "effect/Queue"; +import * as Ref from "effect/Ref"; import * as Stream from "effect/Stream"; import * as SubscriptionRef from "effect/SubscriptionRef"; import { Atom } from "effect/unstable/reactivity"; @@ -17,8 +18,9 @@ import { Atom } from "effect/unstable/reactivity"; import { EnvironmentRegistry } from "../connection/registry.ts"; import { connectionProjectionPhase } from "../connection/model.ts"; import { EnvironmentSupervisor } from "../connection/supervisor.ts"; +import * as ConnectionWakeups from "../connection/wakeups.ts"; import { EnvironmentCacheStore } from "../platform/persistence.ts"; -import { subscribe } from "../rpc/client.ts"; +import { subscribeDynamic } from "../rpc/client.ts"; import { ThreadSnapshotLoader } from "./threadSnapshotHttp.ts"; import { parseThreadKey, threadKey } from "./entities.ts"; import { applyThreadDetailEvent } from "./threadReducer.ts"; @@ -52,6 +54,7 @@ export const makeEnvironmentThreadState = Effect.fn("EnvironmentThreadState.make const supervisor = yield* EnvironmentSupervisor; const cache = yield* EnvironmentCacheStore; const snapshotLoader = yield* ThreadSnapshotLoader; + const wakeups = yield* Effect.serviceOption(ConnectionWakeups.ConnectionWakeups); const environmentId = supervisor.target.environmentId; const cached = yield* cache.loadThread(environmentId, threadId).pipe( Effect.catch((error) => @@ -76,6 +79,7 @@ export const makeEnvironmentThreadState = Effect.fn("EnvironmentThreadState.make const lastSequence = yield* SubscriptionRef.make( Option.match(cached, { onNone: () => 0, onSome: (snapshot) => snapshot.snapshotSequence }), ); + const awaitingCompletion = yield* Ref.make(false); const persistence = yield* Queue.sliding(1); const persist = Effect.fn("EnvironmentThreadState.persist")(function* ( @@ -100,35 +104,50 @@ export const makeEnvironmentThreadState = Effect.fn("EnvironmentThreadState.make Effect.forkScoped, ); - const setSynchronizing = SubscriptionRef.update(state, (current) => ({ - ...current, - status: "synchronizing" as const, - error: Option.none(), - })); + const setSynchronizing = SubscriptionRef.update(state, (current) => + current.status === "deleted" + ? current + : { + ...current, + status: "synchronizing" as const, + error: Option.none(), + }, + ); const setReady = SubscriptionRef.update(state, (current) => current.status === "live" || current.status === "deleted" ? current - : current.status === "synchronizing" && Option.isSome(current.data) - ? { ...current, status: "live" as const, error: Option.none() } - : { ...current, status: "synchronizing" as const, error: Option.none() }, + : { + ...current, + status: "synchronizing" as const, + error: Option.none(), + }, ); - const setDisconnected = SubscriptionRef.update(state, (current) => ({ - ...current, - status: current.status === "deleted" ? current.status : statusWithoutLiveData(current.data), - })); - const setStreamError = (cause: Cause.Cause) => - SubscriptionRef.update(state, (current) => ({ + const setDisconnected = Effect.gen(function* () { + yield* Ref.set(awaitingCompletion, false); + yield* SubscriptionRef.update(state, (current) => ({ ...current, status: current.status === "deleted" ? current.status : statusWithoutLiveData(current.data), - error: Option.some(formatThreadError(cause)), })); + }); + const setStreamError = (cause: Cause.Cause) => + Ref.set(awaitingCompletion, false).pipe( + Effect.andThen( + SubscriptionRef.update(state, (current) => ({ + ...current, + status: + current.status === "deleted" ? current.status : statusWithoutLiveData(current.data), + error: Option.some(formatThreadError(cause)), + })), + ), + ); const setThread = Effect.fn("EnvironmentThreadState.setThread")(function* ( thread: OrchestrationThread, ) { + const waiting = yield* Ref.get(awaitingCompletion); yield* SubscriptionRef.set(state, { data: Option.some(thread), - status: "live", + status: waiting ? "synchronizing" : "live", error: Option.none(), }); // Active threads can update many times per second and retain large tool @@ -141,6 +160,7 @@ export const makeEnvironmentThreadState = Effect.fn("EnvironmentThreadState.make }); const setDeleted = Effect.fn("EnvironmentThreadState.setDeleted")(function* () { + yield* Ref.set(awaitingCompletion, false); yield* SubscriptionRef.set(state, { data: Option.none(), status: "deleted", @@ -162,6 +182,16 @@ export const makeEnvironmentThreadState = Effect.fn("EnvironmentThreadState.make const applyItem = Effect.fn("EnvironmentThreadState.applyItem")(function* ( item: OrchestrationThreadStreamItem, ) { + if (item.kind === "synchronized") { + yield* Ref.set(awaitingCompletion, false); + yield* SubscriptionRef.update(state, (current) => + Option.isSome(current.data) && current.status !== "deleted" + ? { ...current, status: "live" as const, error: Option.none() } + : current, + ); + return; + } + if (item.kind === "snapshot") { yield* SubscriptionRef.set(lastSequence, item.snapshot.snapshotSequence); yield* setThread(item.snapshot.thread); @@ -203,60 +233,69 @@ export const makeEnvironmentThreadState = Effect.fn("EnvironmentThreadState.make Effect.forkScoped, ); + const foregroundResubscriptions = Option.match(wakeups, { + onNone: () => Stream.never, + onSome: (service) => + service.changes.pipe(Stream.filter((reason) => reason === "application-active")), + }); + yield* setSynchronizing; yield* Effect.forkScoped( - Effect.gen(function* () { - // Establish the base snapshot to resume from, minimizing bytes over the - // wire: - // - Warm cache: reuse the cached snapshot (zero network) and resume via - // `afterSequence` so we only receive events since the cached sequence. - // - Cold cache: load the full snapshot over HTTP (gzip-compressible, and - // off the socket), then resume via `afterSequence`. - // If no base can be established we fall back to the socket-embedded - // snapshot so the thread still synchronizes. Overlapping/replayed events - // are deduped by sequence in applyItem. - const base = Option.isSome(cached) - ? cached - : yield* Effect.gen(function* () { - // Cold cache only: wait for a prepared connection so we can - // authenticate the HTTP request; this mirrors the socket path, which - // likewise waits for a live session. - const prepared = yield* SubscriptionRef.changes(supervisor.prepared).pipe( - Stream.filter(Option.isSome), - Stream.map((current) => current.value), - Stream.runHead, - ); - return Option.isSome(prepared) - ? yield* snapshotLoader.load(prepared.value, threadId) - : Option.none(); - }); + subscribeDynamic( + ORCHESTRATION_WS_METHODS.subscribeThread, + Effect.fn("EnvironmentThreadState.makeSubscribeInput")(function* (session) { + const supportsCompletionMarker = yield* session.initialConfig.pipe( + Effect.map((config) => config.threadResumeCompletionMarker === true), + Effect.orElseSucceed(() => false), + ); + yield* Ref.set(awaitingCompletion, supportsCompletionMarker); + yield* setSynchronizing; - if (Option.isSome(base)) { - // Apply the base snapshot while keeping status at "synchronizing" — the - // socket subscribe/catch-up hasn't attached yet so marking "live" here - // would be premature (e.g. an offline deletion would never be seen). - yield* SubscriptionRef.set(lastSequence, base.value.snapshotSequence); - yield* SubscriptionRef.set(state, { - data: Option.some(base.value.thread), - status: "synchronizing", - error: Option.none(), - }); - // Match setThread/finalizer: skip cache rewrites while a turn is active. - if (shouldPersistThread(base.value.thread)) { - yield* Queue.offer(persistence, base.value); + let current = yield* SubscriptionRef.get(state); + if (Option.isNone(current.data) && current.status !== "deleted") { + const prepared = yield* SubscriptionRef.get(supervisor.prepared).pipe( + Effect.flatMap( + Option.match({ + onSome: Effect.succeed, + onNone: () => + SubscriptionRef.changes(supervisor.prepared).pipe( + Stream.filter(Option.isSome), + Stream.map((value) => value.value), + Stream.runHead, + Effect.map(Option.getOrThrow), + ), + }), + ), + ); + const httpSnapshot = yield* snapshotLoader.load(prepared, threadId); + if (Option.isSome(httpSnapshot)) { + yield* applyItem({ kind: "snapshot", snapshot: httpSnapshot.value }); + current = yield* SubscriptionRef.get(state); + } } - } - const subscribeInput = Option.match(base, { - onNone: () => ({ threadId }), - onSome: (snapshot) => ({ threadId, afterSequence: snapshot.snapshotSequence }), - }); + const sequence = yield* SubscriptionRef.get(lastSequence); + const canResume = Option.isSome(current.data); + if (!supportsCompletionMarker && canResume) { + yield* SubscriptionRef.update(state, (value) => ({ + ...value, + status: value.status === "deleted" ? value.status : ("live" as const), + error: Option.none(), + })); + } - yield* subscribe(ORCHESTRATION_WS_METHODS.subscribeThread, subscribeInput, { + return { + threadId, + ...(canResume ? { afterSequence: sequence } : {}), + ...(supportsCompletionMarker ? { requestCompletionMarker: true as const } : {}), + }; + }), + { onExpectedFailure: setStreamError, retryExpectedFailureAfter: "250 millis", - }).pipe(Stream.runForEach(applyItem)); - }), + resubscribe: foregroundResubscriptions, + }, + ).pipe(Stream.runForEach(applyItem)), ); yield* Effect.addFinalizer(() => diff --git a/packages/contracts/src/orchestration.ts b/packages/contracts/src/orchestration.ts index 491a88f8f2e5..f687aa5197b9 100644 --- a/packages/contracts/src/orchestration.ts +++ b/packages/contracts/src/orchestration.ts @@ -444,6 +444,9 @@ export const OrchestrationShellStreamEvent = Schema.Union([ export type OrchestrationShellStreamEvent = typeof OrchestrationShellStreamEvent.Type; export const OrchestrationShellStreamItem = Schema.Union([ + Schema.Struct({ + kind: Schema.Literal("synchronized"), + }), Schema.Struct({ kind: Schema.Literal("snapshot"), snapshot: OrchestrationShellSnapshot, @@ -462,6 +465,11 @@ export const OrchestrationSubscribeShellInput = Schema.Struct({ * client). */ afterSequence: Schema.optionalKey(NonNegativeInt), + /** + * Requests an explicit marker after the subscription has emitted its initial + * snapshot or catch-up replay and before it begins emitting live events. + */ + requestCompletionMarker: Schema.optionalKey(Schema.Boolean), }); export type OrchestrationSubscribeShellInput = typeof OrchestrationSubscribeShellInput.Type; @@ -475,6 +483,11 @@ export const OrchestrationSubscribeThreadInput = Schema.Struct({ * sequence on the client). */ afterSequence: Schema.optionalKey(NonNegativeInt), + /** + * Requests an explicit marker after the subscription has emitted its initial + * snapshot or catch-up replay and before it begins emitting live events. + */ + requestCompletionMarker: Schema.optionalKey(Schema.Boolean), }); export type OrchestrationSubscribeThreadInput = typeof OrchestrationSubscribeThreadInput.Type; @@ -1136,6 +1149,9 @@ export const OrchestrationEvent = Schema.Union([ export type OrchestrationEvent = typeof OrchestrationEvent.Type; export const OrchestrationThreadStreamItem = Schema.Union([ + Schema.Struct({ + kind: Schema.Literal("synchronized"), + }), Schema.Struct({ kind: Schema.Literal("snapshot"), snapshot: OrchestrationThreadDetailSnapshot, diff --git a/packages/contracts/src/server.ts b/packages/contracts/src/server.ts index b76ea965afe7..316f09693ecb 100644 --- a/packages/contracts/src/server.ts +++ b/packages/contracts/src/server.ts @@ -417,6 +417,10 @@ export const ServerConfig = Schema.Struct({ availableEditors: Schema.Array(EditorId), observability: ServerObservability, settings: ServerSettings, + /** Whether shell subscriptions can emit an opt-in catch-up completion marker. */ + shellResumeCompletionMarker: Schema.optionalKey(Schema.Boolean), + /** Whether thread subscriptions can emit an opt-in catch-up completion marker. */ + threadResumeCompletionMarker: Schema.optionalKey(Schema.Boolean), }); export type ServerConfig = typeof ServerConfig.Type; diff --git a/packages/contracts/src/settings.test.ts b/packages/contracts/src/settings.test.ts index ac2d47ca3365..0f618729c43e 100644 --- a/packages/contracts/src/settings.test.ts +++ b/packages/contracts/src/settings.test.ts @@ -141,6 +141,7 @@ describe("ServerSettingsPatch string normalization", () => { codex: { binaryPath: " /opt/homebrew/bin/codex ", homePath: " ~/.codex ", + launchArgs: " --strict-config --enable foo ", }, }, providerInstances: { @@ -157,6 +158,7 @@ describe("ServerSettingsPatch string normalization", () => { expect(patch.observability?.otlpTracesUrl).toBe("http://localhost:4318/v1/traces"); expect(patch.providers?.codex?.binaryPath).toBe("/opt/homebrew/bin/codex"); expect(patch.providers?.codex?.homePath).toBe("~/.codex"); + expect(patch.providers?.codex?.launchArgs).toBe("--strict-config --enable foo"); expect(patch.providerInstances?.[ProviderInstanceId.make("codex_personal")]?.driver).toBe( "codex", ); @@ -178,11 +180,13 @@ describe("ServerSettingsPatch string normalization", () => { codex: { ...defaultSettings.providers.codex, binaryPath: " /opt/homebrew/bin/codex ", + launchArgs: " --strict-config ", }, }, }); expect(encoded.addProjectBaseDirectory).toBe("~/Development"); expect(encoded.providers?.codex?.binaryPath).toBe("/opt/homebrew/bin/codex"); + expect(encoded.providers?.codex?.launchArgs).toBe("--strict-config"); }); }); diff --git a/packages/contracts/src/settings.ts b/packages/contracts/src/settings.ts index 9a1d10563d5a..bd3bbfb6410f 100644 --- a/packages/contracts/src/settings.ts +++ b/packages/contracts/src/settings.ts @@ -191,13 +191,20 @@ export const CodexSettings = makeProviderSettingsSchema( }, }), ), + launchArgs: TrimmedString.pipe( + Schema.withDecodingDefault(Effect.succeed("")), + Schema.annotateKey({ + title: "Launch arguments", + description: "Additional CLI arguments passed to codex app-server on session start.", + }), + ), customModels: Schema.Array(Schema.String).pipe( Schema.withDecodingDefault(Effect.succeed([])), Schema.annotateKey({ providerSettingsForm: { hidden: true } }), ), }, { - order: ["binaryPath", "homePath", "shadowHomePath"], + order: ["binaryPath", "homePath", "shadowHomePath", "launchArgs"], }, ); export type CodexSettings = typeof CodexSettings.Type; @@ -648,6 +655,7 @@ const CodexSettingsPatch = Schema.Struct({ binaryPath: Schema.optionalKey(TrimmedString), homePath: Schema.optionalKey(TrimmedString), shadowHomePath: Schema.optionalKey(TrimmedString), + launchArgs: Schema.optionalKey(TrimmedString), customModels: Schema.optionalKey(Schema.Array(Schema.String)), }); diff --git a/packages/effect-codex-app-server/scripts/generate.ts b/packages/effect-codex-app-server/scripts/generate.ts index 3deb45142924..9f23a144524d 100644 --- a/packages/effect-codex-app-server/scripts/generate.ts +++ b/packages/effect-codex-app-server/scripts/generate.ts @@ -17,7 +17,7 @@ import { } from "effect/unstable/http"; import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"; -const UPSTREAM_REF = "b39f943a634a6e7ba86c3d6e8cf6d5f35e612566"; +const UPSTREAM_REF = "678157acaa819d5510adfe359abb5d0392cfe461"; const USER_AGENT = "effect-codex-app-server-generator"; const GITHUB_API_BASE = "https://api.github.com/repos/openai/codex/contents/codex-rs/app-server-protocol"; @@ -349,10 +349,12 @@ function resolveResponseTypeName( "account/logout": "LogoutAccountResponse", "account/rateLimits/read": "GetAccountRateLimitsResponse", "account/usage/read": "GetAccountTokenUsageResponse", + "account/workspaceMessages/read": "GetWorkspaceMessagesResponse", "config/batchWrite": "ConfigWriteResponse", "config/mcpServer/reload": "McpServerRefreshResponse", "config/value/write": "ConfigWriteResponse", "configRequirements/read": "ConfigRequirementsReadResponse", + "externalAgentConfig/import/readHistories": "ExternalAgentConfigImportHistoriesReadResponse", }; const override = overrides[method]; diff --git a/packages/effect-codex-app-server/src/_generated/meta.gen.ts b/packages/effect-codex-app-server/src/_generated/meta.gen.ts index ed39896bdb99..24452e881f66 100644 --- a/packages/effect-codex-app-server/src/_generated/meta.gen.ts +++ b/packages/effect-codex-app-server/src/_generated/meta.gen.ts @@ -1,5 +1,5 @@ // This file is generated by the effect-codex-app-server package. Do not edit manually. -// Upstream protocol ref: b39f943a634a6e7ba86c3d6e8cf6d5f35e612566 +// Upstream protocol ref: 678157acaa819d5510adfe359abb5d0392cfe461 import * as CodexSchema from "./schema.gen.ts"; @@ -40,7 +40,9 @@ export const CLIENT_REQUEST_METHODS = { "plugin/share/list": "plugin/share/list", "plugin/share/checkout": "plugin/share/checkout", "plugin/share/delete": "plugin/share/delete", + "app/read": "app/read", "app/list": "app/list", + "app/installed": "app/installed", "fs/readFile": "fs/readFile", "fs/writeFile": "fs/writeFile", "fs/createDirectory": "fs/createDirectory", @@ -73,7 +75,9 @@ export const CLIENT_REQUEST_METHODS = { "account/login/cancel": "account/login/cancel", "account/logout": "account/logout", "account/rateLimits/read": "account/rateLimits/read", + "account/rateLimitResetCredit/consume": "account/rateLimitResetCredit/consume", "account/usage/read": "account/usage/read", + "account/workspaceMessages/read": "account/workspaceMessages/read", "account/sendAddCreditsNudgeEmail": "account/sendAddCreditsNudgeEmail", "feedback/upload": "feedback/upload", "command/exec": "command/exec", @@ -83,6 +87,7 @@ export const CLIENT_REQUEST_METHODS = { "config/read": "config/read", "externalAgentConfig/detect": "externalAgentConfig/detect", "externalAgentConfig/import": "externalAgentConfig/import", + "externalAgentConfig/import/readHistories": "externalAgentConfig/import/readHistories", "config/value/write": "config/value/write", "config/batchWrite": "config/batchWrite", "configRequirements/read": "configRequirements/read", @@ -122,6 +127,8 @@ export const SERVER_NOTIFICATION_METHODS = { "thread/name/updated": "thread/name/updated", "thread/goal/updated": "thread/goal/updated", "thread/goal/cleared": "thread/goal/cleared", + "thread/environment/connected": "thread/environment/connected", + "thread/environment/disconnected": "thread/environment/disconnected", "thread/settings/updated": "thread/settings/updated", "thread/tokenUsage/updated": "thread/tokenUsage/updated", "turn/started": "turn/started", @@ -135,6 +142,7 @@ export const SERVER_NOTIFICATION_METHODS = { "item/autoApprovalReview/completed": "item/autoApprovalReview/completed", "item/completed": "item/completed", "rawResponseItem/completed": "rawResponseItem/completed", + "rawResponse/completed": "rawResponse/completed", "item/agentMessage/delta": "item/agentMessage/delta", "item/plan/delta": "item/plan/delta", "command/exec/outputDelta": "command/exec/outputDelta", @@ -152,6 +160,7 @@ export const SERVER_NOTIFICATION_METHODS = { "account/rateLimits/updated": "account/rateLimits/updated", "app/list/updated": "app/list/updated", "remoteControl/status/changed": "remoteControl/status/changed", + "externalAgentConfig/import/progress": "externalAgentConfig/import/progress", "externalAgentConfig/import/completed": "externalAgentConfig/import/completed", "fs/changed": "fs/changed", "item/reasoning/summaryTextDelta": "item/reasoning/summaryTextDelta", @@ -161,6 +170,7 @@ export const SERVER_NOTIFICATION_METHODS = { "model/rerouted": "model/rerouted", "model/verification": "model/verification", "turn/moderationMetadata": "turn/moderationMetadata", + "model/safetyBuffering/updated": "model/safetyBuffering/updated", warning: "warning", guardianWarning: "guardianWarning", deprecationNotice: "deprecationNotice", @@ -222,7 +232,9 @@ export interface ClientRequestParamsByMethod { readonly "plugin/share/list": CodexSchema.V2PluginShareListParams; readonly "plugin/share/checkout": CodexSchema.V2PluginShareCheckoutParams; readonly "plugin/share/delete": CodexSchema.V2PluginShareDeleteParams; + readonly "app/read": CodexSchema.V2AppsReadParams; readonly "app/list": CodexSchema.V2AppsListParams; + readonly "app/installed": CodexSchema.V2AppsInstalledParams; readonly "fs/readFile": CodexSchema.V2FsReadFileParams; readonly "fs/writeFile": CodexSchema.V2FsWriteFileParams; readonly "fs/createDirectory": CodexSchema.V2FsCreateDirectoryParams; @@ -255,7 +267,9 @@ export interface ClientRequestParamsByMethod { readonly "account/login/cancel": CodexSchema.V2CancelLoginAccountParams; readonly "account/logout": undefined; readonly "account/rateLimits/read": undefined; + readonly "account/rateLimitResetCredit/consume": CodexSchema.V2ConsumeAccountRateLimitResetCreditParams; readonly "account/usage/read": undefined; + readonly "account/workspaceMessages/read": undefined; readonly "account/sendAddCreditsNudgeEmail": CodexSchema.V2SendAddCreditsNudgeEmailParams; readonly "feedback/upload": CodexSchema.V2FeedbackUploadParams; readonly "command/exec": CodexSchema.V2CommandExecParams; @@ -265,6 +279,7 @@ export interface ClientRequestParamsByMethod { readonly "config/read": CodexSchema.V2ConfigReadParams; readonly "externalAgentConfig/detect": CodexSchema.V2ExternalAgentConfigDetectParams; readonly "externalAgentConfig/import": CodexSchema.V2ExternalAgentConfigImportParams; + readonly "externalAgentConfig/import/readHistories": undefined; readonly "config/value/write": CodexSchema.V2ConfigValueWriteParams; readonly "config/batchWrite": CodexSchema.V2ConfigBatchWriteParams; readonly "configRequirements/read": undefined; @@ -312,7 +327,9 @@ export interface ClientRequestResponsesByMethod { readonly "plugin/share/list": CodexSchema.V2PluginShareListResponse; readonly "plugin/share/checkout": CodexSchema.V2PluginShareCheckoutResponse; readonly "plugin/share/delete": CodexSchema.V2PluginShareDeleteResponse; + readonly "app/read": CodexSchema.V2AppsReadResponse; readonly "app/list": CodexSchema.V2AppsListResponse; + readonly "app/installed": CodexSchema.V2AppsInstalledResponse; readonly "fs/readFile": CodexSchema.V2FsReadFileResponse; readonly "fs/writeFile": CodexSchema.V2FsWriteFileResponse; readonly "fs/createDirectory": CodexSchema.V2FsCreateDirectoryResponse; @@ -345,7 +362,9 @@ export interface ClientRequestResponsesByMethod { readonly "account/login/cancel": CodexSchema.V2CancelLoginAccountResponse; readonly "account/logout": CodexSchema.V2LogoutAccountResponse; readonly "account/rateLimits/read": CodexSchema.V2GetAccountRateLimitsResponse; + readonly "account/rateLimitResetCredit/consume": CodexSchema.V2ConsumeAccountRateLimitResetCreditResponse; readonly "account/usage/read": CodexSchema.V2GetAccountTokenUsageResponse; + readonly "account/workspaceMessages/read": CodexSchema.V2GetWorkspaceMessagesResponse; readonly "account/sendAddCreditsNudgeEmail": CodexSchema.V2SendAddCreditsNudgeEmailResponse; readonly "feedback/upload": CodexSchema.V2FeedbackUploadResponse; readonly "command/exec": CodexSchema.V2CommandExecResponse; @@ -355,6 +374,7 @@ export interface ClientRequestResponsesByMethod { readonly "config/read": CodexSchema.V2ConfigReadResponse; readonly "externalAgentConfig/detect": CodexSchema.V2ExternalAgentConfigDetectResponse; readonly "externalAgentConfig/import": CodexSchema.V2ExternalAgentConfigImportResponse; + readonly "externalAgentConfig/import/readHistories": CodexSchema.V2ExternalAgentConfigImportHistoriesReadResponse; readonly "config/value/write": CodexSchema.V2ConfigWriteResponse; readonly "config/batchWrite": CodexSchema.V2ConfigWriteResponse; readonly "configRequirements/read": CodexSchema.V2ConfigRequirementsReadResponse; @@ -407,6 +427,8 @@ export interface ServerNotificationParamsByMethod { readonly "thread/name/updated": CodexSchema.V2ThreadNameUpdatedNotification; readonly "thread/goal/updated": CodexSchema.V2ThreadGoalUpdatedNotification; readonly "thread/goal/cleared": CodexSchema.V2ThreadGoalClearedNotification; + readonly "thread/environment/connected": CodexSchema.V2EnvironmentConnectionNotification; + readonly "thread/environment/disconnected": CodexSchema.V2EnvironmentConnectionNotification; readonly "thread/settings/updated": CodexSchema.V2ThreadSettingsUpdatedNotification; readonly "thread/tokenUsage/updated": CodexSchema.V2ThreadTokenUsageUpdatedNotification; readonly "turn/started": CodexSchema.V2TurnStartedNotification; @@ -420,6 +442,7 @@ export interface ServerNotificationParamsByMethod { readonly "item/autoApprovalReview/completed": CodexSchema.V2ItemGuardianApprovalReviewCompletedNotification; readonly "item/completed": CodexSchema.V2ItemCompletedNotification; readonly "rawResponseItem/completed": CodexSchema.V2RawResponseItemCompletedNotification; + readonly "rawResponse/completed": CodexSchema.V2RawResponseCompletedNotification; readonly "item/agentMessage/delta": CodexSchema.V2AgentMessageDeltaNotification; readonly "item/plan/delta": CodexSchema.V2PlanDeltaNotification; readonly "command/exec/outputDelta": CodexSchema.V2CommandExecOutputDeltaNotification; @@ -437,6 +460,7 @@ export interface ServerNotificationParamsByMethod { readonly "account/rateLimits/updated": CodexSchema.V2AccountRateLimitsUpdatedNotification; readonly "app/list/updated": CodexSchema.V2AppListUpdatedNotification; readonly "remoteControl/status/changed": CodexSchema.V2RemoteControlStatusChangedNotification; + readonly "externalAgentConfig/import/progress": CodexSchema.V2ExternalAgentConfigImportProgressNotification; readonly "externalAgentConfig/import/completed": CodexSchema.V2ExternalAgentConfigImportCompletedNotification; readonly "fs/changed": CodexSchema.V2FsChangedNotification; readonly "item/reasoning/summaryTextDelta": CodexSchema.V2ReasoningSummaryTextDeltaNotification; @@ -446,6 +470,7 @@ export interface ServerNotificationParamsByMethod { readonly "model/rerouted": CodexSchema.V2ModelReroutedNotification; readonly "model/verification": CodexSchema.V2ModelVerificationNotification; readonly "turn/moderationMetadata": CodexSchema.V2TurnModerationMetadataNotification; + readonly "model/safetyBuffering/updated": CodexSchema.V2ModelSafetyBufferingUpdatedNotification; readonly warning: CodexSchema.V2WarningNotification; readonly guardianWarning: CodexSchema.V2GuardianWarningNotification; readonly deprecationNotice: CodexSchema.V2DeprecationNoticeNotification; @@ -502,7 +527,9 @@ export const CLIENT_REQUEST_PARAMS = { "plugin/share/list": CodexSchema.V2PluginShareListParams, "plugin/share/checkout": CodexSchema.V2PluginShareCheckoutParams, "plugin/share/delete": CodexSchema.V2PluginShareDeleteParams, + "app/read": CodexSchema.V2AppsReadParams, "app/list": CodexSchema.V2AppsListParams, + "app/installed": CodexSchema.V2AppsInstalledParams, "fs/readFile": CodexSchema.V2FsReadFileParams, "fs/writeFile": CodexSchema.V2FsWriteFileParams, "fs/createDirectory": CodexSchema.V2FsCreateDirectoryParams, @@ -535,7 +562,9 @@ export const CLIENT_REQUEST_PARAMS = { "account/login/cancel": CodexSchema.V2CancelLoginAccountParams, "account/logout": undefined, "account/rateLimits/read": undefined, + "account/rateLimitResetCredit/consume": CodexSchema.V2ConsumeAccountRateLimitResetCreditParams, "account/usage/read": undefined, + "account/workspaceMessages/read": undefined, "account/sendAddCreditsNudgeEmail": CodexSchema.V2SendAddCreditsNudgeEmailParams, "feedback/upload": CodexSchema.V2FeedbackUploadParams, "command/exec": CodexSchema.V2CommandExecParams, @@ -545,6 +574,7 @@ export const CLIENT_REQUEST_PARAMS = { "config/read": CodexSchema.V2ConfigReadParams, "externalAgentConfig/detect": CodexSchema.V2ExternalAgentConfigDetectParams, "externalAgentConfig/import": CodexSchema.V2ExternalAgentConfigImportParams, + "externalAgentConfig/import/readHistories": undefined, "config/value/write": CodexSchema.V2ConfigValueWriteParams, "config/batchWrite": CodexSchema.V2ConfigBatchWriteParams, "configRequirements/read": undefined, @@ -592,7 +622,9 @@ export const CLIENT_REQUEST_RESPONSES = { "plugin/share/list": CodexSchema.V2PluginShareListResponse, "plugin/share/checkout": CodexSchema.V2PluginShareCheckoutResponse, "plugin/share/delete": CodexSchema.V2PluginShareDeleteResponse, + "app/read": CodexSchema.V2AppsReadResponse, "app/list": CodexSchema.V2AppsListResponse, + "app/installed": CodexSchema.V2AppsInstalledResponse, "fs/readFile": CodexSchema.V2FsReadFileResponse, "fs/writeFile": CodexSchema.V2FsWriteFileResponse, "fs/createDirectory": CodexSchema.V2FsCreateDirectoryResponse, @@ -625,7 +657,9 @@ export const CLIENT_REQUEST_RESPONSES = { "account/login/cancel": CodexSchema.V2CancelLoginAccountResponse, "account/logout": CodexSchema.V2LogoutAccountResponse, "account/rateLimits/read": CodexSchema.V2GetAccountRateLimitsResponse, + "account/rateLimitResetCredit/consume": CodexSchema.V2ConsumeAccountRateLimitResetCreditResponse, "account/usage/read": CodexSchema.V2GetAccountTokenUsageResponse, + "account/workspaceMessages/read": CodexSchema.V2GetWorkspaceMessagesResponse, "account/sendAddCreditsNudgeEmail": CodexSchema.V2SendAddCreditsNudgeEmailResponse, "feedback/upload": CodexSchema.V2FeedbackUploadResponse, "command/exec": CodexSchema.V2CommandExecResponse, @@ -635,6 +669,8 @@ export const CLIENT_REQUEST_RESPONSES = { "config/read": CodexSchema.V2ConfigReadResponse, "externalAgentConfig/detect": CodexSchema.V2ExternalAgentConfigDetectResponse, "externalAgentConfig/import": CodexSchema.V2ExternalAgentConfigImportResponse, + "externalAgentConfig/import/readHistories": + CodexSchema.V2ExternalAgentConfigImportHistoriesReadResponse, "config/value/write": CodexSchema.V2ConfigWriteResponse, "config/batchWrite": CodexSchema.V2ConfigWriteResponse, "configRequirements/read": CodexSchema.V2ConfigRequirementsReadResponse, @@ -687,6 +723,8 @@ export const SERVER_NOTIFICATION_PARAMS = { "thread/name/updated": CodexSchema.V2ThreadNameUpdatedNotification, "thread/goal/updated": CodexSchema.V2ThreadGoalUpdatedNotification, "thread/goal/cleared": CodexSchema.V2ThreadGoalClearedNotification, + "thread/environment/connected": CodexSchema.V2EnvironmentConnectionNotification, + "thread/environment/disconnected": CodexSchema.V2EnvironmentConnectionNotification, "thread/settings/updated": CodexSchema.V2ThreadSettingsUpdatedNotification, "thread/tokenUsage/updated": CodexSchema.V2ThreadTokenUsageUpdatedNotification, "turn/started": CodexSchema.V2TurnStartedNotification, @@ -701,6 +739,7 @@ export const SERVER_NOTIFICATION_PARAMS = { CodexSchema.V2ItemGuardianApprovalReviewCompletedNotification, "item/completed": CodexSchema.V2ItemCompletedNotification, "rawResponseItem/completed": CodexSchema.V2RawResponseItemCompletedNotification, + "rawResponse/completed": CodexSchema.V2RawResponseCompletedNotification, "item/agentMessage/delta": CodexSchema.V2AgentMessageDeltaNotification, "item/plan/delta": CodexSchema.V2PlanDeltaNotification, "command/exec/outputDelta": CodexSchema.V2CommandExecOutputDeltaNotification, @@ -718,6 +757,8 @@ export const SERVER_NOTIFICATION_PARAMS = { "account/rateLimits/updated": CodexSchema.V2AccountRateLimitsUpdatedNotification, "app/list/updated": CodexSchema.V2AppListUpdatedNotification, "remoteControl/status/changed": CodexSchema.V2RemoteControlStatusChangedNotification, + "externalAgentConfig/import/progress": + CodexSchema.V2ExternalAgentConfigImportProgressNotification, "externalAgentConfig/import/completed": CodexSchema.V2ExternalAgentConfigImportCompletedNotification, "fs/changed": CodexSchema.V2FsChangedNotification, @@ -728,6 +769,7 @@ export const SERVER_NOTIFICATION_PARAMS = { "model/rerouted": CodexSchema.V2ModelReroutedNotification, "model/verification": CodexSchema.V2ModelVerificationNotification, "turn/moderationMetadata": CodexSchema.V2TurnModerationMetadataNotification, + "model/safetyBuffering/updated": CodexSchema.V2ModelSafetyBufferingUpdatedNotification, warning: CodexSchema.V2WarningNotification, guardianWarning: CodexSchema.V2GuardianWarningNotification, deprecationNotice: CodexSchema.V2DeprecationNoticeNotification, diff --git a/packages/effect-codex-app-server/src/_generated/namespaces.gen.ts b/packages/effect-codex-app-server/src/_generated/namespaces.gen.ts index 74154a2769fa..8665ad6f436d 100644 --- a/packages/effect-codex-app-server/src/_generated/namespaces.gen.ts +++ b/packages/effect-codex-app-server/src/_generated/namespaces.gen.ts @@ -1,5 +1,5 @@ // This file is generated by the effect-codex-app-server package. Do not edit manually. -// Upstream protocol ref: b39f943a634a6e7ba86c3d6e8cf6d5f35e612566 +// Upstream protocol ref: 678157acaa819d5510adfe359abb5d0392cfe461 import * as CodexSchema from "./schema.gen.ts"; @@ -14,8 +14,12 @@ export const v2 = { AccountUpdatedNotification: CodexSchema.V2AccountUpdatedNotification, AgentMessageDeltaNotification: CodexSchema.V2AgentMessageDeltaNotification, AppListUpdatedNotification: CodexSchema.V2AppListUpdatedNotification, + AppsInstalledParams: CodexSchema.V2AppsInstalledParams, + AppsInstalledResponse: CodexSchema.V2AppsInstalledResponse, AppsListParams: CodexSchema.V2AppsListParams, AppsListResponse: CodexSchema.V2AppsListResponse, + AppsReadParams: CodexSchema.V2AppsReadParams, + AppsReadResponse: CodexSchema.V2AppsReadResponse, CancelLoginAccountParams: CodexSchema.V2CancelLoginAccountParams, CancelLoginAccountResponse: CodexSchema.V2CancelLoginAccountResponse, CommandExecOutputDeltaNotification: CodexSchema.V2CommandExecOutputDeltaNotification, @@ -35,8 +39,12 @@ export const v2 = { ConfigValueWriteParams: CodexSchema.V2ConfigValueWriteParams, ConfigWarningNotification: CodexSchema.V2ConfigWarningNotification, ConfigWriteResponse: CodexSchema.V2ConfigWriteResponse, + ConsumeAccountRateLimitResetCreditParams: CodexSchema.V2ConsumeAccountRateLimitResetCreditParams, + ConsumeAccountRateLimitResetCreditResponse: + CodexSchema.V2ConsumeAccountRateLimitResetCreditResponse, ContextCompactedNotification: CodexSchema.V2ContextCompactedNotification, DeprecationNoticeNotification: CodexSchema.V2DeprecationNoticeNotification, + EnvironmentConnectionNotification: CodexSchema.V2EnvironmentConnectionNotification, ErrorNotification: CodexSchema.V2ErrorNotification, ExperimentalFeatureEnablementSetParams: CodexSchema.V2ExperimentalFeatureEnablementSetParams, ExperimentalFeatureEnablementSetResponse: CodexSchema.V2ExperimentalFeatureEnablementSetResponse, @@ -46,7 +54,11 @@ export const v2 = { ExternalAgentConfigDetectResponse: CodexSchema.V2ExternalAgentConfigDetectResponse, ExternalAgentConfigImportCompletedNotification: CodexSchema.V2ExternalAgentConfigImportCompletedNotification, + ExternalAgentConfigImportHistoriesReadResponse: + CodexSchema.V2ExternalAgentConfigImportHistoriesReadResponse, ExternalAgentConfigImportParams: CodexSchema.V2ExternalAgentConfigImportParams, + ExternalAgentConfigImportProgressNotification: + CodexSchema.V2ExternalAgentConfigImportProgressNotification, ExternalAgentConfigImportResponse: CodexSchema.V2ExternalAgentConfigImportResponse, FeedbackUploadParams: CodexSchema.V2FeedbackUploadParams, FeedbackUploadResponse: CodexSchema.V2FeedbackUploadResponse, @@ -75,6 +87,7 @@ export const v2 = { GetAccountRateLimitsResponse: CodexSchema.V2GetAccountRateLimitsResponse, GetAccountResponse: CodexSchema.V2GetAccountResponse, GetAccountTokenUsageResponse: CodexSchema.V2GetAccountTokenUsageResponse, + GetWorkspaceMessagesResponse: CodexSchema.V2GetWorkspaceMessagesResponse, GuardianWarningNotification: CodexSchema.V2GuardianWarningNotification, HookCompletedNotification: CodexSchema.V2HookCompletedNotification, HooksListParams: CodexSchema.V2HooksListParams, @@ -112,6 +125,7 @@ export const v2 = { ModelProviderCapabilitiesReadParams: CodexSchema.V2ModelProviderCapabilitiesReadParams, ModelProviderCapabilitiesReadResponse: CodexSchema.V2ModelProviderCapabilitiesReadResponse, ModelReroutedNotification: CodexSchema.V2ModelReroutedNotification, + ModelSafetyBufferingUpdatedNotification: CodexSchema.V2ModelSafetyBufferingUpdatedNotification, ModelVerificationNotification: CodexSchema.V2ModelVerificationNotification, PermissionProfileListParams: CodexSchema.V2PermissionProfileListParams, PermissionProfileListResponse: CodexSchema.V2PermissionProfileListResponse, @@ -140,6 +154,7 @@ export const v2 = { PluginUninstallResponse: CodexSchema.V2PluginUninstallResponse, ProcessExitedNotification: CodexSchema.V2ProcessExitedNotification, ProcessOutputDeltaNotification: CodexSchema.V2ProcessOutputDeltaNotification, + RawResponseCompletedNotification: CodexSchema.V2RawResponseCompletedNotification, RawResponseItemCompletedNotification: CodexSchema.V2RawResponseItemCompletedNotification, ReasoningSummaryPartAddedNotification: CodexSchema.V2ReasoningSummaryPartAddedNotification, ReasoningSummaryTextDeltaNotification: CodexSchema.V2ReasoningSummaryTextDeltaNotification, diff --git a/packages/effect-codex-app-server/src/_generated/schema.gen.ts b/packages/effect-codex-app-server/src/_generated/schema.gen.ts index fb93292384dd..d826df60f192 100644 --- a/packages/effect-codex-app-server/src/_generated/schema.gen.ts +++ b/packages/effect-codex-app-server/src/_generated/schema.gen.ts @@ -1,5 +1,5 @@ // This file is generated by the effect-codex-app-server package. Do not edit manually. -// Upstream protocol ref: b39f943a634a6e7ba86c3d6e8cf6d5f35e612566 +// Upstream protocol ref: 678157acaa819d5510adfe359abb5d0392cfe461 import * as Schema from "effect/Schema"; @@ -51,12 +51,17 @@ export const ClientRequest__AddCreditsNudgeCreditType = Schema.Literals(["credit export type ClientRequest__AdditionalContextKind = "untrusted" | "application"; export const ClientRequest__AdditionalContextKind = Schema.Literals(["untrusted", "application"]); -export type ClientRequest__AgentMessageInputContent = { - readonly encrypted_content: string; - readonly type: "encrypted_content"; -}; +export type ClientRequest__AgentMessageInputContent = + | { readonly text: string; readonly type: "input_text" } + | { readonly encrypted_content: string; readonly type: "encrypted_content" }; export const ClientRequest__AgentMessageInputContent = Schema.Union( [ + Schema.Struct({ + text: Schema.String, + type: Schema.Literal("input_text").annotate({ + title: "InputTextAgentMessageInputContentType", + }), + }).annotate({ title: "InputTextAgentMessageInputContent" }), Schema.Struct({ encrypted_content: Schema.String, type: Schema.Literal("encrypted_content").annotate({ @@ -77,6 +82,27 @@ export const ClientRequest__ApprovalsReviewer = Schema.Literals([ "Configures who approval requests are routed to for review. Examples include sandbox escapes, blocked network access, MCP approval prompts, and ARC escalations. Defaults to `user`. `auto_review` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request. The legacy value `guardian_subagent` is accepted for compatibility.", }); +export type ClientRequest__AppsInstalledParams = { + readonly forceRefresh?: boolean; + readonly threadId?: string | null; +}; +export const ClientRequest__AppsInstalledParams = Schema.Struct({ + forceRefresh: Schema.optionalKey( + Schema.Boolean.annotate({ + description: + "When true and Apps are permitted, refresh and publish the hosted connector runtime tool snapshot first.", + }), + ), + threadId: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Optional loaded thread id used to evaluate effective app configuration.", + }), + Schema.Null, + ]), + ), +}).annotate({ description: "Read the committed installed connector runtime snapshot." }); + export type ClientRequest__AppsListParams = { readonly cursor?: string | null; readonly forceRefetch?: boolean; @@ -119,9 +145,25 @@ export const ClientRequest__AppsListParams = Schema.Struct({ ), }).annotate({ description: "EXPERIMENTAL - list available apps/connectors." }); +export type ClientRequest__AppsReadParams = { + readonly appIds: ReadonlyArray; + readonly includeTools?: boolean; +}; +export const ClientRequest__AppsReadParams = Schema.Struct({ + appIds: Schema.Array(Schema.String).annotate({ + description: + "App ids to read. The server accepts at most 100 ids and deduplicates repeated ids while preserving their first-request order.", + }), + includeTools: Schema.optionalKey( + Schema.Boolean.annotate({ + description: + "When true, include display-only public tool summaries in the returned metadata.", + }), + ), +}).annotate({ description: "EXPERIMENTAL - read metadata for specific apps/connectors." }); + export type ClientRequest__AskForApproval = | "untrusted" - | "on-failure" | "on-request" | "never" | { @@ -135,7 +177,7 @@ export type ClientRequest__AskForApproval = }; export const ClientRequest__AskForApproval = Schema.Union( [ - Schema.Literals(["untrusted", "on-failure", "on-request", "never"]), + Schema.Literals(["untrusted", "on-request", "never"]), Schema.Struct({ granular: Schema.Struct({ mcp_elicitations: Schema.Boolean, @@ -260,6 +302,53 @@ export const ClientRequest__ConfigReadParams = Schema.Struct({ includeLayers: Schema.optionalKey(Schema.Boolean), }); +export type ClientRequest__ConsumeAccountRateLimitResetCreditParams = { + readonly creditId?: string | null; + readonly idempotencyKey: string; +}; +export const ClientRequest__ConsumeAccountRateLimitResetCreditParams = Schema.Struct({ + creditId: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: + "Opaque reset-credit identifier to redeem. When omitted, the backend selects the next available credit.", + }), + Schema.Null, + ]), + ), + idempotencyKey: Schema.String.annotate({ + description: + "Identifies one logical reset attempt. A UUID is recommended; reuse the same value when retrying that attempt.", + }), +}); + +export type ClientRequest__ConversationTextRole = "user" | "developer" | "assistant"; +export const ClientRequest__ConversationTextRole = Schema.Literals([ + "user", + "developer", + "assistant", +]); + +export type ClientRequest__DynamicToolNamespaceTool = { + readonly deferLoading?: boolean; + readonly description: string; + readonly inputSchema: unknown; + readonly name: string; + readonly type: "function"; +}; +export const ClientRequest__DynamicToolNamespaceTool = Schema.Union( + [ + Schema.Struct({ + deferLoading: Schema.optionalKey(Schema.Boolean), + description: Schema.String, + inputSchema: Schema.Unknown, + name: Schema.String, + type: Schema.Literal("function").annotate({ title: "FunctionDynamicToolNamespaceToolType" }), + }).annotate({ title: "FunctionDynamicToolNamespaceTool" }), + ], + { mode: "oneOf" }, +); + export type ClientRequest__ExperimentalFeatureEnablementSetParams = { readonly enablement: { readonly [x: string]: boolean }; }; @@ -309,6 +398,8 @@ export const ClientRequest__ExperimentalFeatureListParams = Schema.Struct({ export type ClientRequest__ExternalAgentConfigDetectParams = { readonly cwds?: ReadonlyArray | null; readonly includeHome?: boolean; + readonly migrationSource?: string | null; + readonly source?: string | null; }; export const ClientRequest__ExternalAgentConfigDetectParams = Schema.Struct({ cwds: Schema.optionalKey( @@ -321,9 +412,27 @@ export const ClientRequest__ExternalAgentConfigDetectParams = Schema.Struct({ ), includeHome: Schema.optionalKey( Schema.Boolean.annotate({ - description: "If true, include detection under the user's home (~/.claude, ~/.codex, etc.).", + description: "If true, include detection under the user's home directory.", }), ), + migrationSource: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: + "Optional migration-source selector. Missing or unrecognized values use the default source.", + }), + Schema.Null, + ]), + ), + source: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: + "Deprecated field retained for compatibility. This field is ignored; use `migrationSource` to select the migration source.", + }), + Schema.Null, + ]), + ), }); export type ClientRequest__ExternalAgentConfigMigrationItemType = @@ -335,6 +444,7 @@ export type ClientRequest__ExternalAgentConfigMigrationItemType = | "SUBAGENTS" | "HOOKS" | "COMMANDS" + | "MEMORY" | "SESSIONS"; export const ClientRequest__ExternalAgentConfigMigrationItemType = Schema.Literals([ "AGENTS_MD", @@ -345,6 +455,7 @@ export const ClientRequest__ExternalAgentConfigMigrationItemType = Schema.Litera "SUBAGENTS", "HOOKS", "COMMANDS", + "MEMORY", "SESSIONS", ]); @@ -527,6 +638,7 @@ export const ClientRequest__ImageDetail = Schema.Literals(["auto", "low", "high" export type ClientRequest__InitializeCapabilities = { readonly experimentalApi?: boolean; + readonly mcpServerOpenaiFormElicitation?: boolean; readonly optOutNotificationMethods?: ReadonlyArray | null; readonly requestAttestation?: boolean; }; @@ -537,6 +649,11 @@ export const ClientRequest__InitializeCapabilities = Schema.Struct({ default: false, }), ), + mcpServerOpenaiFormElicitation: Schema.optionalKey( + Schema.Boolean.annotate({ + description: "Allow downstream MCP servers to request OpenAI extended form elicitations.", + }), + ), optOutNotificationMethods: Schema.optionalKey( Schema.Union([ Schema.Array(Schema.String).annotate({ @@ -554,6 +671,19 @@ export const ClientRequest__InitializeCapabilities = Schema.Struct({ ), }).annotate({ description: "Client-declared capabilities negotiated during initialize." }); +export type ClientRequest__InternalChatMessageMetadataPassthrough = { + readonly turn_id?: string | null; +}; +export const ClientRequest__InternalChatMessageMetadataPassthrough = Schema.Struct({ + turn_id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), +}).annotate({ + description: + "Internal Responses API passthrough metadata copied into underlying chat messages.\n\nResponses API strongly types this payload. Do not modify it without first getting API approval and making the corresponding Responses API change.", +}); + +export type ClientRequest__LegacyAppPathString = string; +export const ClientRequest__LegacyAppPathString = Schema.String; + export type ClientRequest__LocalShellAction = { readonly command: ReadonlyArray; readonly env?: { readonly [x: string]: string } | null; @@ -592,59 +722,8 @@ export const ClientRequest__LocalShellStatus = Schema.Literals([ "incomplete", ]); -export type ClientRequest__LoginAccountParams = - | { readonly apiKey: string; readonly type: "apiKey" } - | { readonly codexStreamlinedLogin?: boolean; readonly type: "chatgpt" } - | { readonly type: "chatgptDeviceCode" } - | { - readonly accessToken: string; - readonly chatgptAccountId: string; - readonly chatgptPlanType?: string | null; - readonly type: "chatgptAuthTokens"; - }; -export const ClientRequest__LoginAccountParams = Schema.Union( - [ - Schema.Struct({ - apiKey: Schema.String, - type: Schema.Literal("apiKey").annotate({ title: "ApiKeyLoginAccountParamsType" }), - }).annotate({ title: "ApiKeyLoginAccountParams" }), - Schema.Struct({ - codexStreamlinedLogin: Schema.optionalKey(Schema.Boolean), - type: Schema.Literal("chatgpt").annotate({ title: "ChatgptLoginAccountParamsType" }), - }).annotate({ title: "ChatgptLoginAccountParams" }), - Schema.Struct({ - type: Schema.Literal("chatgptDeviceCode").annotate({ - title: "ChatgptDeviceCodeLoginAccountParamsType", - }), - }).annotate({ title: "ChatgptDeviceCodeLoginAccountParams" }), - Schema.Struct({ - accessToken: Schema.String.annotate({ - description: - "Access token (JWT) supplied by the client. This token is used for backend API requests and email extraction.", - }), - chatgptAccountId: Schema.String.annotate({ - description: "Workspace/account identifier supplied by the client.", - }), - chatgptPlanType: Schema.optionalKey( - Schema.Union([ - Schema.String.annotate({ - description: - "Optional plan type supplied by the client.\n\nWhen `null`, Codex attempts to derive the plan type from access-token claims. If unavailable, the plan defaults to `unknown`.", - }), - Schema.Null, - ]), - ), - type: Schema.Literal("chatgptAuthTokens").annotate({ - title: "ChatgptAuthTokensLoginAccountParamsType", - }), - }).annotate({ - title: "ChatgptAuthTokensLoginAccountParams", - description: - "[UNSTABLE] FOR OPENAI INTERNAL USE ONLY - DO NOT USE. The access token must contain the same scopes that Codex-managed ChatGPT auth tokens have.", - }), - ], - { mode: "oneOf" }, -); +export type ClientRequest__LoginAppBrand = "codex" | "chatgpt"; +export const ClientRequest__LoginAppBrand = Schema.Literals(["codex", "chatgpt"]); export type ClientRequest__MarketplaceAddParams = { readonly refName?: string | null; @@ -684,11 +763,13 @@ export const ClientRequest__McpServerMigration = Schema.Struct({ name: Schema.St export type ClientRequest__McpServerOauthLoginParams = { readonly name: string; readonly scopes?: ReadonlyArray | null; + readonly threadId?: string | null; readonly timeoutSecs?: number | null; }; export const ClientRequest__McpServerOauthLoginParams = Schema.Struct({ name: Schema.String, scopes: Schema.optionalKey(Schema.Union([Schema.Array(Schema.String), Schema.Null])), + threadId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), timeoutSecs: Schema.optionalKey( Schema.Union([Schema.Number.annotate({ format: "int64" }).check(Schema.isInt()), Schema.Null]), ), @@ -808,12 +889,14 @@ export type ClientRequest__PluginListMarketplaceKind = | "local" | "vertical" | "workspace-directory" - | "shared-with-me"; + | "shared-with-me" + | "created-by-me-remote"; export const ClientRequest__PluginListMarketplaceKind = Schema.Literals([ "local", "vertical", "workspace-directory", "shared-with-me", + "created-by-me-remote", ]); export type ClientRequest__PluginShareCheckoutParams = { readonly remotePluginId: string }; @@ -846,10 +929,11 @@ export const ClientRequest__PluginSharePrincipalType = Schema.Literals([ export type ClientRequest__PluginShareTargetRole = "reader" | "editor"; export const ClientRequest__PluginShareTargetRole = Schema.Literals(["reader", "editor"]); -export type ClientRequest__PluginShareUpdateDiscoverability = "UNLISTED" | "PRIVATE"; +export type ClientRequest__PluginShareUpdateDiscoverability = "UNLISTED" | "PRIVATE" | "LISTED"; export const ClientRequest__PluginShareUpdateDiscoverability = Schema.Literals([ "UNLISTED", "PRIVATE", + "LISTED", ]); export type ClientRequest__PluginSkillReadParams = { @@ -1042,6 +1126,9 @@ export const ClientRequest__SessionMigration = Schema.Struct({ title: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), }); +export type ClientRequest__SkillMigration = { readonly name: string }; +export const ClientRequest__SkillMigration = Schema.Struct({ name: Schema.String }); + export type ClientRequest__SkillsListParams = { readonly cwds?: ReadonlyArray; readonly forceReload?: boolean; @@ -1236,7 +1323,7 @@ export const ClientRequest__ThreadRollbackParams = Schema.Struct({ .check(Schema.isInt()) .check(Schema.isGreaterThanOrEqualTo(0)), threadId: Schema.String, -}); +}).annotate({ description: "DEPRECATED: `thread/rollback` will be removed soon." }); export type ClientRequest__ThreadSetNameParams = { readonly name: string; @@ -1259,8 +1346,12 @@ export const ClientRequest__ThreadShellCommandParams = Schema.Struct({ threadId: Schema.String, }); -export type ClientRequest__ThreadSortKey = "created_at" | "updated_at"; -export const ClientRequest__ThreadSortKey = Schema.Literals(["created_at", "updated_at"]); +export type ClientRequest__ThreadSortKey = "created_at" | "updated_at" | "recency_at"; +export const ClientRequest__ThreadSortKey = Schema.Literals([ + "created_at", + "updated_at", + "recency_at", +]); export type ClientRequest__ThreadSource = string; export const ClientRequest__ThreadSource = Schema.String; @@ -1333,39 +1424,8 @@ export const CommandExecutionRequestApprovalParams__FileSystemAccessMode = Schem "deny", ]); -export type CommandExecutionRequestApprovalParams__FileSystemSpecialPath = - | { readonly kind: "root" } - | { readonly kind: "minimal" } - | { readonly kind: "project_roots"; readonly subpath?: string | null } - | { readonly kind: "tmpdir" } - | { readonly kind: "slash_tmp" } - | { readonly kind: "unknown"; readonly path: string; readonly subpath?: string | null }; -export const CommandExecutionRequestApprovalParams__FileSystemSpecialPath = Schema.Union( - [ - Schema.Struct({ kind: Schema.Literal("root") }).annotate({ - title: "RootFileSystemSpecialPath", - }), - Schema.Struct({ kind: Schema.Literal("minimal") }).annotate({ - title: "MinimalFileSystemSpecialPath", - }), - Schema.Struct({ - kind: Schema.Literal("project_roots"), - subpath: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), - }).annotate({ title: "KindFileSystemSpecialPath" }), - Schema.Struct({ kind: Schema.Literal("tmpdir") }).annotate({ - title: "TmpdirFileSystemSpecialPath", - }), - Schema.Struct({ kind: Schema.Literal("slash_tmp") }).annotate({ - title: "SlashTmpFileSystemSpecialPath", - }), - Schema.Struct({ - kind: Schema.Literal("unknown"), - path: Schema.String, - subpath: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), - }), - ], - { mode: "oneOf" }, -); +export type CommandExecutionRequestApprovalParams__LegacyAppPathString = string; +export const CommandExecutionRequestApprovalParams__LegacyAppPathString = Schema.String; export type CommandExecutionRequestApprovalParams__NetworkApprovalProtocol = | "http" @@ -1393,7 +1453,8 @@ export const CommandExecutionRequestApprovalResponse__NetworkPolicyRuleAction = export type DynamicToolCallResponse__DynamicToolCallOutputContentItem = | { readonly text: string; readonly type: "inputText" } - | { readonly imageUrl: string; readonly type: "inputImage" }; + | { readonly imageUrl: string; readonly type: "inputImage" } + | { readonly audioUrl: string; readonly type: "inputAudio" }; export const DynamicToolCallResponse__DynamicToolCallOutputContentItem = Schema.Union( [ Schema.Struct({ @@ -1408,6 +1469,12 @@ export const DynamicToolCallResponse__DynamicToolCallOutputContentItem = Schema. title: "InputImageDynamicToolCallOutputContentItemType", }), }).annotate({ title: "InputImageDynamicToolCallOutputContentItem" }), + Schema.Struct({ + audioUrl: Schema.String, + type: Schema.Literal("inputAudio").annotate({ + title: "InputAudioDynamicToolCallOutputContentItemType", + }), + }).annotate({ title: "InputAudioDynamicToolCallOutputContentItem" }), ], { mode: "oneOf" }, ); @@ -1630,45 +1697,8 @@ export const PermissionsRequestApprovalParams__FileSystemAccessMode = Schema.Lit "deny", ]); -export type PermissionsRequestApprovalParams__FileSystemSpecialPath = - | { readonly kind: "root" } - | { readonly kind: "minimal" } - | { readonly kind: "project_roots"; readonly subpath?: string | null } - | { readonly kind: "tmpdir" } - | { readonly kind: "slash_tmp" } - | { readonly kind: "unknown"; readonly path: string; readonly subpath?: string | null }; -export const PermissionsRequestApprovalParams__FileSystemSpecialPath = Schema.Union( - [ - Schema.Struct({ kind: Schema.Literal("root") }).annotate({ - title: "RootFileSystemSpecialPath", - }), - Schema.Struct({ kind: Schema.Literal("minimal") }).annotate({ - title: "MinimalFileSystemSpecialPath", - }), - Schema.Struct({ - kind: Schema.Literal("project_roots"), - subpath: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), - }).annotate({ title: "KindFileSystemSpecialPath" }), - Schema.Struct({ kind: Schema.Literal("tmpdir") }).annotate({ - title: "TmpdirFileSystemSpecialPath", - }), - Schema.Struct({ kind: Schema.Literal("slash_tmp") }).annotate({ - title: "SlashTmpFileSystemSpecialPath", - }), - Schema.Struct({ - kind: Schema.Literal("unknown"), - path: Schema.String, - subpath: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), - }), - ], - { mode: "oneOf" }, -); - -export type PermissionsRequestApprovalResponse__AbsolutePathBuf = string; -export const PermissionsRequestApprovalResponse__AbsolutePathBuf = Schema.String.annotate({ - description: - "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", -}); +export type PermissionsRequestApprovalParams__LegacyAppPathString = string; +export const PermissionsRequestApprovalParams__LegacyAppPathString = Schema.String; export type PermissionsRequestApprovalResponse__AdditionalNetworkPermissions = { readonly enabled?: boolean | null; @@ -1684,39 +1714,8 @@ export const PermissionsRequestApprovalResponse__FileSystemAccessMode = Schema.L "deny", ]); -export type PermissionsRequestApprovalResponse__FileSystemSpecialPath = - | { readonly kind: "root" } - | { readonly kind: "minimal" } - | { readonly kind: "project_roots"; readonly subpath?: string | null } - | { readonly kind: "tmpdir" } - | { readonly kind: "slash_tmp" } - | { readonly kind: "unknown"; readonly path: string; readonly subpath?: string | null }; -export const PermissionsRequestApprovalResponse__FileSystemSpecialPath = Schema.Union( - [ - Schema.Struct({ kind: Schema.Literal("root") }).annotate({ - title: "RootFileSystemSpecialPath", - }), - Schema.Struct({ kind: Schema.Literal("minimal") }).annotate({ - title: "MinimalFileSystemSpecialPath", - }), - Schema.Struct({ - kind: Schema.Literal("project_roots"), - subpath: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), - }).annotate({ title: "KindFileSystemSpecialPath" }), - Schema.Struct({ kind: Schema.Literal("tmpdir") }).annotate({ - title: "TmpdirFileSystemSpecialPath", - }), - Schema.Struct({ kind: Schema.Literal("slash_tmp") }).annotate({ - title: "SlashTmpFileSystemSpecialPath", - }), - Schema.Struct({ - kind: Schema.Literal("unknown"), - path: Schema.String, - subpath: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), - }), - ], - { mode: "oneOf" }, -); +export type PermissionsRequestApprovalResponse__LegacyAppPathString = string; +export const PermissionsRequestApprovalResponse__LegacyAppPathString = Schema.String; export type ServerNotification__AbsolutePathBuf = string; export const ServerNotification__AbsolutePathBuf = Schema.String.annotate({ @@ -1821,7 +1820,6 @@ export const ServerNotification__ApprovalsReviewer = Schema.Literals([ export type ServerNotification__AskForApproval = | "untrusted" - | "on-failure" | "on-request" | "never" | { @@ -1835,7 +1833,7 @@ export type ServerNotification__AskForApproval = }; export const ServerNotification__AskForApproval = Schema.Union( [ - Schema.Literals(["untrusted", "on-failure", "on-request", "never"]), + Schema.Literals(["untrusted", "on-request", "never"]), Schema.Struct({ granular: Schema.Struct({ mcp_elicitations: Schema.Boolean, @@ -1853,14 +1851,18 @@ export type ServerNotification__AuthMode = | "apikey" | "chatgpt" | "chatgptAuthTokens" + | "headers" | "agentIdentity" - | "personalAccessToken"; + | "personalAccessToken" + | "bedrockApiKey"; export const ServerNotification__AuthMode = Schema.Literals([ "apikey", "chatgpt", "chatgptAuthTokens", + "headers", "agentIdentity", "personalAccessToken", + "bedrockApiKey", ]).annotate({ description: "Authentication mode for OpenAI-backed providers." }); export type ServerNotification__AutoReviewDecisionSource = "agent"; @@ -1973,7 +1975,8 @@ export const ServerNotification__DeprecationNoticeNotification = Schema.Struct({ export type ServerNotification__DynamicToolCallOutputContentItem = | { readonly text: string; readonly type: "inputText" } - | { readonly imageUrl: string; readonly type: "inputImage" }; + | { readonly imageUrl: string; readonly type: "inputImage" } + | { readonly audioUrl: string; readonly type: "inputAudio" }; export const ServerNotification__DynamicToolCallOutputContentItem = Schema.Union( [ Schema.Struct({ @@ -1988,6 +1991,12 @@ export const ServerNotification__DynamicToolCallOutputContentItem = Schema.Union title: "InputImageDynamicToolCallOutputContentItemType", }), }).annotate({ title: "InputImageDynamicToolCallOutputContentItem" }), + Schema.Struct({ + audioUrl: Schema.String, + type: Schema.Literal("inputAudio").annotate({ + title: "InputAudioDynamicToolCallOutputContentItemType", + }), + }).annotate({ title: "InputAudioDynamicToolCallOutputContentItem" }), ], { mode: "oneOf" }, ); @@ -1999,8 +2008,38 @@ export const ServerNotification__DynamicToolCallStatus = Schema.Literals([ "failed", ]); -export type ServerNotification__ExternalAgentConfigImportCompletedNotification = {}; -export const ServerNotification__ExternalAgentConfigImportCompletedNotification = Schema.Struct({}); +export type ServerNotification__EnvironmentConnectionNotification = { + readonly environmentId: string; + readonly threadId: string; +}; +export const ServerNotification__EnvironmentConnectionNotification = Schema.Struct({ + environmentId: Schema.String, + threadId: Schema.String, +}); + +export type ServerNotification__ExternalAgentConfigMigrationItemType = + | "AGENTS_MD" + | "CONFIG" + | "SKILLS" + | "PLUGINS" + | "MCP_SERVER_CONFIG" + | "SUBAGENTS" + | "HOOKS" + | "COMMANDS" + | "MEMORY" + | "SESSIONS"; +export const ServerNotification__ExternalAgentConfigMigrationItemType = Schema.Literals([ + "AGENTS_MD", + "CONFIG", + "SKILLS", + "PLUGINS", + "MCP_SERVER_CONFIG", + "SUBAGENTS", + "HOOKS", + "COMMANDS", + "MEMORY", + "SESSIONS", +]); export type ServerNotification__FileChangeOutputDeltaNotification = { readonly delta: string; @@ -2021,40 +2060,6 @@ export const ServerNotification__FileChangeOutputDeltaNotification = Schema.Stru export type ServerNotification__FileSystemAccessMode = "read" | "write" | "deny"; export const ServerNotification__FileSystemAccessMode = Schema.Literals(["read", "write", "deny"]); -export type ServerNotification__FileSystemSpecialPath = - | { readonly kind: "root" } - | { readonly kind: "minimal" } - | { readonly kind: "project_roots"; readonly subpath?: string | null } - | { readonly kind: "tmpdir" } - | { readonly kind: "slash_tmp" } - | { readonly kind: "unknown"; readonly path: string; readonly subpath?: string | null }; -export const ServerNotification__FileSystemSpecialPath = Schema.Union( - [ - Schema.Struct({ kind: Schema.Literal("root") }).annotate({ - title: "RootFileSystemSpecialPath", - }), - Schema.Struct({ kind: Schema.Literal("minimal") }).annotate({ - title: "MinimalFileSystemSpecialPath", - }), - Schema.Struct({ - kind: Schema.Literal("project_roots"), - subpath: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), - }).annotate({ title: "KindFileSystemSpecialPath" }), - Schema.Struct({ kind: Schema.Literal("tmpdir") }).annotate({ - title: "TmpdirFileSystemSpecialPath", - }), - Schema.Struct({ kind: Schema.Literal("slash_tmp") }).annotate({ - title: "SlashTmpFileSystemSpecialPath", - }), - Schema.Struct({ - kind: Schema.Literal("unknown"), - path: Schema.String, - subpath: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), - }), - ], - { mode: "oneOf" }, -); - export type ServerNotification__FuzzyFileSearchMatchType = "file" | "directory"; export const ServerNotification__FuzzyFileSearchMatchType = Schema.Literals(["file", "directory"]); @@ -2127,6 +2132,7 @@ export type ServerNotification__HookEventName = | "preCompact" | "postCompact" | "sessionStart" + | "sessionEnd" | "userPromptSubmit" | "subagentStart" | "subagentStop" @@ -2138,6 +2144,7 @@ export const ServerNotification__HookEventName = Schema.Literals([ "preCompact", "postCompact", "sessionStart", + "sessionEnd", "userPromptSubmit", "subagentStart", "subagentStop", @@ -2193,17 +2200,27 @@ export const ServerNotification__HookScope = Schema.Literals(["thread", "turn"]) export type ServerNotification__ImageDetail = "auto" | "low" | "high" | "original"; export const ServerNotification__ImageDetail = Schema.Literals(["auto", "low", "high", "original"]); +export type ServerNotification__LegacyAppPathString = string; +export const ServerNotification__LegacyAppPathString = Schema.String; + export type ServerNotification__McpServerOauthLoginCompletedNotification = { readonly error?: string | null; readonly name: string; readonly success: boolean; + readonly threadId?: string | null; }; export const ServerNotification__McpServerOauthLoginCompletedNotification = Schema.Struct({ error: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), name: Schema.String, success: Schema.Boolean, + threadId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), }); +export type ServerNotification__McpServerStartupFailureReason = "reauthenticationRequired"; +export const ServerNotification__McpServerStartupFailureReason = Schema.Literal( + "reauthenticationRequired", +); + export type ServerNotification__McpServerStartupState = | "starting" | "ready" @@ -2216,6 +2233,21 @@ export const ServerNotification__McpServerStartupState = Schema.Literals([ "cancelled", ]); +export type ServerNotification__McpToolCallAppContext = { + readonly actionName?: string | null; + readonly appName?: string | null; + readonly connectorId: string; + readonly linkId?: string | null; + readonly resourceUri?: string | null; +}; +export const ServerNotification__McpToolCallAppContext = Schema.Struct({ + actionName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + appName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + connectorId: Schema.String, + linkId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + resourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), +}); + export type ServerNotification__McpToolCallError = { readonly message: string }; export const ServerNotification__McpToolCallError = Schema.Struct({ message: Schema.String }); @@ -2284,6 +2316,25 @@ export const ServerNotification__ModeKind = Schema.Literals(["plan", "default"]) export type ServerNotification__ModelRerouteReason = "highRiskCyberActivity"; export const ServerNotification__ModelRerouteReason = Schema.Literal("highRiskCyberActivity"); +export type ServerNotification__ModelSafetyBufferingUpdatedNotification = { + readonly fasterModel?: string | null; + readonly model: string; + readonly reasons: ReadonlyArray; + readonly showBufferingUi: boolean; + readonly threadId: string; + readonly turnId: string; + readonly useCases: ReadonlyArray; +}; +export const ServerNotification__ModelSafetyBufferingUpdatedNotification = Schema.Struct({ + fasterModel: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + model: Schema.String, + reasons: Schema.Array(Schema.String), + showBufferingUi: Schema.Boolean, + threadId: Schema.String, + turnId: Schema.String, + useCases: Schema.Array(Schema.String), +}); + export type ServerNotification__ModelVerification = "trustedAccessForCyber"; export const ServerNotification__ModelVerification = Schema.Literal("trustedAccessForCyber"); @@ -2465,8 +2516,8 @@ export const ServerNotification__RateLimitWindow = Schema.Struct({ ), }); -export type ServerNotification__RealtimeConversationVersion = "v1" | "v2"; -export const ServerNotification__RealtimeConversationVersion = Schema.Literals(["v1", "v2"]); +export type ServerNotification__RealtimeConversationVersion = "v1" | "v2" | "v3"; +export const ServerNotification__RealtimeConversationVersion = Schema.Literals(["v1", "v2", "v3"]); export type ServerNotification__ReasoningEffort = string; export const ServerNotification__ReasoningEffort = Schema.String.annotate({ @@ -2782,6 +2833,7 @@ export const ServerNotification__ThreadUnarchivedNotification = Schema.Struct({ }); export type ServerNotification__TokenUsageBreakdown = { + readonly cacheWriteInputTokens?: number; readonly cachedInputTokens: number; readonly inputTokens: number; readonly outputTokens: number; @@ -2789,6 +2841,9 @@ export type ServerNotification__TokenUsageBreakdown = { readonly totalTokens: number; }; export const ServerNotification__TokenUsageBreakdown = Schema.Struct({ + cacheWriteInputTokens: Schema.optionalKey( + Schema.Number.annotate({ default: 0, format: "int64" }).check(Schema.isInt()), + ), cachedInputTokens: Schema.Number.annotate({ format: "int64" }).check(Schema.isInt()), inputTokens: Schema.Number.annotate({ format: "int64" }).check(Schema.isInt()), outputTokens: Schema.Number.annotate({ format: "int64" }).check(Schema.isInt()), @@ -2998,39 +3053,8 @@ export const ServerRequest__FileChangeRequestApprovalParams = Schema.Struct({ export type ServerRequest__FileSystemAccessMode = "read" | "write" | "deny"; export const ServerRequest__FileSystemAccessMode = Schema.Literals(["read", "write", "deny"]); -export type ServerRequest__FileSystemSpecialPath = - | { readonly kind: "root" } - | { readonly kind: "minimal" } - | { readonly kind: "project_roots"; readonly subpath?: string | null } - | { readonly kind: "tmpdir" } - | { readonly kind: "slash_tmp" } - | { readonly kind: "unknown"; readonly path: string; readonly subpath?: string | null }; -export const ServerRequest__FileSystemSpecialPath = Schema.Union( - [ - Schema.Struct({ kind: Schema.Literal("root") }).annotate({ - title: "RootFileSystemSpecialPath", - }), - Schema.Struct({ kind: Schema.Literal("minimal") }).annotate({ - title: "MinimalFileSystemSpecialPath", - }), - Schema.Struct({ - kind: Schema.Literal("project_roots"), - subpath: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), - }).annotate({ title: "KindFileSystemSpecialPath" }), - Schema.Struct({ kind: Schema.Literal("tmpdir") }).annotate({ - title: "TmpdirFileSystemSpecialPath", - }), - Schema.Struct({ kind: Schema.Literal("slash_tmp") }).annotate({ - title: "SlashTmpFileSystemSpecialPath", - }), - Schema.Struct({ - kind: Schema.Literal("unknown"), - path: Schema.String, - subpath: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), - }), - ], - { mode: "oneOf" }, -); +export type ServerRequest__LegacyAppPathString = string; +export const ServerRequest__LegacyAppPathString = Schema.String; export type ServerRequest__McpElicitationArrayType = "array"; export const ServerRequest__McpElicitationArrayType = Schema.Literal("array"); @@ -3168,6 +3192,7 @@ export const V1InitializeParams__ClientInfo = Schema.Struct({ export type V1InitializeParams__InitializeCapabilities = { readonly experimentalApi?: boolean; + readonly mcpServerOpenaiFormElicitation?: boolean; readonly optOutNotificationMethods?: ReadonlyArray | null; readonly requestAttestation?: boolean; }; @@ -3178,6 +3203,11 @@ export const V1InitializeParams__InitializeCapabilities = Schema.Struct({ default: false, }), ), + mcpServerOpenaiFormElicitation: Schema.optionalKey( + Schema.Boolean.annotate({ + description: "Allow downstream MCP servers to request OpenAI extended form elicitations.", + }), + ), optOutNotificationMethods: Schema.optionalKey( Schema.Union([ Schema.Array(Schema.String).annotate({ @@ -3280,14 +3310,18 @@ export type V2AccountUpdatedNotification__AuthMode = | "apikey" | "chatgpt" | "chatgptAuthTokens" + | "headers" | "agentIdentity" - | "personalAccessToken"; + | "personalAccessToken" + | "bedrockApiKey"; export const V2AccountUpdatedNotification__AuthMode = Schema.Literals([ "apikey", "chatgpt", "chatgptAuthTokens", + "headers", "agentIdentity", "personalAccessToken", + "bedrockApiKey", ]).annotate({ description: "Authentication mode for OpenAI-backed providers." }); export type V2AccountUpdatedNotification__PlanType = @@ -3349,6 +3383,33 @@ export const V2AppListUpdatedNotification__AppScreenshot = Schema.Struct({ userPrompt: Schema.String, }); +export type V2AppsInstalledResponse__InstalledApp = { + readonly callable: boolean; + readonly enabled: boolean; + readonly id: string; + readonly runtimeName?: string | null; +}; +export const V2AppsInstalledResponse__InstalledApp = Schema.Struct({ + callable: Schema.Boolean.annotate({ + description: + "Whether the connector is enabled and has a non-synthetic, model-visible tool allowed by effective MCP and app/tool policy in the committed runtime snapshot.", + }), + enabled: Schema.Boolean.annotate({ + description: + "Effective enabled state after applying global, workspace, local, and managed configuration at read time.", + }), + id: Schema.String, + runtimeName: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: + "Best-effort name carried by the runtime tool catalog. Canonical app metadata remains owned by `app/read`.", + }), + Schema.Null, + ]), + ), +}).annotate({ description: "Installed connector runtime state." }); + export type V2AppsListResponse__AppBranding = { readonly category?: string | null; readonly developer?: string | null; @@ -3380,6 +3441,17 @@ export const V2AppsListResponse__AppScreenshot = Schema.Struct({ userPrompt: Schema.String, }); +export type V2AppsReadResponse__AppToolSummary = { + readonly description: string; + readonly name: string; + readonly title?: string | null; +}; +export const V2AppsReadResponse__AppToolSummary = Schema.Struct({ + description: Schema.String, + name: Schema.String, + title: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), +}).annotate({ description: "EXPERIMENTAL - metadata returned by app/read." }); + export type V2CancelLoginAccountResponse__CancelLoginAccountStatus = "canceled" | "notFound"; export const V2CancelLoginAccountResponse__CancelLoginAccountStatus = Schema.Literals([ "canceled", @@ -3429,8 +3501,13 @@ export const V2ConfigReadResponse__AnalyticsConfig = Schema.StructWithRest( [Schema.Record(Schema.String, Schema.Unknown)], ); -export type V2ConfigReadResponse__AppToolApproval = "auto" | "prompt" | "approve"; -export const V2ConfigReadResponse__AppToolApproval = Schema.Literals(["auto", "prompt", "approve"]); +export type V2ConfigReadResponse__AppToolApproval = "auto" | "prompt" | "writes" | "approve"; +export const V2ConfigReadResponse__AppToolApproval = Schema.Literals([ + "auto", + "prompt", + "writes", + "approve", +]); export type V2ConfigReadResponse__AppToolsConfig = {}; export const V2ConfigReadResponse__AppToolsConfig = Schema.Struct({}); @@ -3445,20 +3522,8 @@ export const V2ConfigReadResponse__ApprovalsReviewer = Schema.Literals([ "Configures who approval requests are routed to for review. Examples include sandbox escapes, blocked network access, MCP approval prompts, and ARC escalations. Defaults to `user`. `auto_review` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request. The legacy value `guardian_subagent` is accepted for compatibility.", }); -export type V2ConfigReadResponse__AppsDefaultConfig = { - readonly destructive_enabled?: boolean; - readonly enabled?: boolean; - readonly open_world_enabled?: boolean; -}; -export const V2ConfigReadResponse__AppsDefaultConfig = Schema.Struct({ - destructive_enabled: Schema.optionalKey(Schema.Boolean.annotate({ default: true })), - enabled: Schema.optionalKey(Schema.Boolean.annotate({ default: true })), - open_world_enabled: Schema.optionalKey(Schema.Boolean.annotate({ default: true })), -}); - export type V2ConfigReadResponse__AskForApproval = | "untrusted" - | "on-failure" | "on-request" | "never" | { @@ -3472,7 +3537,7 @@ export type V2ConfigReadResponse__AskForApproval = }; export const V2ConfigReadResponse__AskForApproval = Schema.Union( [ - Schema.Literals(["untrusted", "on-failure", "on-request", "never"]), + Schema.Literals(["untrusted", "on-request", "never"]), Schema.Struct({ granular: Schema.Struct({ mcp_elicitations: Schema.Boolean, @@ -3572,12 +3637,16 @@ export const V2ConfigReadResponse__WebSearchLocation = Schema.Struct({ timezone: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), }); -export type V2ConfigReadResponse__WebSearchMode = "disabled" | "cached" | "live"; -export const V2ConfigReadResponse__WebSearchMode = Schema.Literals(["disabled", "cached", "live"]); +export type V2ConfigReadResponse__WebSearchMode = "disabled" | "cached" | "indexed" | "live"; +export const V2ConfigReadResponse__WebSearchMode = Schema.Literals([ + "disabled", + "cached", + "indexed", + "live", +]); export type V2ConfigRequirementsReadResponse__AskForApproval = | "untrusted" - | "on-failure" | "on-request" | "never" | { @@ -3591,7 +3660,7 @@ export type V2ConfigRequirementsReadResponse__AskForApproval = }; export const V2ConfigRequirementsReadResponse__AskForApproval = Schema.Union( [ - Schema.Literals(["untrusted", "on-failure", "on-request", "never"]), + Schema.Literals(["untrusted", "on-request", "never"]), Schema.Struct({ granular: Schema.Struct({ mcp_elicitations: Schema.Boolean, @@ -3662,6 +3731,11 @@ export const V2ConfigRequirementsReadResponse__NetworkUnixSocketPermission = Sch "deny", ]); +export type V2ConfigRequirementsReadResponse__ReasoningEffort = string; +export const V2ConfigRequirementsReadResponse__ReasoningEffort = Schema.String.annotate({ + description: "A non-empty reasoning effort value advertised by the model.", +}).check(Schema.isMinLength(1)); + export type V2ConfigRequirementsReadResponse__ResidencyRequirement = "us"; export const V2ConfigRequirementsReadResponse__ResidencyRequirement = Schema.Literal("us"); @@ -3675,10 +3749,15 @@ export const V2ConfigRequirementsReadResponse__SandboxMode = Schema.Literals([ "danger-full-access", ]); -export type V2ConfigRequirementsReadResponse__WebSearchMode = "disabled" | "cached" | "live"; +export type V2ConfigRequirementsReadResponse__WebSearchMode = + | "disabled" + | "cached" + | "indexed" + | "live"; export const V2ConfigRequirementsReadResponse__WebSearchMode = Schema.Literals([ "disabled", "cached", + "indexed", "live", ]); @@ -3716,6 +3795,11 @@ export const V2ConfigWriteResponse__AbsolutePathBuf = Schema.String.annotate({ export type V2ConfigWriteResponse__WriteStatus = "ok" | "okOverridden"; export const V2ConfigWriteResponse__WriteStatus = Schema.Literals(["ok", "okOverridden"]); +export type V2ConsumeAccountRateLimitResetCreditResponse__ConsumeAccountRateLimitResetCreditOutcome = + "reset" | "nothingToReset" | "noCredit" | "alreadyRedeemed"; +export const V2ConsumeAccountRateLimitResetCreditResponse__ConsumeAccountRateLimitResetCreditOutcome = + Schema.Literals(["reset", "nothingToReset", "noCredit", "alreadyRedeemed"]); + export type V2ErrorNotification__NonSteerableTurnKind = "review" | "compact"; export const V2ErrorNotification__NonSteerableTurnKind = Schema.Literals(["review", "compact"]); @@ -3784,6 +3868,7 @@ export type V2ExternalAgentConfigDetectResponse__ExternalAgentConfigMigrationIte | "SUBAGENTS" | "HOOKS" | "COMMANDS" + | "MEMORY" | "SESSIONS"; export const V2ExternalAgentConfigDetectResponse__ExternalAgentConfigMigrationItemType = Schema.Literals([ @@ -3795,6 +3880,7 @@ export const V2ExternalAgentConfigDetectResponse__ExternalAgentConfigMigrationIt "SUBAGENTS", "HOOKS", "COMMANDS", + "MEMORY", "SESSIONS", ]); @@ -3828,11 +3914,71 @@ export const V2ExternalAgentConfigDetectResponse__SessionMigration = Schema.Stru title: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), }); +export type V2ExternalAgentConfigDetectResponse__SkillMigration = { readonly name: string }; +export const V2ExternalAgentConfigDetectResponse__SkillMigration = Schema.Struct({ + name: Schema.String, +}); + export type V2ExternalAgentConfigDetectResponse__SubagentMigration = { readonly name: string }; export const V2ExternalAgentConfigDetectResponse__SubagentMigration = Schema.Struct({ name: Schema.String, }); +export type V2ExternalAgentConfigImportCompletedNotification__ExternalAgentConfigMigrationItemType = + | "AGENTS_MD" + | "CONFIG" + | "SKILLS" + | "PLUGINS" + | "MCP_SERVER_CONFIG" + | "SUBAGENTS" + | "HOOKS" + | "COMMANDS" + | "MEMORY" + | "SESSIONS"; +export const V2ExternalAgentConfigImportCompletedNotification__ExternalAgentConfigMigrationItemType = + Schema.Literals([ + "AGENTS_MD", + "CONFIG", + "SKILLS", + "PLUGINS", + "MCP_SERVER_CONFIG", + "SUBAGENTS", + "HOOKS", + "COMMANDS", + "MEMORY", + "SESSIONS", + ]); + +export type V2ExternalAgentConfigImportHistoriesReadResponse__ExternalAgentConfigMigrationItemType = + | "AGENTS_MD" + | "CONFIG" + | "SKILLS" + | "PLUGINS" + | "MCP_SERVER_CONFIG" + | "SUBAGENTS" + | "HOOKS" + | "COMMANDS" + | "MEMORY" + | "SESSIONS"; +export const V2ExternalAgentConfigImportHistoriesReadResponse__ExternalAgentConfigMigrationItemType = + Schema.Literals([ + "AGENTS_MD", + "CONFIG", + "SKILLS", + "PLUGINS", + "MCP_SERVER_CONFIG", + "SUBAGENTS", + "HOOKS", + "COMMANDS", + "MEMORY", + "SESSIONS", + ]); + +export type V2ExternalAgentConfigImportHistoriesReadResponse__ExternalAgentImportedConnectorSource = + "remoteMcpServersConfig"; +export const V2ExternalAgentConfigImportHistoriesReadResponse__ExternalAgentImportedConnectorSource = + Schema.Literal("remoteMcpServersConfig"); + export type V2ExternalAgentConfigImportParams__CommandMigration = { readonly name: string }; export const V2ExternalAgentConfigImportParams__CommandMigration = Schema.Struct({ name: Schema.String, @@ -3847,6 +3993,7 @@ export type V2ExternalAgentConfigImportParams__ExternalAgentConfigMigrationItemT | "SUBAGENTS" | "HOOKS" | "COMMANDS" + | "MEMORY" | "SESSIONS"; export const V2ExternalAgentConfigImportParams__ExternalAgentConfigMigrationItemType = Schema.Literals([ @@ -3858,6 +4005,7 @@ export const V2ExternalAgentConfigImportParams__ExternalAgentConfigMigrationItem "SUBAGENTS", "HOOKS", "COMMANDS", + "MEMORY", "SESSIONS", ]); @@ -3891,11 +4039,41 @@ export const V2ExternalAgentConfigImportParams__SessionMigration = Schema.Struct title: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), }); +export type V2ExternalAgentConfigImportParams__SkillMigration = { readonly name: string }; +export const V2ExternalAgentConfigImportParams__SkillMigration = Schema.Struct({ + name: Schema.String, +}); + export type V2ExternalAgentConfigImportParams__SubagentMigration = { readonly name: string }; export const V2ExternalAgentConfigImportParams__SubagentMigration = Schema.Struct({ name: Schema.String, }); +export type V2ExternalAgentConfigImportProgressNotification__ExternalAgentConfigMigrationItemType = + | "AGENTS_MD" + | "CONFIG" + | "SKILLS" + | "PLUGINS" + | "MCP_SERVER_CONFIG" + | "SUBAGENTS" + | "HOOKS" + | "COMMANDS" + | "MEMORY" + | "SESSIONS"; +export const V2ExternalAgentConfigImportProgressNotification__ExternalAgentConfigMigrationItemType = + Schema.Literals([ + "AGENTS_MD", + "CONFIG", + "SKILLS", + "PLUGINS", + "MCP_SERVER_CONFIG", + "SUBAGENTS", + "HOOKS", + "COMMANDS", + "MEMORY", + "SESSIONS", + ]); + export type V2FileChangePatchUpdatedNotification__PatchChangeKind = | { readonly type: "add" } | { readonly type: "delete" } @@ -3992,6 +4170,24 @@ export const V2GetAccountRateLimitsResponse__RateLimitReachedType = Schema.Liter "workspace_member_usage_limit_reached", ]); +export type V2GetAccountRateLimitsResponse__RateLimitResetCreditStatus = + | "available" + | "redeeming" + | "redeemed" + | "unknown"; +export const V2GetAccountRateLimitsResponse__RateLimitResetCreditStatus = Schema.Literals([ + "available", + "redeeming", + "redeemed", + "unknown", +]); + +export type V2GetAccountRateLimitsResponse__RateLimitResetType = "codexRateLimits" | "unknown"; +export const V2GetAccountRateLimitsResponse__RateLimitResetType = Schema.Literals([ + "codexRateLimits", + "unknown", +]); + export type V2GetAccountRateLimitsResponse__RateLimitWindow = { readonly resetsAt?: number | null; readonly usedPercent: number; @@ -4082,6 +4278,16 @@ export const V2GetAccountTokenUsageResponse__AccountTokenUsageSummary = Schema.S ), }); +export type V2GetWorkspaceMessagesResponse__WorkspaceMessageType = + | "headline" + | "announcement" + | "unknown"; +export const V2GetWorkspaceMessagesResponse__WorkspaceMessageType = Schema.Literals([ + "headline", + "announcement", + "unknown", +]); + export type V2HookCompletedNotification__AbsolutePathBuf = string; export const V2HookCompletedNotification__AbsolutePathBuf = Schema.String.annotate({ description: @@ -4095,6 +4301,7 @@ export type V2HookCompletedNotification__HookEventName = | "preCompact" | "postCompact" | "sessionStart" + | "sessionEnd" | "userPromptSubmit" | "subagentStart" | "subagentStop" @@ -4106,6 +4313,7 @@ export const V2HookCompletedNotification__HookEventName = Schema.Literals([ "preCompact", "postCompact", "sessionStart", + "sessionEnd", "userPromptSubmit", "subagentStart", "subagentStop", @@ -4175,6 +4383,7 @@ export type V2HooksListResponse__HookEventName = | "preCompact" | "postCompact" | "sessionStart" + | "sessionEnd" | "userPromptSubmit" | "subagentStart" | "subagentStop" @@ -4186,6 +4395,7 @@ export const V2HooksListResponse__HookEventName = Schema.Literals([ "preCompact", "postCompact", "sessionStart", + "sessionEnd", "userPromptSubmit", "subagentStart", "subagentStop", @@ -4242,6 +4452,7 @@ export type V2HookStartedNotification__HookEventName = | "preCompact" | "postCompact" | "sessionStart" + | "sessionEnd" | "userPromptSubmit" | "subagentStart" | "subagentStop" @@ -4253,6 +4464,7 @@ export const V2HookStartedNotification__HookEventName = Schema.Literals([ "preCompact", "postCompact", "sessionStart", + "sessionEnd", "userPromptSubmit", "subagentStart", "subagentStop", @@ -4338,7 +4550,8 @@ export const V2ItemCompletedNotification__CommandExecutionStatus = Schema.Litera export type V2ItemCompletedNotification__DynamicToolCallOutputContentItem = | { readonly text: string; readonly type: "inputText" } - | { readonly imageUrl: string; readonly type: "inputImage" }; + | { readonly imageUrl: string; readonly type: "inputImage" } + | { readonly audioUrl: string; readonly type: "inputAudio" }; export const V2ItemCompletedNotification__DynamicToolCallOutputContentItem = Schema.Union( [ Schema.Struct({ @@ -4353,6 +4566,12 @@ export const V2ItemCompletedNotification__DynamicToolCallOutputContentItem = Sch title: "InputImageDynamicToolCallOutputContentItemType", }), }).annotate({ title: "InputImageDynamicToolCallOutputContentItem" }), + Schema.Struct({ + audioUrl: Schema.String, + type: Schema.Literal("inputAudio").annotate({ + title: "InputAudioDynamicToolCallOutputContentItemType", + }), + }).annotate({ title: "InputAudioDynamicToolCallOutputContentItem" }), ], { mode: "oneOf" }, ); @@ -4384,6 +4603,24 @@ export const V2ItemCompletedNotification__ImageDetail = Schema.Literals([ "original", ]); +export type V2ItemCompletedNotification__LegacyAppPathString = string; +export const V2ItemCompletedNotification__LegacyAppPathString = Schema.String; + +export type V2ItemCompletedNotification__McpToolCallAppContext = { + readonly actionName?: string | null; + readonly appName?: string | null; + readonly connectorId: string; + readonly linkId?: string | null; + readonly resourceUri?: string | null; +}; +export const V2ItemCompletedNotification__McpToolCallAppContext = Schema.Struct({ + actionName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + appName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + connectorId: Schema.String, + linkId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + resourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), +}); + export type V2ItemCompletedNotification__McpToolCallError = { readonly message: string }; export const V2ItemCompletedNotification__McpToolCallError = Schema.Struct({ message: Schema.String, @@ -4563,41 +4800,6 @@ export type V2ItemGuardianApprovalReviewCompletedNotification__FileSystemAccessM export const V2ItemGuardianApprovalReviewCompletedNotification__FileSystemAccessMode = Schema.Literals(["read", "write", "deny"]); -export type V2ItemGuardianApprovalReviewCompletedNotification__FileSystemSpecialPath = - | { readonly kind: "root" } - | { readonly kind: "minimal" } - | { readonly kind: "project_roots"; readonly subpath?: string | null } - | { readonly kind: "tmpdir" } - | { readonly kind: "slash_tmp" } - | { readonly kind: "unknown"; readonly path: string; readonly subpath?: string | null }; -export const V2ItemGuardianApprovalReviewCompletedNotification__FileSystemSpecialPath = - Schema.Union( - [ - Schema.Struct({ kind: Schema.Literal("root") }).annotate({ - title: "RootFileSystemSpecialPath", - }), - Schema.Struct({ kind: Schema.Literal("minimal") }).annotate({ - title: "MinimalFileSystemSpecialPath", - }), - Schema.Struct({ - kind: Schema.Literal("project_roots"), - subpath: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), - }).annotate({ title: "KindFileSystemSpecialPath" }), - Schema.Struct({ kind: Schema.Literal("tmpdir") }).annotate({ - title: "TmpdirFileSystemSpecialPath", - }), - Schema.Struct({ kind: Schema.Literal("slash_tmp") }).annotate({ - title: "SlashTmpFileSystemSpecialPath", - }), - Schema.Struct({ - kind: Schema.Literal("unknown"), - path: Schema.String, - subpath: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), - }), - ], - { mode: "oneOf" }, - ); - export type V2ItemGuardianApprovalReviewCompletedNotification__GuardianApprovalReviewStatus = | "inProgress" | "approved" @@ -4634,6 +4836,9 @@ export const V2ItemGuardianApprovalReviewCompletedNotification__GuardianUserAuth description: "[UNSTABLE] Authorization level assigned by approval auto-review.", }); +export type V2ItemGuardianApprovalReviewCompletedNotification__LegacyAppPathString = string; +export const V2ItemGuardianApprovalReviewCompletedNotification__LegacyAppPathString = Schema.String; + export type V2ItemGuardianApprovalReviewCompletedNotification__NetworkApprovalProtocol = | "http" | "https" @@ -4662,40 +4867,6 @@ export type V2ItemGuardianApprovalReviewStartedNotification__FileSystemAccessMod export const V2ItemGuardianApprovalReviewStartedNotification__FileSystemAccessMode = Schema.Literals(["read", "write", "deny"]); -export type V2ItemGuardianApprovalReviewStartedNotification__FileSystemSpecialPath = - | { readonly kind: "root" } - | { readonly kind: "minimal" } - | { readonly kind: "project_roots"; readonly subpath?: string | null } - | { readonly kind: "tmpdir" } - | { readonly kind: "slash_tmp" } - | { readonly kind: "unknown"; readonly path: string; readonly subpath?: string | null }; -export const V2ItemGuardianApprovalReviewStartedNotification__FileSystemSpecialPath = Schema.Union( - [ - Schema.Struct({ kind: Schema.Literal("root") }).annotate({ - title: "RootFileSystemSpecialPath", - }), - Schema.Struct({ kind: Schema.Literal("minimal") }).annotate({ - title: "MinimalFileSystemSpecialPath", - }), - Schema.Struct({ - kind: Schema.Literal("project_roots"), - subpath: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), - }).annotate({ title: "KindFileSystemSpecialPath" }), - Schema.Struct({ kind: Schema.Literal("tmpdir") }).annotate({ - title: "TmpdirFileSystemSpecialPath", - }), - Schema.Struct({ kind: Schema.Literal("slash_tmp") }).annotate({ - title: "SlashTmpFileSystemSpecialPath", - }), - Schema.Struct({ - kind: Schema.Literal("unknown"), - path: Schema.String, - subpath: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), - }), - ], - { mode: "oneOf" }, -); - export type V2ItemGuardianApprovalReviewStartedNotification__GuardianApprovalReviewStatus = | "inProgress" | "approved" @@ -4735,6 +4906,9 @@ export const V2ItemGuardianApprovalReviewStartedNotification__GuardianUserAuthor description: "[UNSTABLE] Authorization level assigned by approval auto-review.", }); +export type V2ItemGuardianApprovalReviewStartedNotification__LegacyAppPathString = string; +export const V2ItemGuardianApprovalReviewStartedNotification__LegacyAppPathString = Schema.String; + export type V2ItemGuardianApprovalReviewStartedNotification__NetworkApprovalProtocol = | "http" | "https" @@ -4781,7 +4955,8 @@ export const V2ItemStartedNotification__CommandExecutionStatus = Schema.Literals export type V2ItemStartedNotification__DynamicToolCallOutputContentItem = | { readonly text: string; readonly type: "inputText" } - | { readonly imageUrl: string; readonly type: "inputImage" }; + | { readonly imageUrl: string; readonly type: "inputImage" } + | { readonly audioUrl: string; readonly type: "inputAudio" }; export const V2ItemStartedNotification__DynamicToolCallOutputContentItem = Schema.Union( [ Schema.Struct({ @@ -4796,6 +4971,12 @@ export const V2ItemStartedNotification__DynamicToolCallOutputContentItem = Schem title: "InputImageDynamicToolCallOutputContentItemType", }), }).annotate({ title: "InputImageDynamicToolCallOutputContentItem" }), + Schema.Struct({ + audioUrl: Schema.String, + type: Schema.Literal("inputAudio").annotate({ + title: "InputAudioDynamicToolCallOutputContentItemType", + }), + }).annotate({ title: "InputAudioDynamicToolCallOutputContentItem" }), ], { mode: "oneOf" }, ); @@ -4827,6 +5008,24 @@ export const V2ItemStartedNotification__ImageDetail = Schema.Literals([ "original", ]); +export type V2ItemStartedNotification__LegacyAppPathString = string; +export const V2ItemStartedNotification__LegacyAppPathString = Schema.String; + +export type V2ItemStartedNotification__McpToolCallAppContext = { + readonly actionName?: string | null; + readonly appName?: string | null; + readonly connectorId: string; + readonly linkId?: string | null; + readonly resourceUri?: string | null; +}; +export const V2ItemStartedNotification__McpToolCallAppContext = Schema.Struct({ + actionName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + appName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + connectorId: Schema.String, + linkId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + resourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), +}); + export type V2ItemStartedNotification__McpToolCallError = { readonly message: string }; export const V2ItemStartedNotification__McpToolCallError = Schema.Struct({ message: Schema.String, @@ -5078,6 +5277,9 @@ export const V2ListMcpServerStatusResponse__Tool = Schema.Struct({ title: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), }).annotate({ description: "Definition for a tool the client can call." }); +export type V2LoginAccountParams__LoginAppBrand = "codex" | "chatgpt"; +export const V2LoginAccountParams__LoginAppBrand = Schema.Literals(["codex", "chatgpt"]); + export type V2MarketplaceAddResponse__AbsolutePathBuf = string; export const V2MarketplaceAddResponse__AbsolutePathBuf = Schema.String.annotate({ description: @@ -5133,6 +5335,12 @@ export const V2McpResourceReadResponse__ResourceContent = Schema.Union([ }), ]).annotate({ description: "Contents returned when reading a resource from an MCP server." }); +export type V2McpServerStatusUpdatedNotification__McpServerStartupFailureReason = + "reauthenticationRequired"; +export const V2McpServerStatusUpdatedNotification__McpServerStartupFailureReason = Schema.Literal( + "reauthenticationRequired", +); + export type V2McpServerStatusUpdatedNotification__McpServerStartupState = | "starting" | "ready" @@ -5145,10 +5353,12 @@ export const V2McpServerStatusUpdatedNotification__McpServerStartupState = Schem "cancelled", ]); -export type V2ModelListResponse__InputModality = "text" | "image"; -export const V2ModelListResponse__InputModality = Schema.Literals(["text", "image"]).annotate({ - description: "Canonical user-input modality tags advertised by a model.", -}); +export type V2ModelListResponse__InputModality = "text" | "image" | "audio"; +export const V2ModelListResponse__InputModality = Schema.Literals([ + "text", + "image", + "audio", +]).annotate({ description: "Canonical user-input modality tags advertised by a model." }); export type V2ModelListResponse__ModelAvailabilityNux = { readonly message: string }; export const V2ModelListResponse__ModelAvailabilityNux = Schema.Struct({ message: Schema.String }); @@ -5191,10 +5401,14 @@ export const V2ModelVerificationNotification__ModelVerification = Schema.Literal("trustedAccessForCyber"); export type V2PermissionProfileListResponse__PermissionProfileSummary = { + readonly allowed: boolean; readonly description?: string | null; readonly id: string; }; export const V2PermissionProfileListResponse__PermissionProfileSummary = Schema.Struct({ + allowed: Schema.Boolean.annotate({ + description: "Whether the effective requirements allow selecting this profile.", + }), description: Schema.optionalKey( Schema.Union([ Schema.String.annotate({ @@ -5241,6 +5455,14 @@ export const V2PluginInstalledResponse__PluginInstallPolicy = Schema.Literals([ "INSTALLED_BY_DEFAULT", ]); +export type V2PluginInstalledResponse__PluginInstallPolicySource = + | "WORKSPACE_SETTING" + | "IMPLICIT_CANONICAL_APP"; +export const V2PluginInstalledResponse__PluginInstallPolicySource = Schema.Literals([ + "WORKSPACE_SETTING", + "IMPLICIT_CANONICAL_APP", +]); + export type V2PluginInstalledResponse__PluginShareDiscoverability = | "LISTED" | "UNLISTED" @@ -5272,18 +5494,18 @@ export const V2PluginInstallParams__AbsolutePathBuf = Schema.String.annotate({ }); export type V2PluginInstallResponse__AppSummary = { + readonly category?: string | null; readonly description?: string | null; readonly id: string; readonly installUrl?: string | null; readonly name: string; - readonly needsAuth: boolean; }; export const V2PluginInstallResponse__AppSummary = Schema.Struct({ + category: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), description: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), id: Schema.String, installUrl: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), name: Schema.String, - needsAuth: Schema.Boolean, }).annotate({ description: "EXPERIMENTAL - app metadata summary for plugin responses." }); export type V2PluginInstallResponse__PluginAuthPolicy = "ON_INSTALL" | "ON_USE"; @@ -5299,12 +5521,14 @@ export type V2PluginListParams__PluginListMarketplaceKind = | "local" | "vertical" | "workspace-directory" - | "shared-with-me"; + | "shared-with-me" + | "created-by-me-remote"; export const V2PluginListParams__PluginListMarketplaceKind = Schema.Literals([ "local", "vertical", "workspace-directory", "shared-with-me", + "created-by-me-remote", ]); export type V2PluginListResponse__AbsolutePathBuf = string; @@ -5331,6 +5555,14 @@ export const V2PluginListResponse__PluginInstallPolicy = Schema.Literals([ "INSTALLED_BY_DEFAULT", ]); +export type V2PluginListResponse__PluginInstallPolicySource = + | "WORKSPACE_SETTING" + | "IMPLICIT_CANONICAL_APP"; +export const V2PluginListResponse__PluginInstallPolicySource = Schema.Literals([ + "WORKSPACE_SETTING", + "IMPLICIT_CANONICAL_APP", +]); + export type V2PluginListResponse__PluginShareDiscoverability = "LISTED" | "UNLISTED" | "PRIVATE"; export const V2PluginListResponse__PluginShareDiscoverability = Schema.Literals([ "LISTED", @@ -5365,18 +5597,18 @@ export const V2PluginReadResponse__AbsolutePathBuf = Schema.String.annotate({ }); export type V2PluginReadResponse__AppSummary = { + readonly category?: string | null; readonly description?: string | null; readonly id: string; readonly installUrl?: string | null; readonly name: string; - readonly needsAuth: boolean; }; export const V2PluginReadResponse__AppSummary = Schema.Struct({ + category: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), description: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), id: Schema.String, installUrl: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), name: Schema.String, - needsAuth: Schema.Boolean, }).annotate({ description: "EXPERIMENTAL - app metadata summary for plugin responses." }); export type V2PluginReadResponse__AppTemplateUnavailableReason = @@ -5394,6 +5626,7 @@ export type V2PluginReadResponse__HookEventName = | "preCompact" | "postCompact" | "sessionStart" + | "sessionEnd" | "userPromptSubmit" | "subagentStart" | "subagentStop" @@ -5405,6 +5638,7 @@ export const V2PluginReadResponse__HookEventName = Schema.Literals([ "preCompact", "postCompact", "sessionStart", + "sessionEnd", "userPromptSubmit", "subagentStart", "subagentStop", @@ -5424,6 +5658,14 @@ export const V2PluginReadResponse__PluginInstallPolicy = Schema.Literals([ "INSTALLED_BY_DEFAULT", ]); +export type V2PluginReadResponse__PluginInstallPolicySource = + | "WORKSPACE_SETTING" + | "IMPLICIT_CANONICAL_APP"; +export const V2PluginReadResponse__PluginInstallPolicySource = Schema.Literals([ + "WORKSPACE_SETTING", + "IMPLICIT_CANONICAL_APP", +]); + export type V2PluginReadResponse__PluginShareDiscoverability = "LISTED" | "UNLISTED" | "PRIVATE"; export const V2PluginReadResponse__PluginShareDiscoverability = Schema.Literals([ "LISTED", @@ -5445,6 +5687,24 @@ export const V2PluginReadResponse__PluginSharePrincipalType = Schema.Literals([ "workspace", ]); +export type V2PluginReadResponse__ScheduledTaskWeekday = + | "MO" + | "TU" + | "WE" + | "TH" + | "FR" + | "SA" + | "SU"; +export const V2PluginReadResponse__ScheduledTaskWeekday = Schema.Literals([ + "MO", + "TU", + "WE", + "TH", + "FR", + "SA", + "SU", +]); + export type V2PluginShareCheckoutResponse__AbsolutePathBuf = string; export const V2PluginShareCheckoutResponse__AbsolutePathBuf = Schema.String.annotate({ description: @@ -5473,6 +5733,14 @@ export const V2PluginShareListResponse__PluginInstallPolicy = Schema.Literals([ "INSTALLED_BY_DEFAULT", ]); +export type V2PluginShareListResponse__PluginInstallPolicySource = + | "WORKSPACE_SETTING" + | "IMPLICIT_CANONICAL_APP"; +export const V2PluginShareListResponse__PluginInstallPolicySource = Schema.Literals([ + "WORKSPACE_SETTING", + "IMPLICIT_CANONICAL_APP", +]); + export type V2PluginShareListResponse__PluginShareDiscoverability = | "LISTED" | "UNLISTED" @@ -5538,10 +5806,12 @@ export const V2PluginShareUpdateTargetsParams__PluginShareTargetRole = Schema.Li export type V2PluginShareUpdateTargetsParams__PluginShareUpdateDiscoverability = | "UNLISTED" - | "PRIVATE"; + | "PRIVATE" + | "LISTED"; export const V2PluginShareUpdateTargetsParams__PluginShareUpdateDiscoverability = Schema.Literals([ "UNLISTED", "PRIVATE", + "LISTED", ]); export type V2PluginShareUpdateTargetsResponse__PluginShareDiscoverability = @@ -5574,12 +5844,36 @@ export const V2PluginShareUpdateTargetsResponse__PluginSharePrincipalType = Sche "workspace", ]); -export type V2RawResponseItemCompletedNotification__AgentMessageInputContent = { - readonly encrypted_content: string; - readonly type: "encrypted_content"; +export type V2RawResponseCompletedNotification__TokenUsageBreakdown = { + readonly cacheWriteInputTokens?: number; + readonly cachedInputTokens: number; + readonly inputTokens: number; + readonly outputTokens: number; + readonly reasoningOutputTokens: number; + readonly totalTokens: number; }; +export const V2RawResponseCompletedNotification__TokenUsageBreakdown = Schema.Struct({ + cacheWriteInputTokens: Schema.optionalKey( + Schema.Number.annotate({ default: 0, format: "int64" }).check(Schema.isInt()), + ), + cachedInputTokens: Schema.Number.annotate({ format: "int64" }).check(Schema.isInt()), + inputTokens: Schema.Number.annotate({ format: "int64" }).check(Schema.isInt()), + outputTokens: Schema.Number.annotate({ format: "int64" }).check(Schema.isInt()), + reasoningOutputTokens: Schema.Number.annotate({ format: "int64" }).check(Schema.isInt()), + totalTokens: Schema.Number.annotate({ format: "int64" }).check(Schema.isInt()), +}); + +export type V2RawResponseItemCompletedNotification__AgentMessageInputContent = + | { readonly text: string; readonly type: "input_text" } + | { readonly encrypted_content: string; readonly type: "encrypted_content" }; export const V2RawResponseItemCompletedNotification__AgentMessageInputContent = Schema.Union( [ + Schema.Struct({ + text: Schema.String, + type: Schema.Literal("input_text").annotate({ + title: "InputTextAgentMessageInputContentType", + }), + }).annotate({ title: "InputTextAgentMessageInputContent" }), Schema.Struct({ encrypted_content: Schema.String, type: Schema.Literal("encrypted_content").annotate({ @@ -5602,6 +5896,17 @@ export const V2RawResponseItemCompletedNotification__ImageDetail = Schema.Litera "original", ]); +export type V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough = { + readonly turn_id?: string | null; +}; +export const V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough = + Schema.Struct({ + turn_id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + }).annotate({ + description: + "Internal Responses API passthrough metadata copied into underlying chat messages.\n\nResponses API strongly types this payload. Do not modify it without first getting API approval and making the corresponding Responses API change.", + }); + export type V2RawResponseItemCompletedNotification__LocalShellAction = { readonly command: ReadonlyArray; readonly env?: { readonly [x: string]: string } | null; @@ -5824,7 +6129,8 @@ export const V2ReviewStartResponse__CommandExecutionStatus = Schema.Literals([ export type V2ReviewStartResponse__DynamicToolCallOutputContentItem = | { readonly text: string; readonly type: "inputText" } - | { readonly imageUrl: string; readonly type: "inputImage" }; + | { readonly imageUrl: string; readonly type: "inputImage" } + | { readonly audioUrl: string; readonly type: "inputAudio" }; export const V2ReviewStartResponse__DynamicToolCallOutputContentItem = Schema.Union( [ Schema.Struct({ @@ -5839,6 +6145,12 @@ export const V2ReviewStartResponse__DynamicToolCallOutputContentItem = Schema.Un title: "InputImageDynamicToolCallOutputContentItemType", }), }).annotate({ title: "InputImageDynamicToolCallOutputContentItem" }), + Schema.Struct({ + audioUrl: Schema.String, + type: Schema.Literal("inputAudio").annotate({ + title: "InputAudioDynamicToolCallOutputContentItemType", + }), + }).annotate({ title: "InputAudioDynamicToolCallOutputContentItem" }), ], { mode: "oneOf" }, ); @@ -5867,6 +6179,24 @@ export const V2ReviewStartResponse__ImageDetail = Schema.Literals([ "original", ]); +export type V2ReviewStartResponse__LegacyAppPathString = string; +export const V2ReviewStartResponse__LegacyAppPathString = Schema.String; + +export type V2ReviewStartResponse__McpToolCallAppContext = { + readonly actionName?: string | null; + readonly appName?: string | null; + readonly connectorId: string; + readonly linkId?: string | null; + readonly resourceUri?: string | null; +}; +export const V2ReviewStartResponse__McpToolCallAppContext = Schema.Struct({ + actionName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + appName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + connectorId: Schema.String, + linkId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + resourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), +}); + export type V2ReviewStartResponse__McpToolCallError = { readonly message: string }; export const V2ReviewStartResponse__McpToolCallError = Schema.Struct({ message: Schema.String }); @@ -6114,7 +6444,6 @@ export const V2ThreadForkParams__ApprovalsReviewer = Schema.Literals([ export type V2ThreadForkParams__AskForApproval = | "untrusted" - | "on-failure" | "on-request" | "never" | { @@ -6128,7 +6457,7 @@ export type V2ThreadForkParams__AskForApproval = }; export const V2ThreadForkParams__AskForApproval = Schema.Union( [ - Schema.Literals(["untrusted", "on-failure", "on-request", "never"]), + Schema.Literals(["untrusted", "on-request", "never"]), Schema.Struct({ granular: Schema.Struct({ mcp_elicitations: Schema.Boolean, @@ -6166,7 +6495,6 @@ export const V2ThreadForkResponse__AgentPath = Schema.String; export type V2ThreadForkResponse__AskForApproval = | "untrusted" - | "on-failure" | "on-request" | "never" | { @@ -6180,7 +6508,7 @@ export type V2ThreadForkResponse__AskForApproval = }; export const V2ThreadForkResponse__AskForApproval = Schema.Union( [ - Schema.Literals(["untrusted", "on-failure", "on-request", "never"]), + Schema.Literals(["untrusted", "on-request", "never"]), Schema.Struct({ granular: Schema.Struct({ mcp_elicitations: Schema.Boolean, @@ -6226,7 +6554,8 @@ export const V2ThreadForkResponse__CommandExecutionStatus = Schema.Literals([ export type V2ThreadForkResponse__DynamicToolCallOutputContentItem = | { readonly text: string; readonly type: "inputText" } - | { readonly imageUrl: string; readonly type: "inputImage" }; + | { readonly imageUrl: string; readonly type: "inputImage" } + | { readonly audioUrl: string; readonly type: "inputAudio" }; export const V2ThreadForkResponse__DynamicToolCallOutputContentItem = Schema.Union( [ Schema.Struct({ @@ -6241,6 +6570,12 @@ export const V2ThreadForkResponse__DynamicToolCallOutputContentItem = Schema.Uni title: "InputImageDynamicToolCallOutputContentItemType", }), }).annotate({ title: "InputImageDynamicToolCallOutputContentItem" }), + Schema.Struct({ + audioUrl: Schema.String, + type: Schema.Literal("inputAudio").annotate({ + title: "InputAudioDynamicToolCallOutputContentItemType", + }), + }).annotate({ title: "InputAudioDynamicToolCallOutputContentItem" }), ], { mode: "oneOf" }, ); @@ -6280,6 +6615,24 @@ export const V2ThreadForkResponse__ImageDetail = Schema.Literals([ "original", ]); +export type V2ThreadForkResponse__LegacyAppPathString = string; +export const V2ThreadForkResponse__LegacyAppPathString = Schema.String; + +export type V2ThreadForkResponse__McpToolCallAppContext = { + readonly actionName?: string | null; + readonly appName?: string | null; + readonly connectorId: string; + readonly linkId?: string | null; + readonly resourceUri?: string | null; +}; +export const V2ThreadForkResponse__McpToolCallAppContext = Schema.Struct({ + actionName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + appName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + connectorId: Schema.String, + linkId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + resourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), +}); + export type V2ThreadForkResponse__McpToolCallError = { readonly message: string }; export const V2ThreadForkResponse__McpToolCallError = Schema.Struct({ message: Schema.String }); @@ -6528,8 +6881,12 @@ export const V2ThreadListParams__ThreadListCwdFilter = Schema.Union([ Schema.Array(Schema.String), ]); -export type V2ThreadListParams__ThreadSortKey = "created_at" | "updated_at"; -export const V2ThreadListParams__ThreadSortKey = Schema.Literals(["created_at", "updated_at"]); +export type V2ThreadListParams__ThreadSortKey = "created_at" | "updated_at" | "recency_at"; +export const V2ThreadListParams__ThreadSortKey = Schema.Literals([ + "created_at", + "updated_at", + "recency_at", +]); export type V2ThreadListParams__ThreadSourceKind = | "cli" @@ -6596,7 +6953,8 @@ export const V2ThreadListResponse__CommandExecutionStatus = Schema.Literals([ export type V2ThreadListResponse__DynamicToolCallOutputContentItem = | { readonly text: string; readonly type: "inputText" } - | { readonly imageUrl: string; readonly type: "inputImage" }; + | { readonly imageUrl: string; readonly type: "inputImage" } + | { readonly audioUrl: string; readonly type: "inputAudio" }; export const V2ThreadListResponse__DynamicToolCallOutputContentItem = Schema.Union( [ Schema.Struct({ @@ -6611,6 +6969,12 @@ export const V2ThreadListResponse__DynamicToolCallOutputContentItem = Schema.Uni title: "InputImageDynamicToolCallOutputContentItemType", }), }).annotate({ title: "InputImageDynamicToolCallOutputContentItem" }), + Schema.Struct({ + audioUrl: Schema.String, + type: Schema.Literal("inputAudio").annotate({ + title: "InputAudioDynamicToolCallOutputContentItemType", + }), + }).annotate({ title: "InputAudioDynamicToolCallOutputContentItem" }), ], { mode: "oneOf" }, ); @@ -6650,6 +7014,24 @@ export const V2ThreadListResponse__ImageDetail = Schema.Literals([ "original", ]); +export type V2ThreadListResponse__LegacyAppPathString = string; +export const V2ThreadListResponse__LegacyAppPathString = Schema.String; + +export type V2ThreadListResponse__McpToolCallAppContext = { + readonly actionName?: string | null; + readonly appName?: string | null; + readonly connectorId: string; + readonly linkId?: string | null; + readonly resourceUri?: string | null; +}; +export const V2ThreadListResponse__McpToolCallAppContext = Schema.Struct({ + actionName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + appName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + connectorId: Schema.String, + linkId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + resourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), +}); + export type V2ThreadListResponse__McpToolCallError = { readonly message: string }; export const V2ThreadListResponse__McpToolCallError = Schema.Struct({ message: Schema.String }); @@ -6901,7 +7283,8 @@ export const V2ThreadMetadataUpdateResponse__CommandExecutionStatus = Schema.Lit export type V2ThreadMetadataUpdateResponse__DynamicToolCallOutputContentItem = | { readonly text: string; readonly type: "inputText" } - | { readonly imageUrl: string; readonly type: "inputImage" }; + | { readonly imageUrl: string; readonly type: "inputImage" } + | { readonly audioUrl: string; readonly type: "inputAudio" }; export const V2ThreadMetadataUpdateResponse__DynamicToolCallOutputContentItem = Schema.Union( [ Schema.Struct({ @@ -6916,6 +7299,12 @@ export const V2ThreadMetadataUpdateResponse__DynamicToolCallOutputContentItem = title: "InputImageDynamicToolCallOutputContentItemType", }), }).annotate({ title: "InputImageDynamicToolCallOutputContentItem" }), + Schema.Struct({ + audioUrl: Schema.String, + type: Schema.Literal("inputAudio").annotate({ + title: "InputAudioDynamicToolCallOutputContentItemType", + }), + }).annotate({ title: "InputAudioDynamicToolCallOutputContentItem" }), ], { mode: "oneOf" }, ); @@ -6958,6 +7347,24 @@ export const V2ThreadMetadataUpdateResponse__ImageDetail = Schema.Literals([ "original", ]); +export type V2ThreadMetadataUpdateResponse__LegacyAppPathString = string; +export const V2ThreadMetadataUpdateResponse__LegacyAppPathString = Schema.String; + +export type V2ThreadMetadataUpdateResponse__McpToolCallAppContext = { + readonly actionName?: string | null; + readonly appName?: string | null; + readonly connectorId: string; + readonly linkId?: string | null; + readonly resourceUri?: string | null; +}; +export const V2ThreadMetadataUpdateResponse__McpToolCallAppContext = Schema.Struct({ + actionName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + appName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + connectorId: Schema.String, + linkId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + resourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), +}); + export type V2ThreadMetadataUpdateResponse__McpToolCallError = { readonly message: string }; export const V2ThreadMetadataUpdateResponse__McpToolCallError = Schema.Struct({ message: Schema.String, @@ -7187,7 +7594,8 @@ export const V2ThreadReadResponse__CommandExecutionStatus = Schema.Literals([ export type V2ThreadReadResponse__DynamicToolCallOutputContentItem = | { readonly text: string; readonly type: "inputText" } - | { readonly imageUrl: string; readonly type: "inputImage" }; + | { readonly imageUrl: string; readonly type: "inputImage" } + | { readonly audioUrl: string; readonly type: "inputAudio" }; export const V2ThreadReadResponse__DynamicToolCallOutputContentItem = Schema.Union( [ Schema.Struct({ @@ -7202,6 +7610,12 @@ export const V2ThreadReadResponse__DynamicToolCallOutputContentItem = Schema.Uni title: "InputImageDynamicToolCallOutputContentItemType", }), }).annotate({ title: "InputImageDynamicToolCallOutputContentItem" }), + Schema.Struct({ + audioUrl: Schema.String, + type: Schema.Literal("inputAudio").annotate({ + title: "InputAudioDynamicToolCallOutputContentItemType", + }), + }).annotate({ title: "InputAudioDynamicToolCallOutputContentItem" }), ], { mode: "oneOf" }, ); @@ -7241,6 +7655,24 @@ export const V2ThreadReadResponse__ImageDetail = Schema.Literals([ "original", ]); +export type V2ThreadReadResponse__LegacyAppPathString = string; +export const V2ThreadReadResponse__LegacyAppPathString = Schema.String; + +export type V2ThreadReadResponse__McpToolCallAppContext = { + readonly actionName?: string | null; + readonly appName?: string | null; + readonly connectorId: string; + readonly linkId?: string | null; + readonly resourceUri?: string | null; +}; +export const V2ThreadReadResponse__McpToolCallAppContext = Schema.Struct({ + actionName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + appName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + connectorId: Schema.String, + linkId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + resourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), +}); + export type V2ThreadReadResponse__McpToolCallError = { readonly message: string }; export const V2ThreadReadResponse__McpToolCallError = Schema.Struct({ message: Schema.String }); @@ -7444,18 +7876,24 @@ export const V2ThreadRealtimeOutputAudioDeltaNotification__ThreadRealtimeAudioCh }, ).annotate({ description: "EXPERIMENTAL - thread realtime audio chunk." }); -export type V2ThreadRealtimeStartedNotification__RealtimeConversationVersion = "v1" | "v2"; +export type V2ThreadRealtimeStartedNotification__RealtimeConversationVersion = "v1" | "v2" | "v3"; export const V2ThreadRealtimeStartedNotification__RealtimeConversationVersion = Schema.Literals([ "v1", "v2", + "v3", ]); -export type V2ThreadResumeParams__AgentMessageInputContent = { - readonly encrypted_content: string; - readonly type: "encrypted_content"; -}; +export type V2ThreadResumeParams__AgentMessageInputContent = + | { readonly text: string; readonly type: "input_text" } + | { readonly encrypted_content: string; readonly type: "encrypted_content" }; export const V2ThreadResumeParams__AgentMessageInputContent = Schema.Union( [ + Schema.Struct({ + text: Schema.String, + type: Schema.Literal("input_text").annotate({ + title: "InputTextAgentMessageInputContentType", + }), + }).annotate({ title: "InputTextAgentMessageInputContent" }), Schema.Struct({ encrypted_content: Schema.String, type: Schema.Literal("encrypted_content").annotate({ @@ -7478,7 +7916,6 @@ export const V2ThreadResumeParams__ApprovalsReviewer = Schema.Literals([ export type V2ThreadResumeParams__AskForApproval = | "untrusted" - | "on-failure" | "on-request" | "never" | { @@ -7492,7 +7929,7 @@ export type V2ThreadResumeParams__AskForApproval = }; export const V2ThreadResumeParams__AskForApproval = Schema.Union( [ - Schema.Literals(["untrusted", "on-failure", "on-request", "never"]), + Schema.Literals(["untrusted", "on-request", "never"]), Schema.Struct({ granular: Schema.Struct({ mcp_elicitations: Schema.Boolean, @@ -7514,6 +7951,16 @@ export const V2ThreadResumeParams__ImageDetail = Schema.Literals([ "original", ]); +export type V2ThreadResumeParams__InternalChatMessageMetadataPassthrough = { + readonly turn_id?: string | null; +}; +export const V2ThreadResumeParams__InternalChatMessageMetadataPassthrough = Schema.Struct({ + turn_id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), +}).annotate({ + description: + "Internal Responses API passthrough metadata copied into underlying chat messages.\n\nResponses API strongly types this payload. Do not modify it without first getting API approval and making the corresponding Responses API change.", +}); + export type V2ThreadResumeParams__LocalShellAction = { readonly command: ReadonlyArray; readonly env?: { readonly [x: string]: string } | null; @@ -7670,7 +8117,6 @@ export const V2ThreadResumeResponse__AgentPath = Schema.String; export type V2ThreadResumeResponse__AskForApproval = | "untrusted" - | "on-failure" | "on-request" | "never" | { @@ -7684,7 +8130,7 @@ export type V2ThreadResumeResponse__AskForApproval = }; export const V2ThreadResumeResponse__AskForApproval = Schema.Union( [ - Schema.Literals(["untrusted", "on-failure", "on-request", "never"]), + Schema.Literals(["untrusted", "on-request", "never"]), Schema.Struct({ granular: Schema.Struct({ mcp_elicitations: Schema.Boolean, @@ -7730,7 +8176,8 @@ export const V2ThreadResumeResponse__CommandExecutionStatus = Schema.Literals([ export type V2ThreadResumeResponse__DynamicToolCallOutputContentItem = | { readonly text: string; readonly type: "inputText" } - | { readonly imageUrl: string; readonly type: "inputImage" }; + | { readonly imageUrl: string; readonly type: "inputImage" } + | { readonly audioUrl: string; readonly type: "inputAudio" }; export const V2ThreadResumeResponse__DynamicToolCallOutputContentItem = Schema.Union( [ Schema.Struct({ @@ -7745,6 +8192,12 @@ export const V2ThreadResumeResponse__DynamicToolCallOutputContentItem = Schema.U title: "InputImageDynamicToolCallOutputContentItemType", }), }).annotate({ title: "InputImageDynamicToolCallOutputContentItem" }), + Schema.Struct({ + audioUrl: Schema.String, + type: Schema.Literal("inputAudio").annotate({ + title: "InputAudioDynamicToolCallOutputContentItemType", + }), + }).annotate({ title: "InputAudioDynamicToolCallOutputContentItem" }), ], { mode: "oneOf" }, ); @@ -7784,6 +8237,24 @@ export const V2ThreadResumeResponse__ImageDetail = Schema.Literals([ "original", ]); +export type V2ThreadResumeResponse__LegacyAppPathString = string; +export const V2ThreadResumeResponse__LegacyAppPathString = Schema.String; + +export type V2ThreadResumeResponse__McpToolCallAppContext = { + readonly actionName?: string | null; + readonly appName?: string | null; + readonly connectorId: string; + readonly linkId?: string | null; + readonly resourceUri?: string | null; +}; +export const V2ThreadResumeResponse__McpToolCallAppContext = Schema.Struct({ + actionName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + appName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + connectorId: Schema.String, + linkId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + resourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), +}); + export type V2ThreadResumeResponse__McpToolCallError = { readonly message: string }; export const V2ThreadResumeResponse__McpToolCallError = Schema.Struct({ message: Schema.String }); @@ -8000,7 +8471,8 @@ export const V2ThreadRollbackResponse__CommandExecutionStatus = Schema.Literals( export type V2ThreadRollbackResponse__DynamicToolCallOutputContentItem = | { readonly text: string; readonly type: "inputText" } - | { readonly imageUrl: string; readonly type: "inputImage" }; + | { readonly imageUrl: string; readonly type: "inputImage" } + | { readonly audioUrl: string; readonly type: "inputAudio" }; export const V2ThreadRollbackResponse__DynamicToolCallOutputContentItem = Schema.Union( [ Schema.Struct({ @@ -8015,6 +8487,12 @@ export const V2ThreadRollbackResponse__DynamicToolCallOutputContentItem = Schema title: "InputImageDynamicToolCallOutputContentItemType", }), }).annotate({ title: "InputImageDynamicToolCallOutputContentItem" }), + Schema.Struct({ + audioUrl: Schema.String, + type: Schema.Literal("inputAudio").annotate({ + title: "InputAudioDynamicToolCallOutputContentItemType", + }), + }).annotate({ title: "InputAudioDynamicToolCallOutputContentItem" }), ], { mode: "oneOf" }, ); @@ -8054,6 +8532,24 @@ export const V2ThreadRollbackResponse__ImageDetail = Schema.Literals([ "original", ]); +export type V2ThreadRollbackResponse__LegacyAppPathString = string; +export const V2ThreadRollbackResponse__LegacyAppPathString = Schema.String; + +export type V2ThreadRollbackResponse__McpToolCallAppContext = { + readonly actionName?: string | null; + readonly appName?: string | null; + readonly connectorId: string; + readonly linkId?: string | null; + readonly resourceUri?: string | null; +}; +export const V2ThreadRollbackResponse__McpToolCallAppContext = Schema.Struct({ + actionName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + appName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + connectorId: Schema.String, + linkId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + resourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), +}); + export type V2ThreadRollbackResponse__McpToolCallError = { readonly message: string }; export const V2ThreadRollbackResponse__McpToolCallError = Schema.Struct({ message: Schema.String }); @@ -8276,7 +8772,6 @@ export const V2ThreadSettingsUpdatedNotification__ApprovalsReviewer = Schema.Lit export type V2ThreadSettingsUpdatedNotification__AskForApproval = | "untrusted" - | "on-failure" | "on-request" | "never" | { @@ -8290,7 +8785,7 @@ export type V2ThreadSettingsUpdatedNotification__AskForApproval = }; export const V2ThreadSettingsUpdatedNotification__AskForApproval = Schema.Union( [ - Schema.Literals(["untrusted", "on-failure", "on-request", "never"]), + Schema.Literals(["untrusted", "on-request", "never"]), Schema.Struct({ granular: Schema.Struct({ mcp_elicitations: Schema.Boolean, @@ -8379,7 +8874,8 @@ export const V2ThreadStartedNotification__CommandExecutionStatus = Schema.Litera export type V2ThreadStartedNotification__DynamicToolCallOutputContentItem = | { readonly text: string; readonly type: "inputText" } - | { readonly imageUrl: string; readonly type: "inputImage" }; + | { readonly imageUrl: string; readonly type: "inputImage" } + | { readonly audioUrl: string; readonly type: "inputAudio" }; export const V2ThreadStartedNotification__DynamicToolCallOutputContentItem = Schema.Union( [ Schema.Struct({ @@ -8394,6 +8890,12 @@ export const V2ThreadStartedNotification__DynamicToolCallOutputContentItem = Sch title: "InputImageDynamicToolCallOutputContentItemType", }), }).annotate({ title: "InputImageDynamicToolCallOutputContentItem" }), + Schema.Struct({ + audioUrl: Schema.String, + type: Schema.Literal("inputAudio").annotate({ + title: "InputAudioDynamicToolCallOutputContentItemType", + }), + }).annotate({ title: "InputAudioDynamicToolCallOutputContentItem" }), ], { mode: "oneOf" }, ); @@ -8436,6 +8938,24 @@ export const V2ThreadStartedNotification__ImageDetail = Schema.Literals([ "original", ]); +export type V2ThreadStartedNotification__LegacyAppPathString = string; +export const V2ThreadStartedNotification__LegacyAppPathString = Schema.String; + +export type V2ThreadStartedNotification__McpToolCallAppContext = { + readonly actionName?: string | null; + readonly appName?: string | null; + readonly connectorId: string; + readonly linkId?: string | null; + readonly resourceUri?: string | null; +}; +export const V2ThreadStartedNotification__McpToolCallAppContext = Schema.Struct({ + actionName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + appName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + connectorId: Schema.String, + linkId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + resourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), +}); + export type V2ThreadStartedNotification__McpToolCallError = { readonly message: string }; export const V2ThreadStartedNotification__McpToolCallError = Schema.Struct({ message: Schema.String, @@ -8621,12 +9141,6 @@ export const V2ThreadStartedNotification__WebSearchAction = Schema.Union( { mode: "oneOf" }, ); -export type V2ThreadStartParams__AbsolutePathBuf = string; -export const V2ThreadStartParams__AbsolutePathBuf = Schema.String.annotate({ - description: - "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", -}); - export type V2ThreadStartParams__ApprovalsReviewer = "user" | "auto_review" | "guardian_subagent"; export const V2ThreadStartParams__ApprovalsReviewer = Schema.Literals([ "user", @@ -8639,7 +9153,6 @@ export const V2ThreadStartParams__ApprovalsReviewer = Schema.Literals([ export type V2ThreadStartParams__AskForApproval = | "untrusted" - | "on-failure" | "on-request" | "never" | { @@ -8653,7 +9166,7 @@ export type V2ThreadStartParams__AskForApproval = }; export const V2ThreadStartParams__AskForApproval = Schema.Union( [ - Schema.Literals(["untrusted", "on-failure", "on-request", "never"]), + Schema.Literals(["untrusted", "on-request", "never"]), Schema.Struct({ granular: Schema.Struct({ mcp_elicitations: Schema.Boolean, @@ -8667,6 +9180,29 @@ export const V2ThreadStartParams__AskForApproval = Schema.Union( { mode: "oneOf" }, ); +export type V2ThreadStartParams__DynamicToolNamespaceTool = { + readonly deferLoading?: boolean; + readonly description: string; + readonly inputSchema: unknown; + readonly name: string; + readonly type: "function"; +}; +export const V2ThreadStartParams__DynamicToolNamespaceTool = Schema.Union( + [ + Schema.Struct({ + deferLoading: Schema.optionalKey(Schema.Boolean), + description: Schema.String, + inputSchema: Schema.Unknown, + name: Schema.String, + type: Schema.Literal("function").annotate({ title: "FunctionDynamicToolNamespaceToolType" }), + }).annotate({ title: "FunctionDynamicToolNamespaceTool" }), + ], + { mode: "oneOf" }, +); + +export type V2ThreadStartParams__LegacyAppPathString = string; +export const V2ThreadStartParams__LegacyAppPathString = Schema.String; + export type V2ThreadStartParams__Personality = "none" | "friendly" | "pragmatic"; export const V2ThreadStartParams__Personality = Schema.Literals(["none", "friendly", "pragmatic"]); @@ -8697,7 +9233,6 @@ export const V2ThreadStartResponse__AgentPath = Schema.String; export type V2ThreadStartResponse__AskForApproval = | "untrusted" - | "on-failure" | "on-request" | "never" | { @@ -8711,7 +9246,7 @@ export type V2ThreadStartResponse__AskForApproval = }; export const V2ThreadStartResponse__AskForApproval = Schema.Union( [ - Schema.Literals(["untrusted", "on-failure", "on-request", "never"]), + Schema.Literals(["untrusted", "on-request", "never"]), Schema.Struct({ granular: Schema.Struct({ mcp_elicitations: Schema.Boolean, @@ -8757,7 +9292,8 @@ export const V2ThreadStartResponse__CommandExecutionStatus = Schema.Literals([ export type V2ThreadStartResponse__DynamicToolCallOutputContentItem = | { readonly text: string; readonly type: "inputText" } - | { readonly imageUrl: string; readonly type: "inputImage" }; + | { readonly imageUrl: string; readonly type: "inputImage" } + | { readonly audioUrl: string; readonly type: "inputAudio" }; export const V2ThreadStartResponse__DynamicToolCallOutputContentItem = Schema.Union( [ Schema.Struct({ @@ -8772,6 +9308,12 @@ export const V2ThreadStartResponse__DynamicToolCallOutputContentItem = Schema.Un title: "InputImageDynamicToolCallOutputContentItemType", }), }).annotate({ title: "InputImageDynamicToolCallOutputContentItem" }), + Schema.Struct({ + audioUrl: Schema.String, + type: Schema.Literal("inputAudio").annotate({ + title: "InputAudioDynamicToolCallOutputContentItemType", + }), + }).annotate({ title: "InputAudioDynamicToolCallOutputContentItem" }), ], { mode: "oneOf" }, ); @@ -8811,6 +9353,24 @@ export const V2ThreadStartResponse__ImageDetail = Schema.Literals([ "original", ]); +export type V2ThreadStartResponse__LegacyAppPathString = string; +export const V2ThreadStartResponse__LegacyAppPathString = Schema.String; + +export type V2ThreadStartResponse__McpToolCallAppContext = { + readonly actionName?: string | null; + readonly appName?: string | null; + readonly connectorId: string; + readonly linkId?: string | null; + readonly resourceUri?: string | null; +}; +export const V2ThreadStartResponse__McpToolCallAppContext = Schema.Struct({ + actionName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + appName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + connectorId: Schema.String, + linkId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + resourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), +}); + export type V2ThreadStartResponse__McpToolCallError = { readonly message: string }; export const V2ThreadStartResponse__McpToolCallError = Schema.Struct({ message: Schema.String }); @@ -8995,6 +9555,7 @@ export const V2ThreadStatusChangedNotification__ThreadActiveFlag = Schema.Litera ]); export type V2ThreadTokenUsageUpdatedNotification__TokenUsageBreakdown = { + readonly cacheWriteInputTokens?: number; readonly cachedInputTokens: number; readonly inputTokens: number; readonly outputTokens: number; @@ -9002,6 +9563,9 @@ export type V2ThreadTokenUsageUpdatedNotification__TokenUsageBreakdown = { readonly totalTokens: number; }; export const V2ThreadTokenUsageUpdatedNotification__TokenUsageBreakdown = Schema.Struct({ + cacheWriteInputTokens: Schema.optionalKey( + Schema.Number.annotate({ default: 0, format: "int64" }).check(Schema.isInt()), + ), cachedInputTokens: Schema.Number.annotate({ format: "int64" }).check(Schema.isInt()), inputTokens: Schema.Number.annotate({ format: "int64" }).check(Schema.isInt()), outputTokens: Schema.Number.annotate({ format: "int64" }).check(Schema.isInt()), @@ -9050,7 +9614,8 @@ export const V2ThreadUnarchiveResponse__CommandExecutionStatus = Schema.Literals export type V2ThreadUnarchiveResponse__DynamicToolCallOutputContentItem = | { readonly text: string; readonly type: "inputText" } - | { readonly imageUrl: string; readonly type: "inputImage" }; + | { readonly imageUrl: string; readonly type: "inputImage" } + | { readonly audioUrl: string; readonly type: "inputAudio" }; export const V2ThreadUnarchiveResponse__DynamicToolCallOutputContentItem = Schema.Union( [ Schema.Struct({ @@ -9065,6 +9630,12 @@ export const V2ThreadUnarchiveResponse__DynamicToolCallOutputContentItem = Schem title: "InputImageDynamicToolCallOutputContentItemType", }), }).annotate({ title: "InputImageDynamicToolCallOutputContentItem" }), + Schema.Struct({ + audioUrl: Schema.String, + type: Schema.Literal("inputAudio").annotate({ + title: "InputAudioDynamicToolCallOutputContentItemType", + }), + }).annotate({ title: "InputAudioDynamicToolCallOutputContentItem" }), ], { mode: "oneOf" }, ); @@ -9107,6 +9678,24 @@ export const V2ThreadUnarchiveResponse__ImageDetail = Schema.Literals([ "original", ]); +export type V2ThreadUnarchiveResponse__LegacyAppPathString = string; +export const V2ThreadUnarchiveResponse__LegacyAppPathString = Schema.String; + +export type V2ThreadUnarchiveResponse__McpToolCallAppContext = { + readonly actionName?: string | null; + readonly appName?: string | null; + readonly connectorId: string; + readonly linkId?: string | null; + readonly resourceUri?: string | null; +}; +export const V2ThreadUnarchiveResponse__McpToolCallAppContext = Schema.Struct({ + actionName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + appName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + connectorId: Schema.String, + linkId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + resourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), +}); + export type V2ThreadUnarchiveResponse__McpToolCallError = { readonly message: string }; export const V2ThreadUnarchiveResponse__McpToolCallError = Schema.Struct({ message: Schema.String, @@ -9340,7 +9929,8 @@ export const V2TurnCompletedNotification__CommandExecutionStatus = Schema.Litera export type V2TurnCompletedNotification__DynamicToolCallOutputContentItem = | { readonly text: string; readonly type: "inputText" } - | { readonly imageUrl: string; readonly type: "inputImage" }; + | { readonly imageUrl: string; readonly type: "inputImage" } + | { readonly audioUrl: string; readonly type: "inputAudio" }; export const V2TurnCompletedNotification__DynamicToolCallOutputContentItem = Schema.Union( [ Schema.Struct({ @@ -9355,6 +9945,12 @@ export const V2TurnCompletedNotification__DynamicToolCallOutputContentItem = Sch title: "InputImageDynamicToolCallOutputContentItemType", }), }).annotate({ title: "InputImageDynamicToolCallOutputContentItem" }), + Schema.Struct({ + audioUrl: Schema.String, + type: Schema.Literal("inputAudio").annotate({ + title: "InputAudioDynamicToolCallOutputContentItemType", + }), + }).annotate({ title: "InputAudioDynamicToolCallOutputContentItem" }), ], { mode: "oneOf" }, ); @@ -9386,6 +9982,24 @@ export const V2TurnCompletedNotification__ImageDetail = Schema.Literals([ "original", ]); +export type V2TurnCompletedNotification__LegacyAppPathString = string; +export const V2TurnCompletedNotification__LegacyAppPathString = Schema.String; + +export type V2TurnCompletedNotification__McpToolCallAppContext = { + readonly actionName?: string | null; + readonly appName?: string | null; + readonly connectorId: string; + readonly linkId?: string | null; + readonly resourceUri?: string | null; +}; +export const V2TurnCompletedNotification__McpToolCallAppContext = Schema.Struct({ + actionName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + appName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + connectorId: Schema.String, + linkId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + resourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), +}); + export type V2TurnCompletedNotification__McpToolCallError = { readonly message: string }; export const V2TurnCompletedNotification__McpToolCallError = Schema.Struct({ message: Schema.String, @@ -9605,7 +10219,8 @@ export const V2TurnStartedNotification__CommandExecutionStatus = Schema.Literals export type V2TurnStartedNotification__DynamicToolCallOutputContentItem = | { readonly text: string; readonly type: "inputText" } - | { readonly imageUrl: string; readonly type: "inputImage" }; + | { readonly imageUrl: string; readonly type: "inputImage" } + | { readonly audioUrl: string; readonly type: "inputAudio" }; export const V2TurnStartedNotification__DynamicToolCallOutputContentItem = Schema.Union( [ Schema.Struct({ @@ -9620,6 +10235,12 @@ export const V2TurnStartedNotification__DynamicToolCallOutputContentItem = Schem title: "InputImageDynamicToolCallOutputContentItemType", }), }).annotate({ title: "InputImageDynamicToolCallOutputContentItem" }), + Schema.Struct({ + audioUrl: Schema.String, + type: Schema.Literal("inputAudio").annotate({ + title: "InputAudioDynamicToolCallOutputContentItemType", + }), + }).annotate({ title: "InputAudioDynamicToolCallOutputContentItem" }), ], { mode: "oneOf" }, ); @@ -9651,6 +10272,24 @@ export const V2TurnStartedNotification__ImageDetail = Schema.Literals([ "original", ]); +export type V2TurnStartedNotification__LegacyAppPathString = string; +export const V2TurnStartedNotification__LegacyAppPathString = Schema.String; + +export type V2TurnStartedNotification__McpToolCallAppContext = { + readonly actionName?: string | null; + readonly appName?: string | null; + readonly connectorId: string; + readonly linkId?: string | null; + readonly resourceUri?: string | null; +}; +export const V2TurnStartedNotification__McpToolCallAppContext = Schema.Struct({ + actionName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + appName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + connectorId: Schema.String, + linkId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + resourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), +}); + export type V2TurnStartedNotification__McpToolCallError = { readonly message: string }; export const V2TurnStartedNotification__McpToolCallError = Schema.Struct({ message: Schema.String, @@ -9846,7 +10485,6 @@ export const V2TurnStartParams__ApprovalsReviewer = Schema.Literals([ export type V2TurnStartParams__AskForApproval = | "untrusted" - | "on-failure" | "on-request" | "never" | { @@ -9860,7 +10498,7 @@ export type V2TurnStartParams__AskForApproval = }; export const V2TurnStartParams__AskForApproval = Schema.Union( [ - Schema.Literals(["untrusted", "on-failure", "on-request", "never"]), + Schema.Literals(["untrusted", "on-request", "never"]), Schema.Struct({ granular: Schema.Struct({ mcp_elicitations: Schema.Boolean, @@ -9877,6 +10515,9 @@ export const V2TurnStartParams__AskForApproval = Schema.Union( export type V2TurnStartParams__ImageDetail = "auto" | "low" | "high" | "original"; export const V2TurnStartParams__ImageDetail = Schema.Literals(["auto", "low", "high", "original"]); +export type V2TurnStartParams__LegacyAppPathString = string; +export const V2TurnStartParams__LegacyAppPathString = Schema.String; + export type V2TurnStartParams__ModeKind = "plan" | "default"; export const V2TurnStartParams__ModeKind = Schema.Literals(["plan", "default"]).annotate({ description: "Initial collaboration mode to use when the TUI starts.", @@ -9965,7 +10606,8 @@ export const V2TurnStartResponse__CommandExecutionStatus = Schema.Literals([ export type V2TurnStartResponse__DynamicToolCallOutputContentItem = | { readonly text: string; readonly type: "inputText" } - | { readonly imageUrl: string; readonly type: "inputImage" }; + | { readonly imageUrl: string; readonly type: "inputImage" } + | { readonly audioUrl: string; readonly type: "inputAudio" }; export const V2TurnStartResponse__DynamicToolCallOutputContentItem = Schema.Union( [ Schema.Struct({ @@ -9980,6 +10622,12 @@ export const V2TurnStartResponse__DynamicToolCallOutputContentItem = Schema.Unio title: "InputImageDynamicToolCallOutputContentItemType", }), }).annotate({ title: "InputImageDynamicToolCallOutputContentItem" }), + Schema.Struct({ + audioUrl: Schema.String, + type: Schema.Literal("inputAudio").annotate({ + title: "InputAudioDynamicToolCallOutputContentItemType", + }), + }).annotate({ title: "InputAudioDynamicToolCallOutputContentItem" }), ], { mode: "oneOf" }, ); @@ -10008,6 +10656,24 @@ export const V2TurnStartResponse__ImageDetail = Schema.Literals([ "original", ]); +export type V2TurnStartResponse__LegacyAppPathString = string; +export const V2TurnStartResponse__LegacyAppPathString = Schema.String; + +export type V2TurnStartResponse__McpToolCallAppContext = { + readonly actionName?: string | null; + readonly appName?: string | null; + readonly connectorId: string; + readonly linkId?: string | null; + readonly resourceUri?: string | null; +}; +export const V2TurnStartResponse__McpToolCallAppContext = Schema.Struct({ + actionName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + appName: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + connectorId: Schema.String, + linkId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + resourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), +}); + export type V2TurnStartResponse__McpToolCallError = { readonly message: string }; export const V2TurnStartResponse__McpToolCallError = Schema.Struct({ message: Schema.String }); @@ -10367,6 +11033,7 @@ export type ClientRequest__ContentItem = readonly image_url: string; readonly type: "input_image"; } + | { readonly audio_url: string; readonly type: "input_audio" } | { readonly text: string; readonly type: "output_text" }; export const ClientRequest__ContentItem = Schema.Union( [ @@ -10379,6 +11046,10 @@ export const ClientRequest__ContentItem = Schema.Union( image_url: Schema.String, type: Schema.Literal("input_image").annotate({ title: "InputImageContentItemType" }), }).annotate({ title: "InputImageContentItem" }), + Schema.Struct({ + audio_url: Schema.String, + type: Schema.Literal("input_audio").annotate({ title: "InputAudioContentItemType" }), + }).annotate({ title: "InputAudioContentItem" }), Schema.Struct({ text: Schema.String, type: Schema.Literal("output_text").annotate({ title: "OutputTextContentItemType" }), @@ -10394,6 +11065,7 @@ export type ClientRequest__FunctionCallOutputContentItem = readonly image_url: string; readonly type: "input_image"; } + | { readonly audio_url: string; readonly type: "input_audio" } | { readonly encrypted_content: string; readonly type: "encrypted_content" }; export const ClientRequest__FunctionCallOutputContentItem = Schema.Union( [ @@ -10410,6 +11082,12 @@ export const ClientRequest__FunctionCallOutputContentItem = Schema.Union( title: "InputImageFunctionCallOutputContentItemType", }), }).annotate({ title: "InputImageFunctionCallOutputContentItem" }), + Schema.Struct({ + audio_url: Schema.String, + type: Schema.Literal("input_audio").annotate({ + title: "InputAudioFunctionCallOutputContentItemType", + }), + }).annotate({ title: "InputAudioFunctionCallOutputContentItem" }), Schema.Struct({ encrypted_content: Schema.String, type: Schema.Literal("encrypted_content").annotate({ @@ -10434,6 +11112,78 @@ export const ClientRequest__InitializeParams = Schema.Struct({ clientInfo: ClientRequest__ClientInfo, }); +export type ClientRequest__LoginAccountParams = + | { readonly apiKey: string; readonly type: "apiKey" } + | { + readonly appBrand?: ClientRequest__LoginAppBrand | null; + readonly codexStreamlinedLogin?: boolean; + readonly type: "chatgpt"; + readonly useHostedLoginSuccessPage?: boolean; + } + | { readonly type: "chatgptDeviceCode" } + | { + readonly accessToken: string; + readonly chatgptAccountId: string; + readonly chatgptPlanType?: string | null; + readonly type: "chatgptAuthTokens"; + } + | { readonly apiKey: string; readonly region: string; readonly type: "amazonBedrock" }; +export const ClientRequest__LoginAccountParams = Schema.Union( + [ + Schema.Struct({ + apiKey: Schema.String, + type: Schema.Literal("apiKey").annotate({ title: "ApiKeyLoginAccountParamsType" }), + }).annotate({ title: "ApiKeyLoginAccountParams" }), + Schema.Struct({ + appBrand: Schema.optionalKey(Schema.Union([ClientRequest__LoginAppBrand, Schema.Null])), + codexStreamlinedLogin: Schema.optionalKey(Schema.Boolean), + type: Schema.Literal("chatgpt").annotate({ title: "ChatgptLoginAccountParamsType" }), + useHostedLoginSuccessPage: Schema.optionalKey(Schema.Boolean), + }).annotate({ title: "ChatgptLoginAccountParams" }), + Schema.Struct({ + type: Schema.Literal("chatgptDeviceCode").annotate({ + title: "ChatgptDeviceCodeLoginAccountParamsType", + }), + }).annotate({ title: "ChatgptDeviceCodeLoginAccountParams" }), + Schema.Struct({ + accessToken: Schema.String.annotate({ + description: + "Access token (JWT) supplied by the client. This token is used for backend API requests and email extraction.", + }), + chatgptAccountId: Schema.String.annotate({ + description: "Workspace/account identifier supplied by the client.", + }), + chatgptPlanType: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: + "Optional plan type supplied by the client.\n\nWhen `null`, Codex attempts to derive the plan type from access-token claims. If unavailable, the plan defaults to `unknown`.", + }), + Schema.Null, + ]), + ), + type: Schema.Literal("chatgptAuthTokens").annotate({ + title: "ChatgptAuthTokensLoginAccountParamsType", + }), + }).annotate({ + title: "ChatgptAuthTokensLoginAccountParams", + description: + "[UNSTABLE] FOR OPENAI INTERNAL USE ONLY - DO NOT USE. The access token must contain the same scopes that Codex-managed ChatGPT auth tokens have.", + }), + Schema.Struct({ + apiKey: Schema.String, + region: Schema.String, + type: Schema.Literal("amazonBedrock").annotate({ + title: "AmazonBedrockLoginAccountParamsType", + }), + }).annotate({ + title: "AmazonBedrockLoginAccountParams", + description: "[UNSTABLE] Managed Amazon Bedrock login is experimental.", + }), + ], + { mode: "oneOf" }, +); + export type ClientRequest__ListMcpServerStatusParams = { readonly cursor?: string | null; readonly detail?: ClientRequest__McpServerStatusDetail | null; @@ -10616,8 +11366,10 @@ export type ClientRequest__MigrationDetails = { readonly commands?: ReadonlyArray; readonly hooks?: ReadonlyArray; readonly mcpServers?: ReadonlyArray; + readonly memory?: ReadonlyArray; readonly plugins?: ReadonlyArray; readonly sessions?: ReadonlyArray; + readonly skills?: ReadonlyArray; readonly subagents?: ReadonlyArray; }; export const ClientRequest__MigrationDetails = Schema.Struct({ @@ -10628,12 +11380,14 @@ export const ClientRequest__MigrationDetails = Schema.Struct({ mcpServers: Schema.optionalKey( Schema.Array(ClientRequest__McpServerMigration).annotate({ default: [] }), ), + memory: Schema.optionalKey(Schema.Array(Schema.String)), plugins: Schema.optionalKey( Schema.Array(ClientRequest__PluginsMigration).annotate({ default: [] }), ), sessions: Schema.optionalKey( Schema.Array(ClientRequest__SessionMigration).annotate({ default: [] }), ), + skills: Schema.optionalKey(Schema.Array(ClientRequest__SkillMigration).annotate({ default: [] })), subagents: Schema.optionalKey( Schema.Array(ClientRequest__SubagentMigration).annotate({ default: [] }), ), @@ -10655,6 +11409,8 @@ export type ClientRequest__UserInput = readonly path: string; readonly type: "localImage"; } + | { readonly type: "audio"; readonly url: string } + | { readonly path: string; readonly type: "localAudio" } | { readonly name: string; readonly path: string; readonly type: "skill" } | { readonly name: string; readonly path: string; readonly type: "mention" }; export const ClientRequest__UserInput = Schema.Union( @@ -10679,6 +11435,14 @@ export const ClientRequest__UserInput = Schema.Union( path: Schema.String, type: Schema.Literal("localImage").annotate({ title: "LocalImageUserInputType" }), }).annotate({ title: "LocalImageUserInput" }), + Schema.Struct({ + type: Schema.Literal("audio").annotate({ title: "AudioUserInputType" }), + url: Schema.String, + }).annotate({ title: "AudioUserInput" }), + Schema.Struct({ + path: Schema.String, + type: Schema.Literal("localAudio").annotate({ title: "LocalAudioUserInputType" }), + }).annotate({ title: "LocalAudioUserInput" }), Schema.Struct({ name: Schema.String, path: Schema.String, @@ -10730,6 +11494,7 @@ export type ClientRequest__ThreadForkParams = { readonly cwd?: string | null; readonly developerInstructions?: string | null; readonly ephemeral?: boolean; + readonly lastTurnId?: string | null; readonly model?: string | null; readonly modelProvider?: string | null; readonly sandbox?: ClientRequest__SandboxMode | null; @@ -10752,6 +11517,15 @@ export const ClientRequest__ThreadForkParams = Schema.Struct({ cwd: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), developerInstructions: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), ephemeral: Schema.optionalKey(Schema.Boolean), + lastTurnId: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: + "Optional last turn id to fork through, inclusive.\n\nWhen specified, turns after `last_turn_id` are omitted from the fork. The referenced turn cannot be in progress.", + }), + Schema.Null, + ]), + ), model: Schema.optionalKey( Schema.Union([ Schema.String.annotate({ @@ -10965,27 +11739,47 @@ export const CommandExecutionRequestApprovalParams__CommandAction = Schema.Union { mode: "oneOf" }, ); -export type CommandExecutionRequestApprovalParams__FileSystemPath = - | { readonly path: CommandExecutionRequestApprovalParams__AbsolutePathBuf; readonly type: "path" } - | { readonly pattern: string; readonly type: "glob_pattern" } +export type CommandExecutionRequestApprovalParams__FileSystemSpecialPath = + | { readonly kind: "root" } + | { readonly kind: "minimal" } | { - readonly type: "special"; - readonly value: CommandExecutionRequestApprovalParams__FileSystemSpecialPath; + readonly kind: "project_roots"; + readonly subpath?: CommandExecutionRequestApprovalParams__LegacyAppPathString | null; + } + | { readonly kind: "tmpdir" } + | { readonly kind: "slash_tmp" } + | { + readonly kind: "unknown"; + readonly path: string; + readonly subpath?: CommandExecutionRequestApprovalParams__LegacyAppPathString | null; }; -export const CommandExecutionRequestApprovalParams__FileSystemPath = Schema.Union( +export const CommandExecutionRequestApprovalParams__FileSystemSpecialPath = Schema.Union( [ + Schema.Struct({ kind: Schema.Literal("root") }).annotate({ + title: "RootFileSystemSpecialPath", + }), + Schema.Struct({ kind: Schema.Literal("minimal") }).annotate({ + title: "MinimalFileSystemSpecialPath", + }), Schema.Struct({ - path: CommandExecutionRequestApprovalParams__AbsolutePathBuf, - type: Schema.Literal("path").annotate({ title: "PathFileSystemPathType" }), - }).annotate({ title: "PathFileSystemPath" }), - Schema.Struct({ - pattern: Schema.String, - type: Schema.Literal("glob_pattern").annotate({ title: "GlobPatternFileSystemPathType" }), - }).annotate({ title: "GlobPatternFileSystemPath" }), + kind: Schema.Literal("project_roots"), + subpath: Schema.optionalKey( + Schema.Union([CommandExecutionRequestApprovalParams__LegacyAppPathString, Schema.Null]), + ), + }).annotate({ title: "KindFileSystemSpecialPath" }), + Schema.Struct({ kind: Schema.Literal("tmpdir") }).annotate({ + title: "TmpdirFileSystemSpecialPath", + }), + Schema.Struct({ kind: Schema.Literal("slash_tmp") }).annotate({ + title: "SlashTmpFileSystemSpecialPath", + }), Schema.Struct({ - type: Schema.Literal("special").annotate({ title: "SpecialFileSystemPathType" }), - value: CommandExecutionRequestApprovalParams__FileSystemSpecialPath, - }).annotate({ title: "SpecialFileSystemPath" }), + kind: Schema.Literal("unknown"), + path: Schema.String, + subpath: Schema.optionalKey( + Schema.Union([CommandExecutionRequestApprovalParams__LegacyAppPathString, Schema.Null]), + ), + }), ], { mode: "oneOf" }, ); @@ -11263,52 +12057,92 @@ export const McpServerElicitationRequestParams__McpElicitationUntitledSingleSele type: McpServerElicitationRequestParams__McpElicitationStringType, }); -export type PermissionsRequestApprovalParams__FileSystemPath = - | { readonly path: PermissionsRequestApprovalParams__AbsolutePathBuf; readonly type: "path" } - | { readonly pattern: string; readonly type: "glob_pattern" } +export type PermissionsRequestApprovalParams__FileSystemSpecialPath = + | { readonly kind: "root" } + | { readonly kind: "minimal" } | { - readonly type: "special"; - readonly value: PermissionsRequestApprovalParams__FileSystemSpecialPath; + readonly kind: "project_roots"; + readonly subpath?: PermissionsRequestApprovalParams__LegacyAppPathString | null; + } + | { readonly kind: "tmpdir" } + | { readonly kind: "slash_tmp" } + | { + readonly kind: "unknown"; + readonly path: string; + readonly subpath?: PermissionsRequestApprovalParams__LegacyAppPathString | null; }; -export const PermissionsRequestApprovalParams__FileSystemPath = Schema.Union( +export const PermissionsRequestApprovalParams__FileSystemSpecialPath = Schema.Union( [ + Schema.Struct({ kind: Schema.Literal("root") }).annotate({ + title: "RootFileSystemSpecialPath", + }), + Schema.Struct({ kind: Schema.Literal("minimal") }).annotate({ + title: "MinimalFileSystemSpecialPath", + }), Schema.Struct({ - path: PermissionsRequestApprovalParams__AbsolutePathBuf, - type: Schema.Literal("path").annotate({ title: "PathFileSystemPathType" }), - }).annotate({ title: "PathFileSystemPath" }), - Schema.Struct({ - pattern: Schema.String, - type: Schema.Literal("glob_pattern").annotate({ title: "GlobPatternFileSystemPathType" }), - }).annotate({ title: "GlobPatternFileSystemPath" }), + kind: Schema.Literal("project_roots"), + subpath: Schema.optionalKey( + Schema.Union([PermissionsRequestApprovalParams__LegacyAppPathString, Schema.Null]), + ), + }).annotate({ title: "KindFileSystemSpecialPath" }), + Schema.Struct({ kind: Schema.Literal("tmpdir") }).annotate({ + title: "TmpdirFileSystemSpecialPath", + }), + Schema.Struct({ kind: Schema.Literal("slash_tmp") }).annotate({ + title: "SlashTmpFileSystemSpecialPath", + }), Schema.Struct({ - type: Schema.Literal("special").annotate({ title: "SpecialFileSystemPathType" }), - value: PermissionsRequestApprovalParams__FileSystemSpecialPath, - }).annotate({ title: "SpecialFileSystemPath" }), + kind: Schema.Literal("unknown"), + path: Schema.String, + subpath: Schema.optionalKey( + Schema.Union([PermissionsRequestApprovalParams__LegacyAppPathString, Schema.Null]), + ), + }), ], { mode: "oneOf" }, ); -export type PermissionsRequestApprovalResponse__FileSystemPath = - | { readonly path: PermissionsRequestApprovalResponse__AbsolutePathBuf; readonly type: "path" } - | { readonly pattern: string; readonly type: "glob_pattern" } +export type PermissionsRequestApprovalResponse__FileSystemSpecialPath = + | { readonly kind: "root" } + | { readonly kind: "minimal" } | { - readonly type: "special"; - readonly value: PermissionsRequestApprovalResponse__FileSystemSpecialPath; + readonly kind: "project_roots"; + readonly subpath?: PermissionsRequestApprovalResponse__LegacyAppPathString | null; + } + | { readonly kind: "tmpdir" } + | { readonly kind: "slash_tmp" } + | { + readonly kind: "unknown"; + readonly path: string; + readonly subpath?: PermissionsRequestApprovalResponse__LegacyAppPathString | null; }; -export const PermissionsRequestApprovalResponse__FileSystemPath = Schema.Union( +export const PermissionsRequestApprovalResponse__FileSystemSpecialPath = Schema.Union( [ + Schema.Struct({ kind: Schema.Literal("root") }).annotate({ + title: "RootFileSystemSpecialPath", + }), + Schema.Struct({ kind: Schema.Literal("minimal") }).annotate({ + title: "MinimalFileSystemSpecialPath", + }), Schema.Struct({ - path: PermissionsRequestApprovalResponse__AbsolutePathBuf, - type: Schema.Literal("path").annotate({ title: "PathFileSystemPathType" }), - }).annotate({ title: "PathFileSystemPath" }), - Schema.Struct({ - pattern: Schema.String, - type: Schema.Literal("glob_pattern").annotate({ title: "GlobPatternFileSystemPathType" }), - }).annotate({ title: "GlobPatternFileSystemPath" }), + kind: Schema.Literal("project_roots"), + subpath: Schema.optionalKey( + Schema.Union([PermissionsRequestApprovalResponse__LegacyAppPathString, Schema.Null]), + ), + }).annotate({ title: "KindFileSystemSpecialPath" }), + Schema.Struct({ kind: Schema.Literal("tmpdir") }).annotate({ + title: "TmpdirFileSystemSpecialPath", + }), + Schema.Struct({ kind: Schema.Literal("slash_tmp") }).annotate({ + title: "SlashTmpFileSystemSpecialPath", + }), Schema.Struct({ - type: Schema.Literal("special").annotate({ title: "SpecialFileSystemPathType" }), - value: PermissionsRequestApprovalResponse__FileSystemSpecialPath, - }).annotate({ title: "SpecialFileSystemPath" }), + kind: Schema.Literal("unknown"), + path: Schema.String, + subpath: Schema.optionalKey( + Schema.Union([PermissionsRequestApprovalResponse__LegacyAppPathString, Schema.Null]), + ), + }), ], { mode: "oneOf" }, ); @@ -11451,27 +12285,37 @@ export const ServerNotification__CollabAgentState = Schema.Struct({ status: ServerNotification__CollabAgentStatus, }); -export type ServerNotification__FileSystemPath = - | { readonly path: ServerNotification__AbsolutePathBuf; readonly type: "path" } - | { readonly pattern: string; readonly type: "glob_pattern" } - | { readonly type: "special"; readonly value: ServerNotification__FileSystemSpecialPath }; -export const ServerNotification__FileSystemPath = Schema.Union( - [ - Schema.Struct({ - path: ServerNotification__AbsolutePathBuf, - type: Schema.Literal("path").annotate({ title: "PathFileSystemPathType" }), - }).annotate({ title: "PathFileSystemPath" }), - Schema.Struct({ - pattern: Schema.String, - type: Schema.Literal("glob_pattern").annotate({ title: "GlobPatternFileSystemPathType" }), - }).annotate({ title: "GlobPatternFileSystemPath" }), - Schema.Struct({ - type: Schema.Literal("special").annotate({ title: "SpecialFileSystemPathType" }), - value: ServerNotification__FileSystemSpecialPath, - }).annotate({ title: "SpecialFileSystemPath" }), - ], - { mode: "oneOf" }, -); +export type ServerNotification__ExternalAgentConfigImportItemTypeFailure = { + readonly cwd?: string | null; + readonly errorType?: string | null; + readonly failureStage: string; + readonly itemType: ServerNotification__ExternalAgentConfigMigrationItemType; + readonly message: string; + readonly source?: string | null; + readonly subErrorType?: string | null; +}; +export const ServerNotification__ExternalAgentConfigImportItemTypeFailure = Schema.Struct({ + cwd: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + errorType: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + failureStage: Schema.String, + itemType: ServerNotification__ExternalAgentConfigMigrationItemType, + message: Schema.String, + source: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + subErrorType: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), +}); + +export type ServerNotification__ExternalAgentConfigImportItemTypeSuccess = { + readonly cwd?: string | null; + readonly itemType: ServerNotification__ExternalAgentConfigMigrationItemType; + readonly source?: string | null; + readonly target?: string | null; +}; +export const ServerNotification__ExternalAgentConfigImportItemTypeSuccess = Schema.Struct({ + cwd: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + itemType: ServerNotification__ExternalAgentConfigMigrationItemType, + source: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + target: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), +}); export type ServerNotification__FuzzyFileSearchResult = { readonly file_name: string; @@ -11528,14 +12372,63 @@ export const ServerNotification__HookOutputEntry = Schema.Struct({ text: Schema.String, }); +export type ServerNotification__FileSystemSpecialPath = + | { readonly kind: "root" } + | { readonly kind: "minimal" } + | { + readonly kind: "project_roots"; + readonly subpath?: ServerNotification__LegacyAppPathString | null; + } + | { readonly kind: "tmpdir" } + | { readonly kind: "slash_tmp" } + | { + readonly kind: "unknown"; + readonly path: string; + readonly subpath?: ServerNotification__LegacyAppPathString | null; + }; +export const ServerNotification__FileSystemSpecialPath = Schema.Union( + [ + Schema.Struct({ kind: Schema.Literal("root") }).annotate({ + title: "RootFileSystemSpecialPath", + }), + Schema.Struct({ kind: Schema.Literal("minimal") }).annotate({ + title: "MinimalFileSystemSpecialPath", + }), + Schema.Struct({ + kind: Schema.Literal("project_roots"), + subpath: Schema.optionalKey( + Schema.Union([ServerNotification__LegacyAppPathString, Schema.Null]), + ), + }).annotate({ title: "KindFileSystemSpecialPath" }), + Schema.Struct({ kind: Schema.Literal("tmpdir") }).annotate({ + title: "TmpdirFileSystemSpecialPath", + }), + Schema.Struct({ kind: Schema.Literal("slash_tmp") }).annotate({ + title: "SlashTmpFileSystemSpecialPath", + }), + Schema.Struct({ + kind: Schema.Literal("unknown"), + path: Schema.String, + subpath: Schema.optionalKey( + Schema.Union([ServerNotification__LegacyAppPathString, Schema.Null]), + ), + }), + ], + { mode: "oneOf" }, +); + export type ServerNotification__McpServerStatusUpdatedNotification = { readonly error?: string | null; + readonly failureReason?: ServerNotification__McpServerStartupFailureReason | null; readonly name: string; readonly status: ServerNotification__McpServerStartupState; readonly threadId?: string | null; }; export const ServerNotification__McpServerStatusUpdatedNotification = Schema.Struct({ error: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + failureReason: Schema.optionalKey( + Schema.Union([ServerNotification__McpServerStartupFailureReason, Schema.Null]), + ), name: Schema.String, status: ServerNotification__McpServerStartupState, threadId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), @@ -11578,6 +12471,7 @@ export const ServerNotification__ModelVerificationNotification = Schema.Struct({ export type ServerNotification__CodexErrorInfo = | "contextWindowExceeded" + | "sessionBudgetExceeded" | "usageLimitExceeded" | "serverOverloaded" | "cyberPolicy" @@ -11600,6 +12494,7 @@ export const ServerNotification__CodexErrorInfo = Schema.Union( [ Schema.Literals([ "contextWindowExceeded", + "sessionBudgetExceeded", "usageLimitExceeded", "serverOverloaded", "cyberPolicy", @@ -11759,6 +12654,7 @@ export type ServerNotification__RateLimitSnapshot = { readonly primary?: ServerNotification__RateLimitWindow | null; readonly rateLimitReachedType?: ServerNotification__RateLimitReachedType | null; readonly secondary?: ServerNotification__RateLimitWindow | null; + readonly spendControlReached?: boolean | null; }; export const ServerNotification__RateLimitSnapshot = Schema.Struct({ credits: Schema.optionalKey(Schema.Union([ServerNotification__CreditsSnapshot, Schema.Null])), @@ -11773,6 +12669,15 @@ export const ServerNotification__RateLimitSnapshot = Schema.Struct({ Schema.Union([ServerNotification__RateLimitReachedType, Schema.Null]), ), secondary: Schema.optionalKey(Schema.Union([ServerNotification__RateLimitWindow, Schema.Null])), + spendControlReached: Schema.optionalKey( + Schema.Union([ + Schema.Boolean.annotate({ + description: + "Backend-reported spend-control state. `None` is unavailable, not a sparse-update recovery.", + }), + Schema.Null, + ]), + ), }); export type ServerNotification__UserInput = @@ -11791,6 +12696,8 @@ export type ServerNotification__UserInput = readonly path: string; readonly type: "localImage"; } + | { readonly type: "audio"; readonly url: string } + | { readonly path: string; readonly type: "localAudio" } | { readonly name: string; readonly path: string; readonly type: "skill" } | { readonly name: string; readonly path: string; readonly type: "mention" }; export const ServerNotification__UserInput = Schema.Union( @@ -11815,6 +12722,14 @@ export const ServerNotification__UserInput = Schema.Union( path: Schema.String, type: Schema.Literal("localImage").annotate({ title: "LocalImageUserInputType" }), }).annotate({ title: "LocalImageUserInput" }), + Schema.Struct({ + type: Schema.Literal("audio").annotate({ title: "AudioUserInputType" }), + url: Schema.String, + }).annotate({ title: "AudioUserInput" }), + Schema.Struct({ + path: Schema.String, + type: Schema.Literal("localAudio").annotate({ title: "LocalAudioUserInputType" }), + }).annotate({ title: "LocalAudioUserInput" }), Schema.Struct({ name: Schema.String, path: Schema.String, @@ -12020,24 +12935,40 @@ export const ServerRequest__ChatgptAuthTokensRefreshParams = Schema.Struct({ reason: ServerRequest__ChatgptAuthTokensRefreshReason, }); -export type ServerRequest__FileSystemPath = - | { readonly path: ServerRequest__AbsolutePathBuf; readonly type: "path" } - | { readonly pattern: string; readonly type: "glob_pattern" } - | { readonly type: "special"; readonly value: ServerRequest__FileSystemSpecialPath }; -export const ServerRequest__FileSystemPath = Schema.Union( +export type ServerRequest__FileSystemSpecialPath = + | { readonly kind: "root" } + | { readonly kind: "minimal" } + | { readonly kind: "project_roots"; readonly subpath?: ServerRequest__LegacyAppPathString | null } + | { readonly kind: "tmpdir" } + | { readonly kind: "slash_tmp" } + | { + readonly kind: "unknown"; + readonly path: string; + readonly subpath?: ServerRequest__LegacyAppPathString | null; + }; +export const ServerRequest__FileSystemSpecialPath = Schema.Union( [ + Schema.Struct({ kind: Schema.Literal("root") }).annotate({ + title: "RootFileSystemSpecialPath", + }), + Schema.Struct({ kind: Schema.Literal("minimal") }).annotate({ + title: "MinimalFileSystemSpecialPath", + }), Schema.Struct({ - path: ServerRequest__AbsolutePathBuf, - type: Schema.Literal("path").annotate({ title: "PathFileSystemPathType" }), - }).annotate({ title: "PathFileSystemPath" }), - Schema.Struct({ - pattern: Schema.String, - type: Schema.Literal("glob_pattern").annotate({ title: "GlobPatternFileSystemPathType" }), - }).annotate({ title: "GlobPatternFileSystemPath" }), + kind: Schema.Literal("project_roots"), + subpath: Schema.optionalKey(Schema.Union([ServerRequest__LegacyAppPathString, Schema.Null])), + }).annotate({ title: "KindFileSystemSpecialPath" }), + Schema.Struct({ kind: Schema.Literal("tmpdir") }).annotate({ + title: "TmpdirFileSystemSpecialPath", + }), + Schema.Struct({ kind: Schema.Literal("slash_tmp") }).annotate({ + title: "SlashTmpFileSystemSpecialPath", + }), Schema.Struct({ - type: Schema.Literal("special").annotate({ title: "SpecialFileSystemPathType" }), - value: ServerRequest__FileSystemSpecialPath, - }).annotate({ title: "SpecialFileSystemPath" }), + kind: Schema.Literal("unknown"), + path: Schema.String, + subpath: Schema.optionalKey(Schema.Union([ServerRequest__LegacyAppPathString, Schema.Null])), + }), ], { mode: "oneOf" }, ); @@ -12317,6 +13248,7 @@ export type V2AccountRateLimitsUpdatedNotification__RateLimitSnapshot = { readonly primary?: V2AccountRateLimitsUpdatedNotification__RateLimitWindow | null; readonly rateLimitReachedType?: V2AccountRateLimitsUpdatedNotification__RateLimitReachedType | null; readonly secondary?: V2AccountRateLimitsUpdatedNotification__RateLimitWindow | null; + readonly spendControlReached?: boolean | null; }; export const V2AccountRateLimitsUpdatedNotification__RateLimitSnapshot = Schema.Struct({ credits: Schema.optionalKey( @@ -12339,6 +13271,15 @@ export const V2AccountRateLimitsUpdatedNotification__RateLimitSnapshot = Schema. secondary: Schema.optionalKey( Schema.Union([V2AccountRateLimitsUpdatedNotification__RateLimitWindow, Schema.Null]), ), + spendControlReached: Schema.optionalKey( + Schema.Union([ + Schema.Boolean.annotate({ + description: + "Backend-reported spend-control state. `None` is unavailable, not a sparse-update recovery.", + }), + Schema.Null, + ]), + ), }); export type V2AppListUpdatedNotification__AppMetadata = { @@ -12403,6 +13344,23 @@ export const V2AppsListResponse__AppMetadata = Schema.Struct({ versionNotes: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), }); +export type V2AppsReadResponse__ConnectorMetadata = { + readonly description?: string | null; + readonly iconUrl?: string | null; + readonly id: string; + readonly name: string; + readonly toolSummaries?: ReadonlyArray | null; +}; +export const V2AppsReadResponse__ConnectorMetadata = Schema.Struct({ + description: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + iconUrl: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + id: Schema.String, + name: Schema.String, + toolSummaries: Schema.optionalKey( + Schema.Union([Schema.Array(V2AppsReadResponse__AppToolSummary), Schema.Null]), + ), +}).annotate({ description: "EXPERIMENTAL - metadata returned by app/read." }); + export type V2CommandExecParams__SandboxPolicy = | { readonly type: "dangerFullAccess" } | { readonly networkAccess?: boolean; readonly type: "readOnly" } @@ -12555,6 +13513,25 @@ export const V2ConfigReadResponse__ConfigLayerSource = Schema.Union( { mode: "oneOf" }, ); +export type V2ConfigReadResponse__AppsDefaultConfig = { + readonly approvals_reviewer?: V2ConfigReadResponse__ApprovalsReviewer | null; + readonly default_tools_approval_mode?: V2ConfigReadResponse__AppToolApproval | null; + readonly destructive_enabled?: boolean; + readonly enabled?: boolean; + readonly open_world_enabled?: boolean; +}; +export const V2ConfigReadResponse__AppsDefaultConfig = Schema.Struct({ + approvals_reviewer: Schema.optionalKey( + Schema.Union([V2ConfigReadResponse__ApprovalsReviewer, Schema.Null]), + ), + default_tools_approval_mode: Schema.optionalKey( + Schema.Union([V2ConfigReadResponse__AppToolApproval, Schema.Null]), + ), + destructive_enabled: Schema.optionalKey(Schema.Boolean.annotate({ default: true })), + enabled: Schema.optionalKey(Schema.Boolean.annotate({ default: true })), + open_world_enabled: Schema.optionalKey(Schema.Boolean.annotate({ default: true })), +}); + export type V2ConfigReadResponse__WebSearchToolConfig = { readonly allowed_domains?: ReadonlyArray | null; readonly context_size?: V2ConfigReadResponse__WebSearchContextSize | null; @@ -12579,50 +13556,17 @@ export const V2ConfigRequirementsReadResponse__ConfiguredHookMatcherGroup = Sche matcher: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), }); -export type V2ConfigRequirementsReadResponse__ConfigRequirements = { - readonly allowAppshots?: boolean | null; - readonly allowManagedHooksOnly?: boolean | null; - readonly allowedApprovalPolicies?: ReadonlyArray | null; - readonly allowedPermissionProfiles?: { readonly [x: string]: boolean } | null; - readonly allowedSandboxModes?: ReadonlyArray | null; - readonly allowedWebSearchModes?: ReadonlyArray | null; - readonly allowedWindowsSandboxImplementations?: ReadonlyArray | null; - readonly computerUse?: V2ConfigRequirementsReadResponse__ComputerUseRequirements | null; - readonly defaultPermissions?: string | null; - readonly enforceResidency?: V2ConfigRequirementsReadResponse__ResidencyRequirement | null; - readonly featureRequirements?: { readonly [x: string]: boolean } | null; +export type V2ConfigRequirementsReadResponse__NewThreadModelDefaults = { + readonly model?: string | null; + readonly modelReasoningEffort?: V2ConfigRequirementsReadResponse__ReasoningEffort | null; + readonly serviceTier?: string | null; }; -export const V2ConfigRequirementsReadResponse__ConfigRequirements = Schema.Struct({ - allowAppshots: Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), - allowManagedHooksOnly: Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), - allowedApprovalPolicies: Schema.optionalKey( - Schema.Union([Schema.Array(V2ConfigRequirementsReadResponse__AskForApproval), Schema.Null]), - ), - allowedPermissionProfiles: Schema.optionalKey( - Schema.Union([Schema.Record(Schema.String, Schema.Boolean), Schema.Null]), - ), - allowedSandboxModes: Schema.optionalKey( - Schema.Union([Schema.Array(V2ConfigRequirementsReadResponse__SandboxMode), Schema.Null]), - ), - allowedWebSearchModes: Schema.optionalKey( - Schema.Union([Schema.Array(V2ConfigRequirementsReadResponse__WebSearchMode), Schema.Null]), - ), - allowedWindowsSandboxImplementations: Schema.optionalKey( - Schema.Union([ - Schema.Array(V2ConfigRequirementsReadResponse__WindowsSandboxSetupMode), - Schema.Null, - ]), - ), - computerUse: Schema.optionalKey( - Schema.Union([V2ConfigRequirementsReadResponse__ComputerUseRequirements, Schema.Null]), - ), - defaultPermissions: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), - enforceResidency: Schema.optionalKey( - Schema.Union([V2ConfigRequirementsReadResponse__ResidencyRequirement, Schema.Null]), - ), - featureRequirements: Schema.optionalKey( - Schema.Union([Schema.Record(Schema.String, Schema.Boolean), Schema.Null]), +export const V2ConfigRequirementsReadResponse__NewThreadModelDefaults = Schema.Struct({ + model: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + modelReasoningEffort: Schema.optionalKey( + Schema.Union([V2ConfigRequirementsReadResponse__ReasoningEffort, Schema.Null]), ), + serviceTier: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), }); export type V2ConfigWarningNotification__TextRange = { @@ -12734,6 +13678,7 @@ export const V2ConfigWriteResponse__ConfigLayerSource = Schema.Union( export type V2ErrorNotification__CodexErrorInfo = | "contextWindowExceeded" + | "sessionBudgetExceeded" | "usageLimitExceeded" | "serverOverloaded" | "cyberPolicy" @@ -12756,6 +13701,7 @@ export const V2ErrorNotification__CodexErrorInfo = Schema.Union( [ Schema.Literals([ "contextWindowExceeded", + "sessionBudgetExceeded", "usageLimitExceeded", "serverOverloaded", "cyberPolicy", @@ -12844,8 +13790,10 @@ export type V2ExternalAgentConfigDetectResponse__MigrationDetails = { readonly commands?: ReadonlyArray; readonly hooks?: ReadonlyArray; readonly mcpServers?: ReadonlyArray; + readonly memory?: ReadonlyArray; readonly plugins?: ReadonlyArray; readonly sessions?: ReadonlyArray; + readonly skills?: ReadonlyArray; readonly subagents?: ReadonlyArray; }; export const V2ExternalAgentConfigDetectResponse__MigrationDetails = Schema.Struct({ @@ -12858,23 +13806,120 @@ export const V2ExternalAgentConfigDetectResponse__MigrationDetails = Schema.Stru mcpServers: Schema.optionalKey( Schema.Array(V2ExternalAgentConfigDetectResponse__McpServerMigration).annotate({ default: [] }), ), + memory: Schema.optionalKey(Schema.Array(Schema.String)), plugins: Schema.optionalKey( Schema.Array(V2ExternalAgentConfigDetectResponse__PluginsMigration).annotate({ default: [] }), ), sessions: Schema.optionalKey( Schema.Array(V2ExternalAgentConfigDetectResponse__SessionMigration).annotate({ default: [] }), ), + skills: Schema.optionalKey( + Schema.Array(V2ExternalAgentConfigDetectResponse__SkillMigration).annotate({ default: [] }), + ), subagents: Schema.optionalKey( Schema.Array(V2ExternalAgentConfigDetectResponse__SubagentMigration).annotate({ default: [] }), ), }); +export type V2ExternalAgentConfigImportCompletedNotification__ExternalAgentConfigImportItemTypeFailure = + { + readonly cwd?: string | null; + readonly errorType?: string | null; + readonly failureStage: string; + readonly itemType: V2ExternalAgentConfigImportCompletedNotification__ExternalAgentConfigMigrationItemType; + readonly message: string; + readonly source?: string | null; + readonly subErrorType?: string | null; + }; +export const V2ExternalAgentConfigImportCompletedNotification__ExternalAgentConfigImportItemTypeFailure = + Schema.Struct({ + cwd: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + errorType: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + failureStage: Schema.String, + itemType: + V2ExternalAgentConfigImportCompletedNotification__ExternalAgentConfigMigrationItemType, + message: Schema.String, + source: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + subErrorType: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + }); + +export type V2ExternalAgentConfigImportCompletedNotification__ExternalAgentConfigImportItemTypeSuccess = + { + readonly cwd?: string | null; + readonly itemType: V2ExternalAgentConfigImportCompletedNotification__ExternalAgentConfigMigrationItemType; + readonly source?: string | null; + readonly target?: string | null; + }; +export const V2ExternalAgentConfigImportCompletedNotification__ExternalAgentConfigImportItemTypeSuccess = + Schema.Struct({ + cwd: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + itemType: + V2ExternalAgentConfigImportCompletedNotification__ExternalAgentConfigMigrationItemType, + source: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + target: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + }); + +export type V2ExternalAgentConfigImportHistoriesReadResponse__ExternalAgentConfigImportItemTypeFailure = + { + readonly cwd?: string | null; + readonly errorType?: string | null; + readonly failureStage: string; + readonly itemType: V2ExternalAgentConfigImportHistoriesReadResponse__ExternalAgentConfigMigrationItemType; + readonly message: string; + readonly source?: string | null; + readonly subErrorType?: string | null; + }; +export const V2ExternalAgentConfigImportHistoriesReadResponse__ExternalAgentConfigImportItemTypeFailure = + Schema.Struct({ + cwd: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + errorType: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + failureStage: Schema.String, + itemType: + V2ExternalAgentConfigImportHistoriesReadResponse__ExternalAgentConfigMigrationItemType, + message: Schema.String, + source: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + subErrorType: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + }); + +export type V2ExternalAgentConfigImportHistoriesReadResponse__ExternalAgentConfigImportItemTypeSuccess = + { + readonly cwd?: string | null; + readonly itemType: V2ExternalAgentConfigImportHistoriesReadResponse__ExternalAgentConfigMigrationItemType; + readonly source?: string | null; + readonly target?: string | null; + }; +export const V2ExternalAgentConfigImportHistoriesReadResponse__ExternalAgentConfigImportItemTypeSuccess = + Schema.Struct({ + cwd: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + itemType: + V2ExternalAgentConfigImportHistoriesReadResponse__ExternalAgentConfigMigrationItemType, + source: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + target: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + }); + +export type V2ExternalAgentConfigImportHistoriesReadResponse__ExternalAgentImportedConnectorCandidate = + { + readonly name: string; + readonly sessionCount: number; + readonly source: V2ExternalAgentConfigImportHistoriesReadResponse__ExternalAgentImportedConnectorSource; + }; +export const V2ExternalAgentConfigImportHistoriesReadResponse__ExternalAgentImportedConnectorCandidate = + Schema.Struct({ + name: Schema.String, + sessionCount: Schema.Number.annotate({ format: "uint32" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(0)), + source: V2ExternalAgentConfigImportHistoriesReadResponse__ExternalAgentImportedConnectorSource, + }); + export type V2ExternalAgentConfigImportParams__MigrationDetails = { readonly commands?: ReadonlyArray; readonly hooks?: ReadonlyArray; readonly mcpServers?: ReadonlyArray; + readonly memory?: ReadonlyArray; readonly plugins?: ReadonlyArray; readonly sessions?: ReadonlyArray; + readonly skills?: ReadonlyArray; readonly subagents?: ReadonlyArray; }; export const V2ExternalAgentConfigImportParams__MigrationDetails = Schema.Struct({ @@ -12887,17 +13932,57 @@ export const V2ExternalAgentConfigImportParams__MigrationDetails = Schema.Struct mcpServers: Schema.optionalKey( Schema.Array(V2ExternalAgentConfigImportParams__McpServerMigration).annotate({ default: [] }), ), + memory: Schema.optionalKey(Schema.Array(Schema.String)), plugins: Schema.optionalKey( Schema.Array(V2ExternalAgentConfigImportParams__PluginsMigration).annotate({ default: [] }), ), sessions: Schema.optionalKey( Schema.Array(V2ExternalAgentConfigImportParams__SessionMigration).annotate({ default: [] }), ), + skills: Schema.optionalKey( + Schema.Array(V2ExternalAgentConfigImportParams__SkillMigration).annotate({ default: [] }), + ), subagents: Schema.optionalKey( Schema.Array(V2ExternalAgentConfigImportParams__SubagentMigration).annotate({ default: [] }), ), }); +export type V2ExternalAgentConfigImportProgressNotification__ExternalAgentConfigImportItemTypeFailure = + { + readonly cwd?: string | null; + readonly errorType?: string | null; + readonly failureStage: string; + readonly itemType: V2ExternalAgentConfigImportProgressNotification__ExternalAgentConfigMigrationItemType; + readonly message: string; + readonly source?: string | null; + readonly subErrorType?: string | null; + }; +export const V2ExternalAgentConfigImportProgressNotification__ExternalAgentConfigImportItemTypeFailure = + Schema.Struct({ + cwd: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + errorType: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + failureStage: Schema.String, + itemType: V2ExternalAgentConfigImportProgressNotification__ExternalAgentConfigMigrationItemType, + message: Schema.String, + source: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + subErrorType: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + }); + +export type V2ExternalAgentConfigImportProgressNotification__ExternalAgentConfigImportItemTypeSuccess = + { + readonly cwd?: string | null; + readonly itemType: V2ExternalAgentConfigImportProgressNotification__ExternalAgentConfigMigrationItemType; + readonly source?: string | null; + readonly target?: string | null; + }; +export const V2ExternalAgentConfigImportProgressNotification__ExternalAgentConfigImportItemTypeSuccess = + Schema.Struct({ + cwd: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + itemType: V2ExternalAgentConfigImportProgressNotification__ExternalAgentConfigMigrationItemType, + source: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + target: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + }); + export type V2FileChangePatchUpdatedNotification__FileUpdateChange = { readonly diff: string; readonly kind: V2FileChangePatchUpdatedNotification__PatchChangeKind; @@ -12909,6 +13994,52 @@ export const V2FileChangePatchUpdatedNotification__FileUpdateChange = Schema.Str path: Schema.String, }); +export type V2GetAccountRateLimitsResponse__RateLimitResetCredit = { + readonly description?: string | null; + readonly expiresAt?: number | null; + readonly grantedAt: number; + readonly id: string; + readonly resetType: V2GetAccountRateLimitsResponse__RateLimitResetType; + readonly status: V2GetAccountRateLimitsResponse__RateLimitResetCreditStatus; + readonly title?: string | null; +}; +export const V2GetAccountRateLimitsResponse__RateLimitResetCredit = Schema.Struct({ + description: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: + "Backend-provided display description for this credit, or `null` when unavailable.", + }), + Schema.Null, + ]), + ), + expiresAt: Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + description: + "Unix timestamp in seconds when the credit expires, or `null` if it does not expire.", + format: "int64", + }).check(Schema.isInt()), + Schema.Null, + ]), + ), + grantedAt: Schema.Number.annotate({ + description: "Unix timestamp in seconds when the credit was granted.", + format: "int64", + }).check(Schema.isInt()), + id: Schema.String.annotate({ description: "Opaque backend identifier for this reset credit." }), + resetType: V2GetAccountRateLimitsResponse__RateLimitResetType, + status: V2GetAccountRateLimitsResponse__RateLimitResetCreditStatus, + title: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Backend-provided display title for this credit, or `null` when unavailable.", + }), + Schema.Null, + ]), + ), +}); + export type V2GetAccountRateLimitsResponse__RateLimitSnapshot = { readonly credits?: V2GetAccountRateLimitsResponse__CreditsSnapshot | null; readonly individualLimit?: V2GetAccountRateLimitsResponse__SpendControlLimitSnapshot | null; @@ -12918,6 +14049,7 @@ export type V2GetAccountRateLimitsResponse__RateLimitSnapshot = { readonly primary?: V2GetAccountRateLimitsResponse__RateLimitWindow | null; readonly rateLimitReachedType?: V2GetAccountRateLimitsResponse__RateLimitReachedType | null; readonly secondary?: V2GetAccountRateLimitsResponse__RateLimitWindow | null; + readonly spendControlReached?: boolean | null; }; export const V2GetAccountRateLimitsResponse__RateLimitSnapshot = Schema.Struct({ credits: Schema.optionalKey( @@ -12940,33 +14072,74 @@ export const V2GetAccountRateLimitsResponse__RateLimitSnapshot = Schema.Struct({ secondary: Schema.optionalKey( Schema.Union([V2GetAccountRateLimitsResponse__RateLimitWindow, Schema.Null]), ), + spendControlReached: Schema.optionalKey( + Schema.Union([ + Schema.Boolean.annotate({ + description: + "Backend-reported spend-control state. `None` is unavailable, not a sparse-update recovery.", + }), + Schema.Null, + ]), + ), }); export type V2GetAccountResponse__Account = | { readonly type: "apiKey" } | { - readonly email: string; + readonly email: string | null; readonly planType: V2GetAccountResponse__PlanType; readonly type: "chatgpt"; } - | { readonly type: "amazonBedrock" }; + | { readonly type: "amazonBedrock"; readonly usesCodexManagedCredentials?: boolean }; export const V2GetAccountResponse__Account = Schema.Union( [ Schema.Struct({ type: Schema.Literal("apiKey").annotate({ title: "ApiKeyAccountType" }), }).annotate({ title: "ApiKeyAccount" }), Schema.Struct({ - email: Schema.String, + email: Schema.Union([Schema.String, Schema.Null]), planType: V2GetAccountResponse__PlanType, type: Schema.Literal("chatgpt").annotate({ title: "ChatgptAccountType" }), }).annotate({ title: "ChatgptAccount" }), Schema.Struct({ type: Schema.Literal("amazonBedrock").annotate({ title: "AmazonBedrockAccountType" }), + usesCodexManagedCredentials: Schema.optionalKey(Schema.Boolean.annotate({ default: false })), }).annotate({ title: "AmazonBedrockAccount" }), ], { mode: "oneOf" }, ); +export type V2GetWorkspaceMessagesResponse__WorkspaceMessage = { + readonly archivedAt?: number | null; + readonly createdAt?: number | null; + readonly messageBody: string; + readonly messageId: string; + readonly messageType: V2GetWorkspaceMessagesResponse__WorkspaceMessageType; +}; +export const V2GetWorkspaceMessagesResponse__WorkspaceMessage = Schema.Struct({ + archivedAt: Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + description: "Unix timestamp (in seconds) when the message was archived.", + format: "int64", + }).check(Schema.isInt()), + Schema.Null, + ]), + ), + createdAt: Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + description: "Unix timestamp (in seconds) when the message was created.", + format: "int64", + }).check(Schema.isInt()), + Schema.Null, + ]), + ), + messageBody: Schema.String, + messageId: Schema.String, + messageType: V2GetWorkspaceMessagesResponse__WorkspaceMessageType, +}); + export type V2HookCompletedNotification__HookOutputEntry = { readonly kind: V2HookCompletedNotification__HookOutputEntryKind; readonly text: string; @@ -13109,6 +14282,8 @@ export type V2ItemCompletedNotification__UserInput = readonly path: string; readonly type: "localImage"; } + | { readonly type: "audio"; readonly url: string } + | { readonly path: string; readonly type: "localAudio" } | { readonly name: string; readonly path: string; readonly type: "skill" } | { readonly name: string; readonly path: string; readonly type: "mention" }; export const V2ItemCompletedNotification__UserInput = Schema.Union( @@ -13137,6 +14312,14 @@ export const V2ItemCompletedNotification__UserInput = Schema.Union( path: Schema.String, type: Schema.Literal("localImage").annotate({ title: "LocalImageUserInputType" }), }).annotate({ title: "LocalImageUserInput" }), + Schema.Struct({ + type: Schema.Literal("audio").annotate({ title: "AudioUserInputType" }), + url: Schema.String, + }).annotate({ title: "AudioUserInput" }), + Schema.Struct({ + path: Schema.String, + type: Schema.Literal("localAudio").annotate({ title: "LocalAudioUserInputType" }), + }).annotate({ title: "LocalAudioUserInput" }), Schema.Struct({ name: Schema.String, path: Schema.String, @@ -13151,34 +14334,6 @@ export const V2ItemCompletedNotification__UserInput = Schema.Union( { mode: "oneOf" }, ); -export type V2ItemGuardianApprovalReviewCompletedNotification__FileSystemPath = - | { - readonly path: V2ItemGuardianApprovalReviewCompletedNotification__AbsolutePathBuf; - readonly type: "path"; - } - | { readonly pattern: string; readonly type: "glob_pattern" } - | { - readonly type: "special"; - readonly value: V2ItemGuardianApprovalReviewCompletedNotification__FileSystemSpecialPath; - }; -export const V2ItemGuardianApprovalReviewCompletedNotification__FileSystemPath = Schema.Union( - [ - Schema.Struct({ - path: V2ItemGuardianApprovalReviewCompletedNotification__AbsolutePathBuf, - type: Schema.Literal("path").annotate({ title: "PathFileSystemPathType" }), - }).annotate({ title: "PathFileSystemPath" }), - Schema.Struct({ - pattern: Schema.String, - type: Schema.Literal("glob_pattern").annotate({ title: "GlobPatternFileSystemPathType" }), - }).annotate({ title: "GlobPatternFileSystemPath" }), - Schema.Struct({ - type: Schema.Literal("special").annotate({ title: "SpecialFileSystemPathType" }), - value: V2ItemGuardianApprovalReviewCompletedNotification__FileSystemSpecialPath, - }).annotate({ title: "SpecialFileSystemPath" }), - ], - { mode: "oneOf" }, -); - export type V2ItemGuardianApprovalReviewCompletedNotification__GuardianApprovalReview = { readonly rationale?: string | null; readonly riskLevel?: V2ItemGuardianApprovalReviewCompletedNotification__GuardianRiskLevel | null; @@ -13206,33 +14361,57 @@ export const V2ItemGuardianApprovalReviewCompletedNotification__GuardianApproval "[UNSTABLE] Temporary approval auto-review payload used by `item/autoApprovalReview/*` notifications. This shape is expected to change soon.", }); -export type V2ItemGuardianApprovalReviewStartedNotification__FileSystemPath = +export type V2ItemGuardianApprovalReviewCompletedNotification__FileSystemSpecialPath = + | { readonly kind: "root" } + | { readonly kind: "minimal" } | { - readonly path: V2ItemGuardianApprovalReviewStartedNotification__AbsolutePathBuf; - readonly type: "path"; + readonly kind: "project_roots"; + readonly subpath?: V2ItemGuardianApprovalReviewCompletedNotification__LegacyAppPathString | null; } - | { readonly pattern: string; readonly type: "glob_pattern" } + | { readonly kind: "tmpdir" } + | { readonly kind: "slash_tmp" } | { - readonly type: "special"; - readonly value: V2ItemGuardianApprovalReviewStartedNotification__FileSystemSpecialPath; + readonly kind: "unknown"; + readonly path: string; + readonly subpath?: V2ItemGuardianApprovalReviewCompletedNotification__LegacyAppPathString | null; }; -export const V2ItemGuardianApprovalReviewStartedNotification__FileSystemPath = Schema.Union( - [ - Schema.Struct({ - path: V2ItemGuardianApprovalReviewStartedNotification__AbsolutePathBuf, - type: Schema.Literal("path").annotate({ title: "PathFileSystemPathType" }), - }).annotate({ title: "PathFileSystemPath" }), - Schema.Struct({ - pattern: Schema.String, - type: Schema.Literal("glob_pattern").annotate({ title: "GlobPatternFileSystemPathType" }), - }).annotate({ title: "GlobPatternFileSystemPath" }), - Schema.Struct({ - type: Schema.Literal("special").annotate({ title: "SpecialFileSystemPathType" }), - value: V2ItemGuardianApprovalReviewStartedNotification__FileSystemSpecialPath, - }).annotate({ title: "SpecialFileSystemPath" }), - ], - { mode: "oneOf" }, -); +export const V2ItemGuardianApprovalReviewCompletedNotification__FileSystemSpecialPath = + Schema.Union( + [ + Schema.Struct({ kind: Schema.Literal("root") }).annotate({ + title: "RootFileSystemSpecialPath", + }), + Schema.Struct({ kind: Schema.Literal("minimal") }).annotate({ + title: "MinimalFileSystemSpecialPath", + }), + Schema.Struct({ + kind: Schema.Literal("project_roots"), + subpath: Schema.optionalKey( + Schema.Union([ + V2ItemGuardianApprovalReviewCompletedNotification__LegacyAppPathString, + Schema.Null, + ]), + ), + }).annotate({ title: "KindFileSystemSpecialPath" }), + Schema.Struct({ kind: Schema.Literal("tmpdir") }).annotate({ + title: "TmpdirFileSystemSpecialPath", + }), + Schema.Struct({ kind: Schema.Literal("slash_tmp") }).annotate({ + title: "SlashTmpFileSystemSpecialPath", + }), + Schema.Struct({ + kind: Schema.Literal("unknown"), + path: Schema.String, + subpath: Schema.optionalKey( + Schema.Union([ + V2ItemGuardianApprovalReviewCompletedNotification__LegacyAppPathString, + Schema.Null, + ]), + ), + }), + ], + { mode: "oneOf" }, + ); export type V2ItemGuardianApprovalReviewStartedNotification__GuardianApprovalReview = { readonly rationale?: string | null; @@ -13261,6 +14440,57 @@ export const V2ItemGuardianApprovalReviewStartedNotification__GuardianApprovalRe "[UNSTABLE] Temporary approval auto-review payload used by `item/autoApprovalReview/*` notifications. This shape is expected to change soon.", }); +export type V2ItemGuardianApprovalReviewStartedNotification__FileSystemSpecialPath = + | { readonly kind: "root" } + | { readonly kind: "minimal" } + | { + readonly kind: "project_roots"; + readonly subpath?: V2ItemGuardianApprovalReviewStartedNotification__LegacyAppPathString | null; + } + | { readonly kind: "tmpdir" } + | { readonly kind: "slash_tmp" } + | { + readonly kind: "unknown"; + readonly path: string; + readonly subpath?: V2ItemGuardianApprovalReviewStartedNotification__LegacyAppPathString | null; + }; +export const V2ItemGuardianApprovalReviewStartedNotification__FileSystemSpecialPath = Schema.Union( + [ + Schema.Struct({ kind: Schema.Literal("root") }).annotate({ + title: "RootFileSystemSpecialPath", + }), + Schema.Struct({ kind: Schema.Literal("minimal") }).annotate({ + title: "MinimalFileSystemSpecialPath", + }), + Schema.Struct({ + kind: Schema.Literal("project_roots"), + subpath: Schema.optionalKey( + Schema.Union([ + V2ItemGuardianApprovalReviewStartedNotification__LegacyAppPathString, + Schema.Null, + ]), + ), + }).annotate({ title: "KindFileSystemSpecialPath" }), + Schema.Struct({ kind: Schema.Literal("tmpdir") }).annotate({ + title: "TmpdirFileSystemSpecialPath", + }), + Schema.Struct({ kind: Schema.Literal("slash_tmp") }).annotate({ + title: "SlashTmpFileSystemSpecialPath", + }), + Schema.Struct({ + kind: Schema.Literal("unknown"), + path: Schema.String, + subpath: Schema.optionalKey( + Schema.Union([ + V2ItemGuardianApprovalReviewStartedNotification__LegacyAppPathString, + Schema.Null, + ]), + ), + }), + ], + { mode: "oneOf" }, +); + export type V2ItemStartedNotification__CommandAction = | { readonly command: string; @@ -13348,6 +14578,8 @@ export type V2ItemStartedNotification__UserInput = readonly path: string; readonly type: "localImage"; } + | { readonly type: "audio"; readonly url: string } + | { readonly path: string; readonly type: "localAudio" } | { readonly name: string; readonly path: string; readonly type: "skill" } | { readonly name: string; readonly path: string; readonly type: "mention" }; export const V2ItemStartedNotification__UserInput = Schema.Union( @@ -13376,6 +14608,14 @@ export const V2ItemStartedNotification__UserInput = Schema.Union( path: Schema.String, type: Schema.Literal("localImage").annotate({ title: "LocalImageUserInputType" }), }).annotate({ title: "LocalImageUserInput" }), + Schema.Struct({ + type: Schema.Literal("audio").annotate({ title: "AudioUserInputType" }), + url: Schema.String, + }).annotate({ title: "AudioUserInput" }), + Schema.Struct({ + path: Schema.String, + type: Schema.Literal("localAudio").annotate({ title: "LocalAudioUserInputType" }), + }).annotate({ title: "LocalAudioUserInput" }), Schema.Struct({ name: Schema.String, path: Schema.String, @@ -13437,7 +14677,9 @@ export type V2PluginInstalledResponse__PluginInterface = { readonly developerName?: string | null; readonly displayName?: string | null; readonly logo?: V2PluginInstalledResponse__AbsolutePathBuf | null; + readonly logoDark?: V2PluginInstalledResponse__AbsolutePathBuf | null; readonly logoUrl?: string | null; + readonly logoUrlDark?: string | null; readonly longDescription?: string | null; readonly privacyPolicyUrl?: string | null; readonly screenshotUrls: ReadonlyArray; @@ -13477,12 +14719,23 @@ export const V2PluginInstalledResponse__PluginInterface = Schema.Struct({ description: "Local logo path, resolved from the installed plugin package.", }), ), + logoDark: Schema.optionalKey( + Schema.Union([V2PluginInstalledResponse__AbsolutePathBuf, Schema.Null]).annotate({ + description: "Local dark-mode logo path, resolved from the installed plugin package.", + }), + ), logoUrl: Schema.optionalKey( Schema.Union([ Schema.String.annotate({ description: "Remote logo URL from the plugin catalog." }), Schema.Null, ]), ), + logoUrlDark: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ description: "Remote dark-mode logo URL from the plugin catalog." }), + Schema.Null, + ]), + ), longDescription: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), privacyPolicyUrl: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), screenshotUrls: Schema.Array(Schema.String).annotate({ @@ -13505,6 +14758,12 @@ export type V2PluginInstalledResponse__PluginSource = readonly type: "git"; readonly url: string; } + | { + readonly package: string; + readonly registry?: string | null; + readonly type: "npm"; + readonly version?: string | null; + } | { readonly type: "remote" }; export const V2PluginInstalledResponse__PluginSource = Schema.Union( [ @@ -13519,6 +14778,25 @@ export const V2PluginInstalledResponse__PluginSource = Schema.Union( type: Schema.Literal("git").annotate({ title: "GitPluginSourceType" }), url: Schema.String, }).annotate({ title: "GitPluginSource" }), + Schema.Struct({ + package: Schema.String, + registry: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: + "Optional HTTPS registry URL. Authentication stays in the user's npm config.", + }), + Schema.Null, + ]), + ), + type: Schema.Literal("npm").annotate({ title: "NpmPluginSourceType" }), + version: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ description: "Optional npm version or version range." }), + Schema.Null, + ]), + ), + }).annotate({ title: "NpmPluginSource" }), Schema.Struct({ type: Schema.Literal("remote").annotate({ title: "RemotePluginSourceType" }), }).annotate({ @@ -13562,7 +14840,9 @@ export type V2PluginListResponse__PluginInterface = { readonly developerName?: string | null; readonly displayName?: string | null; readonly logo?: V2PluginListResponse__AbsolutePathBuf | null; + readonly logoDark?: V2PluginListResponse__AbsolutePathBuf | null; readonly logoUrl?: string | null; + readonly logoUrlDark?: string | null; readonly longDescription?: string | null; readonly privacyPolicyUrl?: string | null; readonly screenshotUrls: ReadonlyArray; @@ -13602,12 +14882,23 @@ export const V2PluginListResponse__PluginInterface = Schema.Struct({ description: "Local logo path, resolved from the installed plugin package.", }), ), + logoDark: Schema.optionalKey( + Schema.Union([V2PluginListResponse__AbsolutePathBuf, Schema.Null]).annotate({ + description: "Local dark-mode logo path, resolved from the installed plugin package.", + }), + ), logoUrl: Schema.optionalKey( Schema.Union([ Schema.String.annotate({ description: "Remote logo URL from the plugin catalog." }), Schema.Null, ]), ), + logoUrlDark: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ description: "Remote dark-mode logo URL from the plugin catalog." }), + Schema.Null, + ]), + ), longDescription: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), privacyPolicyUrl: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), screenshotUrls: Schema.Array(Schema.String).annotate({ @@ -13630,6 +14921,12 @@ export type V2PluginListResponse__PluginSource = readonly type: "git"; readonly url: string; } + | { + readonly package: string; + readonly registry?: string | null; + readonly type: "npm"; + readonly version?: string | null; + } | { readonly type: "remote" }; export const V2PluginListResponse__PluginSource = Schema.Union( [ @@ -13644,6 +14941,25 @@ export const V2PluginListResponse__PluginSource = Schema.Union( type: Schema.Literal("git").annotate({ title: "GitPluginSourceType" }), url: Schema.String, }).annotate({ title: "GitPluginSource" }), + Schema.Struct({ + package: Schema.String, + registry: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: + "Optional HTTPS registry URL. Authentication stays in the user's npm config.", + }), + Schema.Null, + ]), + ), + type: Schema.Literal("npm").annotate({ title: "NpmPluginSourceType" }), + version: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ description: "Optional npm version or version range." }), + Schema.Null, + ]), + ), + }).annotate({ title: "NpmPluginSource" }), Schema.Struct({ type: Schema.Literal("remote").annotate({ title: "RemotePluginSourceType" }), }).annotate({ @@ -13678,7 +14994,9 @@ export type V2PluginReadResponse__PluginInterface = { readonly developerName?: string | null; readonly displayName?: string | null; readonly logo?: V2PluginReadResponse__AbsolutePathBuf | null; + readonly logoDark?: V2PluginReadResponse__AbsolutePathBuf | null; readonly logoUrl?: string | null; + readonly logoUrlDark?: string | null; readonly longDescription?: string | null; readonly privacyPolicyUrl?: string | null; readonly screenshotUrls: ReadonlyArray; @@ -13718,12 +15036,23 @@ export const V2PluginReadResponse__PluginInterface = Schema.Struct({ description: "Local logo path, resolved from the installed plugin package.", }), ), + logoDark: Schema.optionalKey( + Schema.Union([V2PluginReadResponse__AbsolutePathBuf, Schema.Null]).annotate({ + description: "Local dark-mode logo path, resolved from the installed plugin package.", + }), + ), logoUrl: Schema.optionalKey( Schema.Union([ Schema.String.annotate({ description: "Remote logo URL from the plugin catalog." }), Schema.Null, ]), ), + logoUrlDark: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ description: "Remote dark-mode logo URL from the plugin catalog." }), + Schema.Null, + ]), + ), longDescription: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), privacyPolicyUrl: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), screenshotUrls: Schema.Array(Schema.String).annotate({ @@ -13746,6 +15075,12 @@ export type V2PluginReadResponse__PluginSource = readonly type: "git"; readonly url: string; } + | { + readonly package: string; + readonly registry?: string | null; + readonly type: "npm"; + readonly version?: string | null; + } | { readonly type: "remote" }; export const V2PluginReadResponse__PluginSource = Schema.Union( [ @@ -13760,6 +15095,25 @@ export const V2PluginReadResponse__PluginSource = Schema.Union( type: Schema.Literal("git").annotate({ title: "GitPluginSourceType" }), url: Schema.String, }).annotate({ title: "GitPluginSource" }), + Schema.Struct({ + package: Schema.String, + registry: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: + "Optional HTTPS registry URL. Authentication stays in the user's npm config.", + }), + Schema.Null, + ]), + ), + type: Schema.Literal("npm").annotate({ title: "NpmPluginSourceType" }), + version: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ description: "Optional npm version or version range." }), + Schema.Null, + ]), + ), + }).annotate({ title: "NpmPluginSource" }), Schema.Struct({ type: Schema.Literal("remote").annotate({ title: "RemotePluginSourceType" }), }).annotate({ @@ -13790,6 +15144,7 @@ export const V2PluginReadResponse__SkillInterface = Schema.Struct({ export type V2PluginReadResponse__AppTemplateSummary = { readonly canonicalConnectorId?: string | null; + readonly category?: string | null; readonly description?: string | null; readonly logoUrl?: string | null; readonly logoUrlDark?: string | null; @@ -13800,6 +15155,7 @@ export type V2PluginReadResponse__AppTemplateSummary = { }; export const V2PluginReadResponse__AppTemplateSummary = Schema.Struct({ canonicalConnectorId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + category: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), description: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), logoUrl: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), logoUrlDark: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), @@ -13833,6 +15189,47 @@ export const V2PluginReadResponse__PluginSharePrincipal = Schema.Struct({ role: V2PluginReadResponse__PluginSharePrincipalRole, }); +export type V2PluginReadResponse__ScheduledTaskSchedule = + | { + readonly days?: ReadonlyArray | null; + readonly intervalHours: number; + readonly type: "hourly"; + } + | { readonly time: string; readonly type: "daily" } + | { readonly time: string; readonly type: "weekdays" } + | { + readonly days: ReadonlyArray; + readonly time: string; + readonly type: "weekly"; + }; +export const V2PluginReadResponse__ScheduledTaskSchedule = Schema.Union( + [ + Schema.Struct({ + days: Schema.optionalKey( + Schema.Union([Schema.Array(V2PluginReadResponse__ScheduledTaskWeekday), Schema.Null]), + ), + intervalHours: Schema.Number.annotate({ format: "uint32" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(0)), + type: Schema.Literal("hourly").annotate({ title: "HourlyScheduledTaskScheduleType" }), + }).annotate({ title: "HourlyScheduledTaskSchedule" }), + Schema.Struct({ + time: Schema.String, + type: Schema.Literal("daily").annotate({ title: "DailyScheduledTaskScheduleType" }), + }).annotate({ title: "DailyScheduledTaskSchedule" }), + Schema.Struct({ + time: Schema.String, + type: Schema.Literal("weekdays").annotate({ title: "WeekdaysScheduledTaskScheduleType" }), + }).annotate({ title: "WeekdaysScheduledTaskSchedule" }), + Schema.Struct({ + days: Schema.Array(V2PluginReadResponse__ScheduledTaskWeekday), + time: Schema.String, + type: Schema.Literal("weekly").annotate({ title: "WeeklyScheduledTaskScheduleType" }), + }).annotate({ title: "WeeklyScheduledTaskSchedule" }), + ], + { mode: "oneOf" }, +); + export type V2PluginShareListResponse__PluginInterface = { readonly brandColor?: string | null; readonly capabilities: ReadonlyArray; @@ -13843,7 +15240,9 @@ export type V2PluginShareListResponse__PluginInterface = { readonly developerName?: string | null; readonly displayName?: string | null; readonly logo?: V2PluginShareListResponse__AbsolutePathBuf | null; + readonly logoDark?: V2PluginShareListResponse__AbsolutePathBuf | null; readonly logoUrl?: string | null; + readonly logoUrlDark?: string | null; readonly longDescription?: string | null; readonly privacyPolicyUrl?: string | null; readonly screenshotUrls: ReadonlyArray; @@ -13883,12 +15282,23 @@ export const V2PluginShareListResponse__PluginInterface = Schema.Struct({ description: "Local logo path, resolved from the installed plugin package.", }), ), + logoDark: Schema.optionalKey( + Schema.Union([V2PluginShareListResponse__AbsolutePathBuf, Schema.Null]).annotate({ + description: "Local dark-mode logo path, resolved from the installed plugin package.", + }), + ), logoUrl: Schema.optionalKey( Schema.Union([ Schema.String.annotate({ description: "Remote logo URL from the plugin catalog." }), Schema.Null, ]), ), + logoUrlDark: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ description: "Remote dark-mode logo URL from the plugin catalog." }), + Schema.Null, + ]), + ), longDescription: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), privacyPolicyUrl: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), screenshotUrls: Schema.Array(Schema.String).annotate({ @@ -13911,6 +15321,12 @@ export type V2PluginShareListResponse__PluginSource = readonly type: "git"; readonly url: string; } + | { + readonly package: string; + readonly registry?: string | null; + readonly type: "npm"; + readonly version?: string | null; + } | { readonly type: "remote" }; export const V2PluginShareListResponse__PluginSource = Schema.Union( [ @@ -13925,6 +15341,25 @@ export const V2PluginShareListResponse__PluginSource = Schema.Union( type: Schema.Literal("git").annotate({ title: "GitPluginSourceType" }), url: Schema.String, }).annotate({ title: "GitPluginSource" }), + Schema.Struct({ + package: Schema.String, + registry: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: + "Optional HTTPS registry URL. Authentication stays in the user's npm config.", + }), + Schema.Null, + ]), + ), + type: Schema.Literal("npm").annotate({ title: "NpmPluginSourceType" }), + version: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ description: "Optional npm version or version range." }), + Schema.Null, + ]), + ), + }).annotate({ title: "NpmPluginSource" }), Schema.Struct({ type: Schema.Literal("remote").annotate({ title: "RemotePluginSourceType" }), }).annotate({ @@ -13991,6 +15426,7 @@ export type V2RawResponseItemCompletedNotification__ContentItem = readonly image_url: string; readonly type: "input_image"; } + | { readonly audio_url: string; readonly type: "input_audio" } | { readonly text: string; readonly type: "output_text" }; export const V2RawResponseItemCompletedNotification__ContentItem = Schema.Union( [ @@ -14005,6 +15441,10 @@ export const V2RawResponseItemCompletedNotification__ContentItem = Schema.Union( image_url: Schema.String, type: Schema.Literal("input_image").annotate({ title: "InputImageContentItemType" }), }).annotate({ title: "InputImageContentItem" }), + Schema.Struct({ + audio_url: Schema.String, + type: Schema.Literal("input_audio").annotate({ title: "InputAudioContentItemType" }), + }).annotate({ title: "InputAudioContentItem" }), Schema.Struct({ text: Schema.String, type: Schema.Literal("output_text").annotate({ title: "OutputTextContentItemType" }), @@ -14020,6 +15460,7 @@ export type V2RawResponseItemCompletedNotification__FunctionCallOutputContentIte readonly image_url: string; readonly type: "input_image"; } + | { readonly audio_url: string; readonly type: "input_audio" } | { readonly encrypted_content: string; readonly type: "encrypted_content" }; export const V2RawResponseItemCompletedNotification__FunctionCallOutputContentItem = Schema.Union( [ @@ -14038,6 +15479,12 @@ export const V2RawResponseItemCompletedNotification__FunctionCallOutputContentIt title: "InputImageFunctionCallOutputContentItemType", }), }).annotate({ title: "InputImageFunctionCallOutputContentItem" }), + Schema.Struct({ + audio_url: Schema.String, + type: Schema.Literal("input_audio").annotate({ + title: "InputAudioFunctionCallOutputContentItemType", + }), + }).annotate({ title: "InputAudioFunctionCallOutputContentItem" }), Schema.Struct({ encrypted_content: Schema.String, type: Schema.Literal("encrypted_content").annotate({ @@ -14113,6 +15560,7 @@ export const V2ReviewStartResponse__MemoryCitation = Schema.Struct({ export type V2ReviewStartResponse__CodexErrorInfo = | "contextWindowExceeded" + | "sessionBudgetExceeded" | "usageLimitExceeded" | "serverOverloaded" | "cyberPolicy" @@ -14135,6 +15583,7 @@ export const V2ReviewStartResponse__CodexErrorInfo = Schema.Union( [ Schema.Literals([ "contextWindowExceeded", + "sessionBudgetExceeded", "usageLimitExceeded", "serverOverloaded", "cyberPolicy", @@ -14246,6 +15695,8 @@ export type V2ReviewStartResponse__UserInput = readonly path: string; readonly type: "localImage"; } + | { readonly type: "audio"; readonly url: string } + | { readonly path: string; readonly type: "localAudio" } | { readonly name: string; readonly path: string; readonly type: "skill" } | { readonly name: string; readonly path: string; readonly type: "mention" }; export const V2ReviewStartResponse__UserInput = Schema.Union( @@ -14270,6 +15721,14 @@ export const V2ReviewStartResponse__UserInput = Schema.Union( path: Schema.String, type: Schema.Literal("localImage").annotate({ title: "LocalImageUserInputType" }), }).annotate({ title: "LocalImageUserInput" }), + Schema.Struct({ + type: Schema.Literal("audio").annotate({ title: "AudioUserInputType" }), + url: Schema.String, + }).annotate({ title: "AudioUserInput" }), + Schema.Struct({ + path: Schema.String, + type: Schema.Literal("localAudio").annotate({ title: "LocalAudioUserInputType" }), + }).annotate({ title: "LocalAudioUserInput" }), Schema.Struct({ name: Schema.String, path: Schema.String, @@ -14370,6 +15829,7 @@ export const V2ThreadForkResponse__MemoryCitation = Schema.Struct({ export type V2ThreadForkResponse__CodexErrorInfo = | "contextWindowExceeded" + | "sessionBudgetExceeded" | "usageLimitExceeded" | "serverOverloaded" | "cyberPolicy" @@ -14392,6 +15852,7 @@ export const V2ThreadForkResponse__CodexErrorInfo = Schema.Union( [ Schema.Literals([ "contextWindowExceeded", + "sessionBudgetExceeded", "usageLimitExceeded", "serverOverloaded", "cyberPolicy", @@ -14503,6 +15964,8 @@ export type V2ThreadForkResponse__UserInput = readonly path: string; readonly type: "localImage"; } + | { readonly type: "audio"; readonly url: string } + | { readonly path: string; readonly type: "localAudio" } | { readonly name: string; readonly path: string; readonly type: "skill" } | { readonly name: string; readonly path: string; readonly type: "mention" }; export const V2ThreadForkResponse__UserInput = Schema.Union( @@ -14527,6 +15990,14 @@ export const V2ThreadForkResponse__UserInput = Schema.Union( path: Schema.String, type: Schema.Literal("localImage").annotate({ title: "LocalImageUserInputType" }), }).annotate({ title: "LocalImageUserInput" }), + Schema.Struct({ + type: Schema.Literal("audio").annotate({ title: "AudioUserInputType" }), + url: Schema.String, + }).annotate({ title: "AudioUserInput" }), + Schema.Struct({ + path: Schema.String, + type: Schema.Literal("localAudio").annotate({ title: "LocalAudioUserInputType" }), + }).annotate({ title: "LocalAudioUserInput" }), Schema.Struct({ name: Schema.String, path: Schema.String, @@ -14705,6 +16176,7 @@ export const V2ThreadListResponse__MemoryCitation = Schema.Struct({ export type V2ThreadListResponse__CodexErrorInfo = | "contextWindowExceeded" + | "sessionBudgetExceeded" | "usageLimitExceeded" | "serverOverloaded" | "cyberPolicy" @@ -14727,6 +16199,7 @@ export const V2ThreadListResponse__CodexErrorInfo = Schema.Union( [ Schema.Literals([ "contextWindowExceeded", + "sessionBudgetExceeded", "usageLimitExceeded", "serverOverloaded", "cyberPolicy", @@ -14838,6 +16311,8 @@ export type V2ThreadListResponse__UserInput = readonly path: string; readonly type: "localImage"; } + | { readonly type: "audio"; readonly url: string } + | { readonly path: string; readonly type: "localAudio" } | { readonly name: string; readonly path: string; readonly type: "skill" } | { readonly name: string; readonly path: string; readonly type: "mention" }; export const V2ThreadListResponse__UserInput = Schema.Union( @@ -14862,6 +16337,14 @@ export const V2ThreadListResponse__UserInput = Schema.Union( path: Schema.String, type: Schema.Literal("localImage").annotate({ title: "LocalImageUserInputType" }), }).annotate({ title: "LocalImageUserInput" }), + Schema.Struct({ + type: Schema.Literal("audio").annotate({ title: "AudioUserInputType" }), + url: Schema.String, + }).annotate({ title: "AudioUserInput" }), + Schema.Struct({ + path: Schema.String, + type: Schema.Literal("localAudio").annotate({ title: "LocalAudioUserInputType" }), + }).annotate({ title: "LocalAudioUserInput" }), Schema.Struct({ name: Schema.String, path: Schema.String, @@ -14971,6 +16454,7 @@ export const V2ThreadMetadataUpdateResponse__MemoryCitation = Schema.Struct({ export type V2ThreadMetadataUpdateResponse__CodexErrorInfo = | "contextWindowExceeded" + | "sessionBudgetExceeded" | "usageLimitExceeded" | "serverOverloaded" | "cyberPolicy" @@ -14993,6 +16477,7 @@ export const V2ThreadMetadataUpdateResponse__CodexErrorInfo = Schema.Union( [ Schema.Literals([ "contextWindowExceeded", + "sessionBudgetExceeded", "usageLimitExceeded", "serverOverloaded", "cyberPolicy", @@ -15104,6 +16589,8 @@ export type V2ThreadMetadataUpdateResponse__UserInput = readonly path: string; readonly type: "localImage"; } + | { readonly type: "audio"; readonly url: string } + | { readonly path: string; readonly type: "localAudio" } | { readonly name: string; readonly path: string; readonly type: "skill" } | { readonly name: string; readonly path: string; readonly type: "mention" }; export const V2ThreadMetadataUpdateResponse__UserInput = Schema.Union( @@ -15132,6 +16619,14 @@ export const V2ThreadMetadataUpdateResponse__UserInput = Schema.Union( path: Schema.String, type: Schema.Literal("localImage").annotate({ title: "LocalImageUserInputType" }), }).annotate({ title: "LocalImageUserInput" }), + Schema.Struct({ + type: Schema.Literal("audio").annotate({ title: "AudioUserInputType" }), + url: Schema.String, + }).annotate({ title: "AudioUserInput" }), + Schema.Struct({ + path: Schema.String, + type: Schema.Literal("localAudio").annotate({ title: "LocalAudioUserInputType" }), + }).annotate({ title: "LocalAudioUserInput" }), Schema.Struct({ name: Schema.String, path: Schema.String, @@ -15241,6 +16736,7 @@ export const V2ThreadReadResponse__MemoryCitation = Schema.Struct({ export type V2ThreadReadResponse__CodexErrorInfo = | "contextWindowExceeded" + | "sessionBudgetExceeded" | "usageLimitExceeded" | "serverOverloaded" | "cyberPolicy" @@ -15263,6 +16759,7 @@ export const V2ThreadReadResponse__CodexErrorInfo = Schema.Union( [ Schema.Literals([ "contextWindowExceeded", + "sessionBudgetExceeded", "usageLimitExceeded", "serverOverloaded", "cyberPolicy", @@ -15374,6 +16871,8 @@ export type V2ThreadReadResponse__UserInput = readonly path: string; readonly type: "localImage"; } + | { readonly type: "audio"; readonly url: string } + | { readonly path: string; readonly type: "localAudio" } | { readonly name: string; readonly path: string; readonly type: "skill" } | { readonly name: string; readonly path: string; readonly type: "mention" }; export const V2ThreadReadResponse__UserInput = Schema.Union( @@ -15398,6 +16897,14 @@ export const V2ThreadReadResponse__UserInput = Schema.Union( path: Schema.String, type: Schema.Literal("localImage").annotate({ title: "LocalImageUserInputType" }), }).annotate({ title: "LocalImageUserInput" }), + Schema.Struct({ + type: Schema.Literal("audio").annotate({ title: "AudioUserInputType" }), + url: Schema.String, + }).annotate({ title: "AudioUserInput" }), + Schema.Struct({ + path: Schema.String, + type: Schema.Literal("localAudio").annotate({ title: "LocalAudioUserInputType" }), + }).annotate({ title: "LocalAudioUserInput" }), Schema.Struct({ name: Schema.String, path: Schema.String, @@ -15452,6 +16959,7 @@ export type V2ThreadResumeParams__ContentItem = readonly image_url: string; readonly type: "input_image"; } + | { readonly audio_url: string; readonly type: "input_audio" } | { readonly text: string; readonly type: "output_text" }; export const V2ThreadResumeParams__ContentItem = Schema.Union( [ @@ -15464,6 +16972,10 @@ export const V2ThreadResumeParams__ContentItem = Schema.Union( image_url: Schema.String, type: Schema.Literal("input_image").annotate({ title: "InputImageContentItemType" }), }).annotate({ title: "InputImageContentItem" }), + Schema.Struct({ + audio_url: Schema.String, + type: Schema.Literal("input_audio").annotate({ title: "InputAudioContentItemType" }), + }).annotate({ title: "InputAudioContentItem" }), Schema.Struct({ text: Schema.String, type: Schema.Literal("output_text").annotate({ title: "OutputTextContentItemType" }), @@ -15479,6 +16991,7 @@ export type V2ThreadResumeParams__FunctionCallOutputContentItem = readonly image_url: string; readonly type: "input_image"; } + | { readonly audio_url: string; readonly type: "input_audio" } | { readonly encrypted_content: string; readonly type: "encrypted_content" }; export const V2ThreadResumeParams__FunctionCallOutputContentItem = Schema.Union( [ @@ -15495,6 +17008,12 @@ export const V2ThreadResumeParams__FunctionCallOutputContentItem = Schema.Union( title: "InputImageFunctionCallOutputContentItemType", }), }).annotate({ title: "InputImageFunctionCallOutputContentItem" }), + Schema.Struct({ + audio_url: Schema.String, + type: Schema.Literal("input_audio").annotate({ + title: "InputAudioFunctionCallOutputContentItemType", + }), + }).annotate({ title: "InputAudioFunctionCallOutputContentItem" }), Schema.Struct({ encrypted_content: Schema.String, type: Schema.Literal("encrypted_content").annotate({ @@ -15570,6 +17089,7 @@ export const V2ThreadResumeResponse__MemoryCitation = Schema.Struct({ export type V2ThreadResumeResponse__CodexErrorInfo = | "contextWindowExceeded" + | "sessionBudgetExceeded" | "usageLimitExceeded" | "serverOverloaded" | "cyberPolicy" @@ -15592,6 +17112,7 @@ export const V2ThreadResumeResponse__CodexErrorInfo = Schema.Union( [ Schema.Literals([ "contextWindowExceeded", + "sessionBudgetExceeded", "usageLimitExceeded", "serverOverloaded", "cyberPolicy", @@ -15703,6 +17224,8 @@ export type V2ThreadResumeResponse__UserInput = readonly path: string; readonly type: "localImage"; } + | { readonly type: "audio"; readonly url: string } + | { readonly path: string; readonly type: "localAudio" } | { readonly name: string; readonly path: string; readonly type: "skill" } | { readonly name: string; readonly path: string; readonly type: "mention" }; export const V2ThreadResumeResponse__UserInput = Schema.Union( @@ -15727,6 +17250,14 @@ export const V2ThreadResumeResponse__UserInput = Schema.Union( path: Schema.String, type: Schema.Literal("localImage").annotate({ title: "LocalImageUserInputType" }), }).annotate({ title: "LocalImageUserInput" }), + Schema.Struct({ + type: Schema.Literal("audio").annotate({ title: "AudioUserInputType" }), + url: Schema.String, + }).annotate({ title: "AudioUserInput" }), + Schema.Struct({ + path: Schema.String, + type: Schema.Literal("localAudio").annotate({ title: "LocalAudioUserInputType" }), + }).annotate({ title: "LocalAudioUserInput" }), Schema.Struct({ name: Schema.String, path: Schema.String, @@ -15836,6 +17367,7 @@ export const V2ThreadRollbackResponse__MemoryCitation = Schema.Struct({ export type V2ThreadRollbackResponse__CodexErrorInfo = | "contextWindowExceeded" + | "sessionBudgetExceeded" | "usageLimitExceeded" | "serverOverloaded" | "cyberPolicy" @@ -15858,6 +17390,7 @@ export const V2ThreadRollbackResponse__CodexErrorInfo = Schema.Union( [ Schema.Literals([ "contextWindowExceeded", + "sessionBudgetExceeded", "usageLimitExceeded", "serverOverloaded", "cyberPolicy", @@ -15969,6 +17502,8 @@ export type V2ThreadRollbackResponse__UserInput = readonly path: string; readonly type: "localImage"; } + | { readonly type: "audio"; readonly url: string } + | { readonly path: string; readonly type: "localAudio" } | { readonly name: string; readonly path: string; readonly type: "skill" } | { readonly name: string; readonly path: string; readonly type: "mention" }; export const V2ThreadRollbackResponse__UserInput = Schema.Union( @@ -15997,6 +17532,14 @@ export const V2ThreadRollbackResponse__UserInput = Schema.Union( path: Schema.String, type: Schema.Literal("localImage").annotate({ title: "LocalImageUserInputType" }), }).annotate({ title: "LocalImageUserInput" }), + Schema.Struct({ + type: Schema.Literal("audio").annotate({ title: "AudioUserInputType" }), + url: Schema.String, + }).annotate({ title: "AudioUserInput" }), + Schema.Struct({ + path: Schema.String, + type: Schema.Literal("localAudio").annotate({ title: "LocalAudioUserInputType" }), + }).annotate({ title: "LocalAudioUserInput" }), Schema.Struct({ name: Schema.String, path: Schema.String, @@ -16164,6 +17707,7 @@ export const V2ThreadStartedNotification__MemoryCitation = Schema.Struct({ export type V2ThreadStartedNotification__CodexErrorInfo = | "contextWindowExceeded" + | "sessionBudgetExceeded" | "usageLimitExceeded" | "serverOverloaded" | "cyberPolicy" @@ -16186,6 +17730,7 @@ export const V2ThreadStartedNotification__CodexErrorInfo = Schema.Union( [ Schema.Literals([ "contextWindowExceeded", + "sessionBudgetExceeded", "usageLimitExceeded", "serverOverloaded", "cyberPolicy", @@ -16297,6 +17842,8 @@ export type V2ThreadStartedNotification__UserInput = readonly path: string; readonly type: "localImage"; } + | { readonly type: "audio"; readonly url: string } + | { readonly path: string; readonly type: "localAudio" } | { readonly name: string; readonly path: string; readonly type: "skill" } | { readonly name: string; readonly path: string; readonly type: "mention" }; export const V2ThreadStartedNotification__UserInput = Schema.Union( @@ -16325,6 +17872,14 @@ export const V2ThreadStartedNotification__UserInput = Schema.Union( path: Schema.String, type: Schema.Literal("localImage").annotate({ title: "LocalImageUserInputType" }), }).annotate({ title: "LocalImageUserInput" }), + Schema.Struct({ + type: Schema.Literal("audio").annotate({ title: "AudioUserInputType" }), + url: Schema.String, + }).annotate({ title: "AudioUserInput" }), + Schema.Struct({ + path: Schema.String, + type: Schema.Literal("localAudio").annotate({ title: "LocalAudioUserInputType" }), + }).annotate({ title: "LocalAudioUserInput" }), Schema.Struct({ name: Schema.String, path: Schema.String, @@ -16434,6 +17989,7 @@ export const V2ThreadStartResponse__MemoryCitation = Schema.Struct({ export type V2ThreadStartResponse__CodexErrorInfo = | "contextWindowExceeded" + | "sessionBudgetExceeded" | "usageLimitExceeded" | "serverOverloaded" | "cyberPolicy" @@ -16456,6 +18012,7 @@ export const V2ThreadStartResponse__CodexErrorInfo = Schema.Union( [ Schema.Literals([ "contextWindowExceeded", + "sessionBudgetExceeded", "usageLimitExceeded", "serverOverloaded", "cyberPolicy", @@ -16567,6 +18124,8 @@ export type V2ThreadStartResponse__UserInput = readonly path: string; readonly type: "localImage"; } + | { readonly type: "audio"; readonly url: string } + | { readonly path: string; readonly type: "localAudio" } | { readonly name: string; readonly path: string; readonly type: "skill" } | { readonly name: string; readonly path: string; readonly type: "mention" }; export const V2ThreadStartResponse__UserInput = Schema.Union( @@ -16591,6 +18150,14 @@ export const V2ThreadStartResponse__UserInput = Schema.Union( path: Schema.String, type: Schema.Literal("localImage").annotate({ title: "LocalImageUserInputType" }), }).annotate({ title: "LocalImageUserInput" }), + Schema.Struct({ + type: Schema.Literal("audio").annotate({ title: "AudioUserInputType" }), + url: Schema.String, + }).annotate({ title: "AudioUserInput" }), + Schema.Struct({ + path: Schema.String, + type: Schema.Literal("localAudio").annotate({ title: "LocalAudioUserInputType" }), + }).annotate({ title: "LocalAudioUserInput" }), Schema.Struct({ name: Schema.String, path: Schema.String, @@ -16740,6 +18307,7 @@ export const V2ThreadUnarchiveResponse__MemoryCitation = Schema.Struct({ export type V2ThreadUnarchiveResponse__CodexErrorInfo = | "contextWindowExceeded" + | "sessionBudgetExceeded" | "usageLimitExceeded" | "serverOverloaded" | "cyberPolicy" @@ -16762,6 +18330,7 @@ export const V2ThreadUnarchiveResponse__CodexErrorInfo = Schema.Union( [ Schema.Literals([ "contextWindowExceeded", + "sessionBudgetExceeded", "usageLimitExceeded", "serverOverloaded", "cyberPolicy", @@ -16873,6 +18442,8 @@ export type V2ThreadUnarchiveResponse__UserInput = readonly path: string; readonly type: "localImage"; } + | { readonly type: "audio"; readonly url: string } + | { readonly path: string; readonly type: "localAudio" } | { readonly name: string; readonly path: string; readonly type: "skill" } | { readonly name: string; readonly path: string; readonly type: "mention" }; export const V2ThreadUnarchiveResponse__UserInput = Schema.Union( @@ -16901,6 +18472,14 @@ export const V2ThreadUnarchiveResponse__UserInput = Schema.Union( path: Schema.String, type: Schema.Literal("localImage").annotate({ title: "LocalImageUserInputType" }), }).annotate({ title: "LocalImageUserInput" }), + Schema.Struct({ + type: Schema.Literal("audio").annotate({ title: "AudioUserInputType" }), + url: Schema.String, + }).annotate({ title: "AudioUserInput" }), + Schema.Struct({ + path: Schema.String, + type: Schema.Literal("localAudio").annotate({ title: "LocalAudioUserInputType" }), + }).annotate({ title: "LocalAudioUserInput" }), Schema.Struct({ name: Schema.String, path: Schema.String, @@ -17010,6 +18589,7 @@ export const V2TurnCompletedNotification__MemoryCitation = Schema.Struct({ export type V2TurnCompletedNotification__CodexErrorInfo = | "contextWindowExceeded" + | "sessionBudgetExceeded" | "usageLimitExceeded" | "serverOverloaded" | "cyberPolicy" @@ -17032,6 +18612,7 @@ export const V2TurnCompletedNotification__CodexErrorInfo = Schema.Union( [ Schema.Literals([ "contextWindowExceeded", + "sessionBudgetExceeded", "usageLimitExceeded", "serverOverloaded", "cyberPolicy", @@ -17143,6 +18724,8 @@ export type V2TurnCompletedNotification__UserInput = readonly path: string; readonly type: "localImage"; } + | { readonly type: "audio"; readonly url: string } + | { readonly path: string; readonly type: "localAudio" } | { readonly name: string; readonly path: string; readonly type: "skill" } | { readonly name: string; readonly path: string; readonly type: "mention" }; export const V2TurnCompletedNotification__UserInput = Schema.Union( @@ -17171,6 +18754,14 @@ export const V2TurnCompletedNotification__UserInput = Schema.Union( path: Schema.String, type: Schema.Literal("localImage").annotate({ title: "LocalImageUserInputType" }), }).annotate({ title: "LocalImageUserInput" }), + Schema.Struct({ + type: Schema.Literal("audio").annotate({ title: "AudioUserInputType" }), + url: Schema.String, + }).annotate({ title: "AudioUserInput" }), + Schema.Struct({ + path: Schema.String, + type: Schema.Literal("localAudio").annotate({ title: "LocalAudioUserInputType" }), + }).annotate({ title: "LocalAudioUserInput" }), Schema.Struct({ name: Schema.String, path: Schema.String, @@ -17256,6 +18847,7 @@ export const V2TurnStartedNotification__MemoryCitation = Schema.Struct({ export type V2TurnStartedNotification__CodexErrorInfo = | "contextWindowExceeded" + | "sessionBudgetExceeded" | "usageLimitExceeded" | "serverOverloaded" | "cyberPolicy" @@ -17278,6 +18870,7 @@ export const V2TurnStartedNotification__CodexErrorInfo = Schema.Union( [ Schema.Literals([ "contextWindowExceeded", + "sessionBudgetExceeded", "usageLimitExceeded", "serverOverloaded", "cyberPolicy", @@ -17389,6 +18982,8 @@ export type V2TurnStartedNotification__UserInput = readonly path: string; readonly type: "localImage"; } + | { readonly type: "audio"; readonly url: string } + | { readonly path: string; readonly type: "localAudio" } | { readonly name: string; readonly path: string; readonly type: "skill" } | { readonly name: string; readonly path: string; readonly type: "mention" }; export const V2TurnStartedNotification__UserInput = Schema.Union( @@ -17417,6 +19012,14 @@ export const V2TurnStartedNotification__UserInput = Schema.Union( path: Schema.String, type: Schema.Literal("localImage").annotate({ title: "LocalImageUserInputType" }), }).annotate({ title: "LocalImageUserInput" }), + Schema.Struct({ + type: Schema.Literal("audio").annotate({ title: "AudioUserInputType" }), + url: Schema.String, + }).annotate({ title: "AudioUserInput" }), + Schema.Struct({ + path: Schema.String, + type: Schema.Literal("localAudio").annotate({ title: "LocalAudioUserInputType" }), + }).annotate({ title: "LocalAudioUserInput" }), Schema.Struct({ name: Schema.String, path: Schema.String, @@ -17503,6 +19106,8 @@ export type V2TurnStartParams__UserInput = readonly path: string; readonly type: "localImage"; } + | { readonly type: "audio"; readonly url: string } + | { readonly path: string; readonly type: "localAudio" } | { readonly name: string; readonly path: string; readonly type: "skill" } | { readonly name: string; readonly path: string; readonly type: "mention" }; export const V2TurnStartParams__UserInput = Schema.Union( @@ -17527,6 +19132,14 @@ export const V2TurnStartParams__UserInput = Schema.Union( path: Schema.String, type: Schema.Literal("localImage").annotate({ title: "LocalImageUserInputType" }), }).annotate({ title: "LocalImageUserInput" }), + Schema.Struct({ + type: Schema.Literal("audio").annotate({ title: "AudioUserInputType" }), + url: Schema.String, + }).annotate({ title: "AudioUserInput" }), + Schema.Struct({ + path: Schema.String, + type: Schema.Literal("localAudio").annotate({ title: "LocalAudioUserInputType" }), + }).annotate({ title: "LocalAudioUserInput" }), Schema.Struct({ name: Schema.String, path: Schema.String, @@ -17603,6 +19216,7 @@ export const V2TurnStartResponse__MemoryCitation = Schema.Struct({ export type V2TurnStartResponse__CodexErrorInfo = | "contextWindowExceeded" + | "sessionBudgetExceeded" | "usageLimitExceeded" | "serverOverloaded" | "cyberPolicy" @@ -17625,6 +19239,7 @@ export const V2TurnStartResponse__CodexErrorInfo = Schema.Union( [ Schema.Literals([ "contextWindowExceeded", + "sessionBudgetExceeded", "usageLimitExceeded", "serverOverloaded", "cyberPolicy", @@ -17736,6 +19351,8 @@ export type V2TurnStartResponse__UserInput = readonly path: string; readonly type: "localImage"; } + | { readonly type: "audio"; readonly url: string } + | { readonly path: string; readonly type: "localAudio" } | { readonly name: string; readonly path: string; readonly type: "skill" } | { readonly name: string; readonly path: string; readonly type: "mention" }; export const V2TurnStartResponse__UserInput = Schema.Union( @@ -17760,6 +19377,14 @@ export const V2TurnStartResponse__UserInput = Schema.Union( path: Schema.String, type: Schema.Literal("localImage").annotate({ title: "LocalImageUserInputType" }), }).annotate({ title: "LocalImageUserInput" }), + Schema.Struct({ + type: Schema.Literal("audio").annotate({ title: "AudioUserInputType" }), + url: Schema.String, + }).annotate({ title: "AudioUserInput" }), + Schema.Struct({ + path: Schema.String, + type: Schema.Literal("localAudio").annotate({ title: "LocalAudioUserInputType" }), + }).annotate({ title: "LocalAudioUserInput" }), Schema.Struct({ name: Schema.String, path: Schema.String, @@ -17790,6 +19415,8 @@ export type V2TurnSteerParams__UserInput = readonly path: string; readonly type: "localImage"; } + | { readonly type: "audio"; readonly url: string } + | { readonly path: string; readonly type: "localAudio" } | { readonly name: string; readonly path: string; readonly type: "skill" } | { readonly name: string; readonly path: string; readonly type: "mention" }; export const V2TurnSteerParams__UserInput = Schema.Union( @@ -17814,6 +19441,14 @@ export const V2TurnSteerParams__UserInput = Schema.Union( path: Schema.String, type: Schema.Literal("localImage").annotate({ title: "LocalImageUserInputType" }), }).annotate({ title: "LocalImageUserInput" }), + Schema.Struct({ + type: Schema.Literal("audio").annotate({ title: "AudioUserInputType" }), + url: Schema.String, + }).annotate({ title: "AudioUserInput" }), + Schema.Struct({ + path: Schema.String, + type: Schema.Literal("localAudio").annotate({ title: "LocalAudioUserInputType" }), + }).annotate({ title: "LocalAudioUserInput" }), Schema.Struct({ name: Schema.String, path: Schema.String, @@ -18179,14 +19814,33 @@ export const ClientRequest__TurnSteerParams = Schema.Struct({ threadId: Schema.String, }); -export type CommandExecutionRequestApprovalParams__FileSystemSandboxEntry = { - readonly access: CommandExecutionRequestApprovalParams__FileSystemAccessMode; - readonly path: CommandExecutionRequestApprovalParams__FileSystemPath; -}; -export const CommandExecutionRequestApprovalParams__FileSystemSandboxEntry = Schema.Struct({ - access: CommandExecutionRequestApprovalParams__FileSystemAccessMode, - path: CommandExecutionRequestApprovalParams__FileSystemPath, -}); +export type CommandExecutionRequestApprovalParams__FileSystemPath = + | { + readonly path: CommandExecutionRequestApprovalParams__LegacyAppPathString; + readonly type: "path"; + } + | { readonly pattern: string; readonly type: "glob_pattern" } + | { + readonly type: "special"; + readonly value: CommandExecutionRequestApprovalParams__FileSystemSpecialPath; + }; +export const CommandExecutionRequestApprovalParams__FileSystemPath = Schema.Union( + [ + Schema.Struct({ + path: CommandExecutionRequestApprovalParams__LegacyAppPathString, + type: Schema.Literal("path").annotate({ title: "PathFileSystemPathType" }), + }).annotate({ title: "PathFileSystemPath" }), + Schema.Struct({ + pattern: Schema.String, + type: Schema.Literal("glob_pattern").annotate({ title: "GlobPatternFileSystemPathType" }), + }).annotate({ title: "GlobPatternFileSystemPath" }), + Schema.Struct({ + type: Schema.Literal("special").annotate({ title: "SpecialFileSystemPathType" }), + value: CommandExecutionRequestApprovalParams__FileSystemSpecialPath, + }).annotate({ title: "SpecialFileSystemPath" }), + ], + { mode: "oneOf" }, +); export type CommandExecutionRequestApprovalResponse__CommandExecutionApprovalDecision = | "accept" @@ -18374,29 +20028,66 @@ export const McpServerElicitationRequestParams__McpElicitationSingleSelectEnumSc ], ); -export type PermissionsRequestApprovalParams__FileSystemSandboxEntry = { - readonly access: PermissionsRequestApprovalParams__FileSystemAccessMode; - readonly path: PermissionsRequestApprovalParams__FileSystemPath; -}; -export const PermissionsRequestApprovalParams__FileSystemSandboxEntry = Schema.Struct({ - access: PermissionsRequestApprovalParams__FileSystemAccessMode, - path: PermissionsRequestApprovalParams__FileSystemPath, -}); +export type PermissionsRequestApprovalParams__FileSystemPath = + | { readonly path: PermissionsRequestApprovalParams__LegacyAppPathString; readonly type: "path" } + | { readonly pattern: string; readonly type: "glob_pattern" } + | { + readonly type: "special"; + readonly value: PermissionsRequestApprovalParams__FileSystemSpecialPath; + }; +export const PermissionsRequestApprovalParams__FileSystemPath = Schema.Union( + [ + Schema.Struct({ + path: PermissionsRequestApprovalParams__LegacyAppPathString, + type: Schema.Literal("path").annotate({ title: "PathFileSystemPathType" }), + }).annotate({ title: "PathFileSystemPath" }), + Schema.Struct({ + pattern: Schema.String, + type: Schema.Literal("glob_pattern").annotate({ title: "GlobPatternFileSystemPathType" }), + }).annotate({ title: "GlobPatternFileSystemPath" }), + Schema.Struct({ + type: Schema.Literal("special").annotate({ title: "SpecialFileSystemPathType" }), + value: PermissionsRequestApprovalParams__FileSystemSpecialPath, + }).annotate({ title: "SpecialFileSystemPath" }), + ], + { mode: "oneOf" }, +); -export type PermissionsRequestApprovalResponse__FileSystemSandboxEntry = { - readonly access: PermissionsRequestApprovalResponse__FileSystemAccessMode; - readonly path: PermissionsRequestApprovalResponse__FileSystemPath; -}; -export const PermissionsRequestApprovalResponse__FileSystemSandboxEntry = Schema.Struct({ - access: PermissionsRequestApprovalResponse__FileSystemAccessMode, - path: PermissionsRequestApprovalResponse__FileSystemPath, -}); +export type PermissionsRequestApprovalResponse__FileSystemPath = + | { + readonly path: PermissionsRequestApprovalResponse__LegacyAppPathString; + readonly type: "path"; + } + | { readonly pattern: string; readonly type: "glob_pattern" } + | { + readonly type: "special"; + readonly value: PermissionsRequestApprovalResponse__FileSystemSpecialPath; + }; +export const PermissionsRequestApprovalResponse__FileSystemPath = Schema.Union( + [ + Schema.Struct({ + path: PermissionsRequestApprovalResponse__LegacyAppPathString, + type: Schema.Literal("path").annotate({ title: "PathFileSystemPathType" }), + }).annotate({ title: "PathFileSystemPath" }), + Schema.Struct({ + pattern: Schema.String, + type: Schema.Literal("glob_pattern").annotate({ title: "GlobPatternFileSystemPathType" }), + }).annotate({ title: "GlobPatternFileSystemPath" }), + Schema.Struct({ + type: Schema.Literal("special").annotate({ title: "SpecialFileSystemPathType" }), + value: PermissionsRequestApprovalResponse__FileSystemSpecialPath, + }).annotate({ title: "SpecialFileSystemPath" }), + ], + { mode: "oneOf" }, +); export type ServerNotification__AppInfo = { readonly appMetadata?: ServerNotification__AppMetadata | null; readonly branding?: ServerNotification__AppBranding | null; readonly description?: string | null; readonly distributionChannel?: string | null; + readonly iconAssets?: { readonly [x: string]: string } | null; + readonly iconDarkAssets?: { readonly [x: string]: string } | null; readonly id: string; readonly installUrl?: string | null; readonly isAccessible?: boolean; @@ -18412,6 +20103,12 @@ export const ServerNotification__AppInfo = Schema.Struct({ branding: Schema.optionalKey(Schema.Union([ServerNotification__AppBranding, Schema.Null])), description: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), distributionChannel: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + iconAssets: Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.String), Schema.Null]), + ), + iconDarkAssets: Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.String), Schema.Null]), + ), id: Schema.String, installUrl: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), isAccessible: Schema.optionalKey(Schema.Boolean.annotate({ default: false })), @@ -18431,13 +20128,15 @@ export const ServerNotification__AppInfo = Schema.Struct({ pluginDisplayNames: Schema.optionalKey(Schema.Array(Schema.String).annotate({ default: [] })), }).annotate({ description: "EXPERIMENTAL - app metadata returned by app-list APIs." }); -export type ServerNotification__FileSystemSandboxEntry = { - readonly access: ServerNotification__FileSystemAccessMode; - readonly path: ServerNotification__FileSystemPath; +export type ServerNotification__ExternalAgentConfigImportTypeResult = { + readonly failures: ReadonlyArray; + readonly itemType: ServerNotification__ExternalAgentConfigMigrationItemType; + readonly successes: ReadonlyArray; }; -export const ServerNotification__FileSystemSandboxEntry = Schema.Struct({ - access: ServerNotification__FileSystemAccessMode, - path: ServerNotification__FileSystemPath, +export const ServerNotification__ExternalAgentConfigImportTypeResult = Schema.Struct({ + failures: Schema.Array(ServerNotification__ExternalAgentConfigImportItemTypeFailure), + itemType: ServerNotification__ExternalAgentConfigMigrationItemType, + successes: Schema.Array(ServerNotification__ExternalAgentConfigImportItemTypeSuccess), }); export type ServerNotification__FuzzyFileSearchSessionUpdatedNotification = { @@ -18513,6 +20212,28 @@ export const ServerNotification__HookRunSummary = Schema.Struct({ statusMessage: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), }); +export type ServerNotification__FileSystemPath = + | { readonly path: ServerNotification__LegacyAppPathString; readonly type: "path" } + | { readonly pattern: string; readonly type: "glob_pattern" } + | { readonly type: "special"; readonly value: ServerNotification__FileSystemSpecialPath }; +export const ServerNotification__FileSystemPath = Schema.Union( + [ + Schema.Struct({ + path: ServerNotification__LegacyAppPathString, + type: Schema.Literal("path").annotate({ title: "PathFileSystemPathType" }), + }).annotate({ title: "PathFileSystemPath" }), + Schema.Struct({ + pattern: Schema.String, + type: Schema.Literal("glob_pattern").annotate({ title: "GlobPatternFileSystemPathType" }), + }).annotate({ title: "GlobPatternFileSystemPath" }), + Schema.Struct({ + type: Schema.Literal("special").annotate({ title: "SpecialFileSystemPathType" }), + value: ServerNotification__FileSystemSpecialPath, + }).annotate({ title: "SpecialFileSystemPath" }), + ], + { mode: "oneOf" }, +); + export type ServerNotification__TurnError = { readonly additionalDetails?: string | null; readonly codexErrorInfo?: ServerNotification__CodexErrorInfo | null; @@ -18604,6 +20325,7 @@ export type ServerNotification__ThreadItem = readonly type: "fileChange"; } | { + readonly appContext?: ServerNotification__McpToolCallAppContext | null; readonly arguments: unknown; readonly durationMs?: number | null; readonly error?: ServerNotification__McpToolCallError | null; @@ -18650,13 +20372,15 @@ export type ServerNotification__ThreadItem = readonly action?: ServerNotification__WebSearchAction | null; readonly id: string; readonly query: string; + readonly results?: ReadonlyArray | null; readonly type: "webSearch"; } | { readonly id: string; - readonly path: ServerNotification__AbsolutePathBuf; + readonly path: ServerNotification__LegacyAppPathString; readonly type: "imageView"; } + | { readonly durationMs: number; readonly id: string; readonly type: "sleep" } | { readonly id: string; readonly result: string; @@ -18719,10 +20443,7 @@ export const ServerNotification__ThreadItem = Schema.Union( description: "A best-effort parsing of the command to understand the action(s) it will perform. This returns a list of CommandAction objects because a single shell command may be composed of many commands piped together.", }), - cwd: Schema.String.annotate({ - description: - "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", - }), + cwd: Schema.String.annotate({ description: "The command's working directory." }), durationMs: Schema.optionalKey( Schema.Union([ Schema.Number.annotate({ @@ -18770,6 +20491,9 @@ export const ServerNotification__ThreadItem = Schema.Union( type: Schema.Literal("fileChange").annotate({ title: "FileChangeThreadItemType" }), }).annotate({ title: "FileChangeThreadItem" }), Schema.Struct({ + appContext: Schema.optionalKey( + Schema.Union([ServerNotification__McpToolCallAppContext, Schema.Null]), + ), arguments: Schema.Unknown, durationMs: Schema.optionalKey( Schema.Union([ @@ -18782,7 +20506,14 @@ export const ServerNotification__ThreadItem = Schema.Union( ), error: Schema.optionalKey(Schema.Union([ServerNotification__McpToolCallError, Schema.Null])), id: Schema.String, - mcpAppResourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + mcpAppResourceUri: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Deprecated: use `appContext.resourceUri` instead.", + }), + Schema.Null, + ]), + ), pluginId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), result: Schema.optionalKey( Schema.Union([ServerNotification__McpToolCallResult, Schema.Null]), @@ -18876,13 +20607,32 @@ export const ServerNotification__ThreadItem = Schema.Union( action: Schema.optionalKey(Schema.Union([ServerNotification__WebSearchAction, Schema.Null])), id: Schema.String, query: Schema.String, + results: Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Unknown).annotate({ + description: + "Structured search results returned out-of-band by standalone web search.\n\nThese stay as opaque JSON at the extension/app-server boundary so new result fields and result types can pass through without a Codex release.", + }), + Schema.Null, + ]), + ), type: Schema.Literal("webSearch").annotate({ title: "WebSearchThreadItemType" }), }).annotate({ title: "WebSearchThreadItem" }), Schema.Struct({ id: Schema.String, - path: ServerNotification__AbsolutePathBuf, + path: ServerNotification__LegacyAppPathString, type: Schema.Literal("imageView").annotate({ title: "ImageViewThreadItemType" }), }).annotate({ title: "ImageViewThreadItem" }), + Schema.Struct({ + durationMs: Schema.Number.annotate({ format: "uint64" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(0)), + id: Schema.String, + type: Schema.Literal("sleep").annotate({ title: "SleepThreadItemType" }), + }).annotate({ + title: "SleepThreadItem", + description: "Display item emitted by the interruptible `clock.sleep` tool.", + }), Schema.Struct({ id: Schema.String, result: Schema.String, @@ -18990,14 +20740,27 @@ export const ServerNotification__TurnPlanUpdatedNotification = Schema.Struct({ turnId: Schema.String, }); -export type ServerRequest__FileSystemSandboxEntry = { - readonly access: ServerRequest__FileSystemAccessMode; - readonly path: ServerRequest__FileSystemPath; -}; -export const ServerRequest__FileSystemSandboxEntry = Schema.Struct({ - access: ServerRequest__FileSystemAccessMode, - path: ServerRequest__FileSystemPath, -}); +export type ServerRequest__FileSystemPath = + | { readonly path: ServerRequest__LegacyAppPathString; readonly type: "path" } + | { readonly pattern: string; readonly type: "glob_pattern" } + | { readonly type: "special"; readonly value: ServerRequest__FileSystemSpecialPath }; +export const ServerRequest__FileSystemPath = Schema.Union( + [ + Schema.Struct({ + path: ServerRequest__LegacyAppPathString, + type: Schema.Literal("path").annotate({ title: "PathFileSystemPathType" }), + }).annotate({ title: "PathFileSystemPath" }), + Schema.Struct({ + pattern: Schema.String, + type: Schema.Literal("glob_pattern").annotate({ title: "GlobPatternFileSystemPathType" }), + }).annotate({ title: "GlobPatternFileSystemPath" }), + Schema.Struct({ + type: Schema.Literal("special").annotate({ title: "SpecialFileSystemPathType" }), + value: ServerRequest__FileSystemSpecialPath, + }).annotate({ title: "SpecialFileSystemPath" }), + ], + { mode: "oneOf" }, +); export type ServerRequest__McpElicitationTitledMultiSelectEnumSchema = { readonly default?: ReadonlyArray | null; @@ -19077,7 +20840,8 @@ export type ServerRequest__CommandExecutionRequestApprovalParams = { readonly approvalId?: string | null; readonly command?: string | null; readonly commandActions?: ReadonlyArray | null; - readonly cwd?: ServerRequest__AbsolutePathBuf | null; + readonly cwd?: ServerRequest__LegacyAppPathString | null; + readonly environmentId?: string | null; readonly itemId: string; readonly networkApprovalContext?: ServerRequest__NetworkApprovalContext | null; readonly proposedExecpolicyAmendment?: ReadonlyArray | null; @@ -19112,10 +20876,16 @@ export const ServerRequest__CommandExecutionRequestApprovalParams = Schema.Struc ]), ), cwd: Schema.optionalKey( - Schema.Union([ServerRequest__AbsolutePathBuf, Schema.Null]).annotate({ + Schema.Union([ServerRequest__LegacyAppPathString, Schema.Null]).annotate({ description: "The command's working directory.", }), ), + environmentId: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ description: "Environment in which the command will run." }), + Schema.Null, + ]), + ), itemId: Schema.String, networkApprovalContext: Schema.optionalKey( Schema.Union([ServerRequest__NetworkApprovalContext, Schema.Null]).annotate({ @@ -19157,12 +20927,21 @@ export const ServerRequest__CommandExecutionRequestApprovalParams = Schema.Struc }); export type ServerRequest__ToolRequestUserInputParams = { + readonly autoResolutionMs?: number | null; readonly itemId: string; readonly questions: ReadonlyArray; readonly threadId: string; readonly turnId: string; }; export const ServerRequest__ToolRequestUserInputParams = Schema.Struct({ + autoResolutionMs: Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ format: "uint64" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(0)), + Schema.Null, + ]), + ), itemId: Schema.String, questions: Schema.Array(ServerRequest__ToolRequestUserInputQuestion), threadId: Schema.String, @@ -19174,6 +20953,8 @@ export type V2AppListUpdatedNotification__AppInfo = { readonly branding?: V2AppListUpdatedNotification__AppBranding | null; readonly description?: string | null; readonly distributionChannel?: string | null; + readonly iconAssets?: { readonly [x: string]: string } | null; + readonly iconDarkAssets?: { readonly [x: string]: string } | null; readonly id: string; readonly installUrl?: string | null; readonly isAccessible?: boolean; @@ -19193,6 +20974,12 @@ export const V2AppListUpdatedNotification__AppInfo = Schema.Struct({ ), description: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), distributionChannel: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + iconAssets: Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.String), Schema.Null]), + ), + iconDarkAssets: Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.String), Schema.Null]), + ), id: Schema.String, installUrl: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), isAccessible: Schema.optionalKey(Schema.Boolean.annotate({ default: false })), @@ -19217,6 +21004,8 @@ export type V2AppsListResponse__AppInfo = { readonly branding?: V2AppsListResponse__AppBranding | null; readonly description?: string | null; readonly distributionChannel?: string | null; + readonly iconAssets?: { readonly [x: string]: string } | null; + readonly iconDarkAssets?: { readonly [x: string]: string } | null; readonly id: string; readonly installUrl?: string | null; readonly isAccessible?: boolean; @@ -19232,6 +21021,12 @@ export const V2AppsListResponse__AppInfo = Schema.Struct({ branding: Schema.optionalKey(Schema.Union([V2AppsListResponse__AppBranding, Schema.Null])), description: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), distributionChannel: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + iconAssets: Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.String), Schema.Null]), + ), + iconDarkAssets: Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.String), Schema.Null]), + ), id: Schema.String, installUrl: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), isAccessible: Schema.optionalKey(Schema.Boolean.annotate({ default: false })), @@ -19282,6 +21077,15 @@ export const V2ConfigReadResponse__ToolsV2 = Schema.Struct({ ), }); +export type V2ConfigRequirementsReadResponse__ModelsRequirements = { + readonly newThread?: V2ConfigRequirementsReadResponse__NewThreadModelDefaults | null; +}; +export const V2ConfigRequirementsReadResponse__ModelsRequirements = Schema.Struct({ + newThread: Schema.optionalKey( + Schema.Union([V2ConfigRequirementsReadResponse__NewThreadModelDefaults, Schema.Null]), + ), +}); + export type V2ConfigWriteResponse__ConfigLayerMetadata = { readonly name: V2ConfigWriteResponse__ConfigLayerSource; readonly version: string; @@ -19327,6 +21131,42 @@ export const V2ExternalAgentConfigDetectResponse__ExternalAgentConfigMigrationIt itemType: V2ExternalAgentConfigDetectResponse__ExternalAgentConfigMigrationItemType, }); +export type V2ExternalAgentConfigImportCompletedNotification__ExternalAgentConfigImportTypeResult = + { + readonly failures: ReadonlyArray; + readonly itemType: V2ExternalAgentConfigImportCompletedNotification__ExternalAgentConfigMigrationItemType; + readonly successes: ReadonlyArray; + }; +export const V2ExternalAgentConfigImportCompletedNotification__ExternalAgentConfigImportTypeResult = + Schema.Struct({ + failures: Schema.Array( + V2ExternalAgentConfigImportCompletedNotification__ExternalAgentConfigImportItemTypeFailure, + ), + itemType: + V2ExternalAgentConfigImportCompletedNotification__ExternalAgentConfigMigrationItemType, + successes: Schema.Array( + V2ExternalAgentConfigImportCompletedNotification__ExternalAgentConfigImportItemTypeSuccess, + ), + }); + +export type V2ExternalAgentConfigImportHistoriesReadResponse__ExternalAgentConfigImportHistory = { + readonly completedAtMs: number; + readonly failures: ReadonlyArray; + readonly importId: string; + readonly successes: ReadonlyArray; +}; +export const V2ExternalAgentConfigImportHistoriesReadResponse__ExternalAgentConfigImportHistory = + Schema.Struct({ + completedAtMs: Schema.Number.annotate({ format: "int64" }).check(Schema.isInt()), + failures: Schema.Array( + V2ExternalAgentConfigImportHistoriesReadResponse__ExternalAgentConfigImportItemTypeFailure, + ), + importId: Schema.String, + successes: Schema.Array( + V2ExternalAgentConfigImportHistoriesReadResponse__ExternalAgentConfigImportItemTypeSuccess, + ), + }); + export type V2ExternalAgentConfigImportParams__ExternalAgentConfigMigrationItem = { readonly cwd?: string | null; readonly description: string; @@ -19350,6 +21190,39 @@ export const V2ExternalAgentConfigImportParams__ExternalAgentConfigMigrationItem itemType: V2ExternalAgentConfigImportParams__ExternalAgentConfigMigrationItemType, }); +export type V2ExternalAgentConfigImportProgressNotification__ExternalAgentConfigImportTypeResult = { + readonly failures: ReadonlyArray; + readonly itemType: V2ExternalAgentConfigImportProgressNotification__ExternalAgentConfigMigrationItemType; + readonly successes: ReadonlyArray; +}; +export const V2ExternalAgentConfigImportProgressNotification__ExternalAgentConfigImportTypeResult = + Schema.Struct({ + failures: Schema.Array( + V2ExternalAgentConfigImportProgressNotification__ExternalAgentConfigImportItemTypeFailure, + ), + itemType: V2ExternalAgentConfigImportProgressNotification__ExternalAgentConfigMigrationItemType, + successes: Schema.Array( + V2ExternalAgentConfigImportProgressNotification__ExternalAgentConfigImportItemTypeSuccess, + ), + }); + +export type V2GetAccountRateLimitsResponse__RateLimitResetCreditsSummary = { + readonly availableCount: number; + readonly credits?: ReadonlyArray | null; +}; +export const V2GetAccountRateLimitsResponse__RateLimitResetCreditsSummary = Schema.Struct({ + availableCount: Schema.Number.annotate({ format: "int64" }).check(Schema.isInt()), + credits: Schema.optionalKey( + Schema.Union([ + Schema.Array(V2GetAccountRateLimitsResponse__RateLimitResetCredit).annotate({ + description: + "Detail rows for available reset credits, when the backend provides them.\n\n`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`.", + }), + Schema.Null, + ]), + ), +}); + export type V2HookCompletedNotification__HookRunSummary = { readonly completedAt?: number | null; readonly displayOrder: number; @@ -19533,6 +21406,7 @@ export type V2ItemCompletedNotification__ThreadItem = readonly type: "fileChange"; } | { + readonly appContext?: V2ItemCompletedNotification__McpToolCallAppContext | null; readonly arguments: unknown; readonly durationMs?: number | null; readonly error?: V2ItemCompletedNotification__McpToolCallError | null; @@ -19581,13 +21455,15 @@ export type V2ItemCompletedNotification__ThreadItem = readonly action?: V2ItemCompletedNotification__WebSearchAction | null; readonly id: string; readonly query: string; + readonly results?: ReadonlyArray | null; readonly type: "webSearch"; } | { readonly id: string; - readonly path: V2ItemCompletedNotification__AbsolutePathBuf; + readonly path: V2ItemCompletedNotification__LegacyAppPathString; readonly type: "imageView"; } + | { readonly durationMs: number; readonly id: string; readonly type: "sleep" } | { readonly id: string; readonly result: string; @@ -19652,10 +21528,7 @@ export const V2ItemCompletedNotification__ThreadItem = Schema.Union( description: "A best-effort parsing of the command to understand the action(s) it will perform. This returns a list of CommandAction objects because a single shell command may be composed of many commands piped together.", }), - cwd: Schema.String.annotate({ - description: - "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", - }), + cwd: Schema.String.annotate({ description: "The command's working directory." }), durationMs: Schema.optionalKey( Schema.Union([ Schema.Number.annotate({ @@ -19703,6 +21576,9 @@ export const V2ItemCompletedNotification__ThreadItem = Schema.Union( type: Schema.Literal("fileChange").annotate({ title: "FileChangeThreadItemType" }), }).annotate({ title: "FileChangeThreadItem" }), Schema.Struct({ + appContext: Schema.optionalKey( + Schema.Union([V2ItemCompletedNotification__McpToolCallAppContext, Schema.Null]), + ), arguments: Schema.Unknown, durationMs: Schema.optionalKey( Schema.Union([ @@ -19717,7 +21593,14 @@ export const V2ItemCompletedNotification__ThreadItem = Schema.Union( Schema.Union([V2ItemCompletedNotification__McpToolCallError, Schema.Null]), ), id: Schema.String, - mcpAppResourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + mcpAppResourceUri: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Deprecated: use `appContext.resourceUri` instead.", + }), + Schema.Null, + ]), + ), pluginId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), result: Schema.optionalKey( Schema.Union([V2ItemCompletedNotification__McpToolCallResult, Schema.Null]), @@ -19814,13 +21697,32 @@ export const V2ItemCompletedNotification__ThreadItem = Schema.Union( ), id: Schema.String, query: Schema.String, + results: Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Unknown).annotate({ + description: + "Structured search results returned out-of-band by standalone web search.\n\nThese stay as opaque JSON at the extension/app-server boundary so new result fields and result types can pass through without a Codex release.", + }), + Schema.Null, + ]), + ), type: Schema.Literal("webSearch").annotate({ title: "WebSearchThreadItemType" }), }).annotate({ title: "WebSearchThreadItem" }), Schema.Struct({ id: Schema.String, - path: V2ItemCompletedNotification__AbsolutePathBuf, + path: V2ItemCompletedNotification__LegacyAppPathString, type: Schema.Literal("imageView").annotate({ title: "ImageViewThreadItemType" }), }).annotate({ title: "ImageViewThreadItem" }), + Schema.Struct({ + durationMs: Schema.Number.annotate({ format: "uint64" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(0)), + id: Schema.String, + type: Schema.Literal("sleep").annotate({ title: "SleepThreadItemType" }), + }).annotate({ + title: "SleepThreadItem", + description: "Display item emitted by the interruptible `clock.sleep` tool.", + }), Schema.Struct({ id: Schema.String, result: Schema.String, @@ -19855,25 +21757,61 @@ export const V2ItemCompletedNotification__ThreadItem = Schema.Union( { mode: "oneOf" }, ); -export type V2ItemGuardianApprovalReviewCompletedNotification__FileSystemSandboxEntry = { - readonly access: V2ItemGuardianApprovalReviewCompletedNotification__FileSystemAccessMode; - readonly path: V2ItemGuardianApprovalReviewCompletedNotification__FileSystemPath; -}; -export const V2ItemGuardianApprovalReviewCompletedNotification__FileSystemSandboxEntry = - Schema.Struct({ - access: V2ItemGuardianApprovalReviewCompletedNotification__FileSystemAccessMode, - path: V2ItemGuardianApprovalReviewCompletedNotification__FileSystemPath, - }); +export type V2ItemGuardianApprovalReviewCompletedNotification__FileSystemPath = + | { + readonly path: V2ItemGuardianApprovalReviewCompletedNotification__LegacyAppPathString; + readonly type: "path"; + } + | { readonly pattern: string; readonly type: "glob_pattern" } + | { + readonly type: "special"; + readonly value: V2ItemGuardianApprovalReviewCompletedNotification__FileSystemSpecialPath; + }; +export const V2ItemGuardianApprovalReviewCompletedNotification__FileSystemPath = Schema.Union( + [ + Schema.Struct({ + path: V2ItemGuardianApprovalReviewCompletedNotification__LegacyAppPathString, + type: Schema.Literal("path").annotate({ title: "PathFileSystemPathType" }), + }).annotate({ title: "PathFileSystemPath" }), + Schema.Struct({ + pattern: Schema.String, + type: Schema.Literal("glob_pattern").annotate({ title: "GlobPatternFileSystemPathType" }), + }).annotate({ title: "GlobPatternFileSystemPath" }), + Schema.Struct({ + type: Schema.Literal("special").annotate({ title: "SpecialFileSystemPathType" }), + value: V2ItemGuardianApprovalReviewCompletedNotification__FileSystemSpecialPath, + }).annotate({ title: "SpecialFileSystemPath" }), + ], + { mode: "oneOf" }, +); -export type V2ItemGuardianApprovalReviewStartedNotification__FileSystemSandboxEntry = { - readonly access: V2ItemGuardianApprovalReviewStartedNotification__FileSystemAccessMode; - readonly path: V2ItemGuardianApprovalReviewStartedNotification__FileSystemPath; -}; -export const V2ItemGuardianApprovalReviewStartedNotification__FileSystemSandboxEntry = - Schema.Struct({ - access: V2ItemGuardianApprovalReviewStartedNotification__FileSystemAccessMode, - path: V2ItemGuardianApprovalReviewStartedNotification__FileSystemPath, - }); +export type V2ItemGuardianApprovalReviewStartedNotification__FileSystemPath = + | { + readonly path: V2ItemGuardianApprovalReviewStartedNotification__LegacyAppPathString; + readonly type: "path"; + } + | { readonly pattern: string; readonly type: "glob_pattern" } + | { + readonly type: "special"; + readonly value: V2ItemGuardianApprovalReviewStartedNotification__FileSystemSpecialPath; + }; +export const V2ItemGuardianApprovalReviewStartedNotification__FileSystemPath = Schema.Union( + [ + Schema.Struct({ + path: V2ItemGuardianApprovalReviewStartedNotification__LegacyAppPathString, + type: Schema.Literal("path").annotate({ title: "PathFileSystemPathType" }), + }).annotate({ title: "PathFileSystemPath" }), + Schema.Struct({ + pattern: Schema.String, + type: Schema.Literal("glob_pattern").annotate({ title: "GlobPatternFileSystemPathType" }), + }).annotate({ title: "GlobPatternFileSystemPath" }), + Schema.Struct({ + type: Schema.Literal("special").annotate({ title: "SpecialFileSystemPathType" }), + value: V2ItemGuardianApprovalReviewStartedNotification__FileSystemSpecialPath, + }).annotate({ title: "SpecialFileSystemPath" }), + ], + { mode: "oneOf" }, +); export type V2ItemStartedNotification__ThreadItem = | { @@ -19921,6 +21859,7 @@ export type V2ItemStartedNotification__ThreadItem = readonly type: "fileChange"; } | { + readonly appContext?: V2ItemStartedNotification__McpToolCallAppContext | null; readonly arguments: unknown; readonly durationMs?: number | null; readonly error?: V2ItemStartedNotification__McpToolCallError | null; @@ -19967,13 +21906,15 @@ export type V2ItemStartedNotification__ThreadItem = readonly action?: V2ItemStartedNotification__WebSearchAction | null; readonly id: string; readonly query: string; + readonly results?: ReadonlyArray | null; readonly type: "webSearch"; } | { readonly id: string; - readonly path: V2ItemStartedNotification__AbsolutePathBuf; + readonly path: V2ItemStartedNotification__LegacyAppPathString; readonly type: "imageView"; } + | { readonly durationMs: number; readonly id: string; readonly type: "sleep" } | { readonly id: string; readonly result: string; @@ -20038,10 +21979,7 @@ export const V2ItemStartedNotification__ThreadItem = Schema.Union( description: "A best-effort parsing of the command to understand the action(s) it will perform. This returns a list of CommandAction objects because a single shell command may be composed of many commands piped together.", }), - cwd: Schema.String.annotate({ - description: - "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", - }), + cwd: Schema.String.annotate({ description: "The command's working directory." }), durationMs: Schema.optionalKey( Schema.Union([ Schema.Number.annotate({ @@ -20089,6 +22027,9 @@ export const V2ItemStartedNotification__ThreadItem = Schema.Union( type: Schema.Literal("fileChange").annotate({ title: "FileChangeThreadItemType" }), }).annotate({ title: "FileChangeThreadItem" }), Schema.Struct({ + appContext: Schema.optionalKey( + Schema.Union([V2ItemStartedNotification__McpToolCallAppContext, Schema.Null]), + ), arguments: Schema.Unknown, durationMs: Schema.optionalKey( Schema.Union([ @@ -20103,7 +22044,14 @@ export const V2ItemStartedNotification__ThreadItem = Schema.Union( Schema.Union([V2ItemStartedNotification__McpToolCallError, Schema.Null]), ), id: Schema.String, - mcpAppResourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + mcpAppResourceUri: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Deprecated: use `appContext.resourceUri` instead.", + }), + Schema.Null, + ]), + ), pluginId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), result: Schema.optionalKey( Schema.Union([V2ItemStartedNotification__McpToolCallResult, Schema.Null]), @@ -20200,13 +22148,32 @@ export const V2ItemStartedNotification__ThreadItem = Schema.Union( ), id: Schema.String, query: Schema.String, + results: Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Unknown).annotate({ + description: + "Structured search results returned out-of-band by standalone web search.\n\nThese stay as opaque JSON at the extension/app-server boundary so new result fields and result types can pass through without a Codex release.", + }), + Schema.Null, + ]), + ), type: Schema.Literal("webSearch").annotate({ title: "WebSearchThreadItemType" }), }).annotate({ title: "WebSearchThreadItem" }), Schema.Struct({ id: Schema.String, - path: V2ItemStartedNotification__AbsolutePathBuf, + path: V2ItemStartedNotification__LegacyAppPathString, type: Schema.Literal("imageView").annotate({ title: "ImageViewThreadItemType" }), }).annotate({ title: "ImageViewThreadItem" }), + Schema.Struct({ + durationMs: Schema.Number.annotate({ format: "uint64" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(0)), + id: Schema.String, + type: Schema.Literal("sleep").annotate({ title: "SleepThreadItemType" }), + }).annotate({ + title: "SleepThreadItem", + description: "Display item emitted by the interruptible `clock.sleep` tool.", + }), Schema.Struct({ id: Schema.String, result: Schema.String, @@ -20405,6 +22372,19 @@ export const V2PluginReadResponse__PluginShareContext = Schema.Struct({ shareUrl: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), }); +export type V2PluginReadResponse__ScheduledTaskSummary = { + readonly key: string; + readonly name: string; + readonly prompt: string; + readonly schedule: V2PluginReadResponse__ScheduledTaskSchedule; +}; +export const V2PluginReadResponse__ScheduledTaskSummary = Schema.Struct({ + key: Schema.String, + name: Schema.String, + prompt: Schema.String, + schedule: V2PluginReadResponse__ScheduledTaskSchedule, +}); + export type V2PluginShareListResponse__PluginShareContext = { readonly creatorAccountUserId?: string | null; readonly creatorName?: string | null; @@ -20502,6 +22482,7 @@ export type V2ReviewStartResponse__ThreadItem = readonly type: "fileChange"; } | { + readonly appContext?: V2ReviewStartResponse__McpToolCallAppContext | null; readonly arguments: unknown; readonly durationMs?: number | null; readonly error?: V2ReviewStartResponse__McpToolCallError | null; @@ -20548,13 +22529,15 @@ export type V2ReviewStartResponse__ThreadItem = readonly action?: V2ReviewStartResponse__WebSearchAction | null; readonly id: string; readonly query: string; + readonly results?: ReadonlyArray | null; readonly type: "webSearch"; } | { readonly id: string; - readonly path: V2ReviewStartResponse__AbsolutePathBuf; + readonly path: V2ReviewStartResponse__LegacyAppPathString; readonly type: "imageView"; } + | { readonly durationMs: number; readonly id: string; readonly type: "sleep" } | { readonly id: string; readonly result: string; @@ -20617,10 +22600,7 @@ export const V2ReviewStartResponse__ThreadItem = Schema.Union( description: "A best-effort parsing of the command to understand the action(s) it will perform. This returns a list of CommandAction objects because a single shell command may be composed of many commands piped together.", }), - cwd: Schema.String.annotate({ - description: - "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", - }), + cwd: Schema.String.annotate({ description: "The command's working directory." }), durationMs: Schema.optionalKey( Schema.Union([ Schema.Number.annotate({ @@ -20668,6 +22648,9 @@ export const V2ReviewStartResponse__ThreadItem = Schema.Union( type: Schema.Literal("fileChange").annotate({ title: "FileChangeThreadItemType" }), }).annotate({ title: "FileChangeThreadItem" }), Schema.Struct({ + appContext: Schema.optionalKey( + Schema.Union([V2ReviewStartResponse__McpToolCallAppContext, Schema.Null]), + ), arguments: Schema.Unknown, durationMs: Schema.optionalKey( Schema.Union([ @@ -20682,7 +22665,14 @@ export const V2ReviewStartResponse__ThreadItem = Schema.Union( Schema.Union([V2ReviewStartResponse__McpToolCallError, Schema.Null]), ), id: Schema.String, - mcpAppResourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + mcpAppResourceUri: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Deprecated: use `appContext.resourceUri` instead.", + }), + Schema.Null, + ]), + ), pluginId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), result: Schema.optionalKey( Schema.Union([V2ReviewStartResponse__McpToolCallResult, Schema.Null]), @@ -20778,13 +22768,32 @@ export const V2ReviewStartResponse__ThreadItem = Schema.Union( ), id: Schema.String, query: Schema.String, + results: Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Unknown).annotate({ + description: + "Structured search results returned out-of-band by standalone web search.\n\nThese stay as opaque JSON at the extension/app-server boundary so new result fields and result types can pass through without a Codex release.", + }), + Schema.Null, + ]), + ), type: Schema.Literal("webSearch").annotate({ title: "WebSearchThreadItemType" }), }).annotate({ title: "WebSearchThreadItem" }), Schema.Struct({ id: Schema.String, - path: V2ReviewStartResponse__AbsolutePathBuf, + path: V2ReviewStartResponse__LegacyAppPathString, type: Schema.Literal("imageView").annotate({ title: "ImageViewThreadItemType" }), }).annotate({ title: "ImageViewThreadItem" }), + Schema.Struct({ + durationMs: Schema.Number.annotate({ format: "uint64" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(0)), + id: Schema.String, + type: Schema.Literal("sleep").annotate({ title: "SleepThreadItemType" }), + }).annotate({ + title: "SleepThreadItem", + description: "Display item emitted by the interruptible `clock.sleep` tool.", + }), Schema.Struct({ id: Schema.String, result: Schema.String, @@ -20909,6 +22918,7 @@ export type V2ThreadForkResponse__ThreadItem = readonly type: "fileChange"; } | { + readonly appContext?: V2ThreadForkResponse__McpToolCallAppContext | null; readonly arguments: unknown; readonly durationMs?: number | null; readonly error?: V2ThreadForkResponse__McpToolCallError | null; @@ -20955,13 +22965,15 @@ export type V2ThreadForkResponse__ThreadItem = readonly action?: V2ThreadForkResponse__WebSearchAction | null; readonly id: string; readonly query: string; + readonly results?: ReadonlyArray | null; readonly type: "webSearch"; } | { readonly id: string; - readonly path: V2ThreadForkResponse__AbsolutePathBuf; + readonly path: V2ThreadForkResponse__LegacyAppPathString; readonly type: "imageView"; } + | { readonly durationMs: number; readonly id: string; readonly type: "sleep" } | { readonly id: string; readonly result: string; @@ -21024,10 +23036,7 @@ export const V2ThreadForkResponse__ThreadItem = Schema.Union( description: "A best-effort parsing of the command to understand the action(s) it will perform. This returns a list of CommandAction objects because a single shell command may be composed of many commands piped together.", }), - cwd: Schema.String.annotate({ - description: - "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", - }), + cwd: Schema.String.annotate({ description: "The command's working directory." }), durationMs: Schema.optionalKey( Schema.Union([ Schema.Number.annotate({ @@ -21075,6 +23084,9 @@ export const V2ThreadForkResponse__ThreadItem = Schema.Union( type: Schema.Literal("fileChange").annotate({ title: "FileChangeThreadItemType" }), }).annotate({ title: "FileChangeThreadItem" }), Schema.Struct({ + appContext: Schema.optionalKey( + Schema.Union([V2ThreadForkResponse__McpToolCallAppContext, Schema.Null]), + ), arguments: Schema.Unknown, durationMs: Schema.optionalKey( Schema.Union([ @@ -21089,7 +23101,14 @@ export const V2ThreadForkResponse__ThreadItem = Schema.Union( Schema.Union([V2ThreadForkResponse__McpToolCallError, Schema.Null]), ), id: Schema.String, - mcpAppResourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + mcpAppResourceUri: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Deprecated: use `appContext.resourceUri` instead.", + }), + Schema.Null, + ]), + ), pluginId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), result: Schema.optionalKey( Schema.Union([V2ThreadForkResponse__McpToolCallResult, Schema.Null]), @@ -21185,13 +23204,32 @@ export const V2ThreadForkResponse__ThreadItem = Schema.Union( ), id: Schema.String, query: Schema.String, + results: Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Unknown).annotate({ + description: + "Structured search results returned out-of-band by standalone web search.\n\nThese stay as opaque JSON at the extension/app-server boundary so new result fields and result types can pass through without a Codex release.", + }), + Schema.Null, + ]), + ), type: Schema.Literal("webSearch").annotate({ title: "WebSearchThreadItemType" }), }).annotate({ title: "WebSearchThreadItem" }), Schema.Struct({ id: Schema.String, - path: V2ThreadForkResponse__AbsolutePathBuf, + path: V2ThreadForkResponse__LegacyAppPathString, type: Schema.Literal("imageView").annotate({ title: "ImageViewThreadItemType" }), }).annotate({ title: "ImageViewThreadItem" }), + Schema.Struct({ + durationMs: Schema.Number.annotate({ format: "uint64" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(0)), + id: Schema.String, + type: Schema.Literal("sleep").annotate({ title: "SleepThreadItemType" }), + }).annotate({ + title: "SleepThreadItem", + description: "Display item emitted by the interruptible `clock.sleep` tool.", + }), Schema.Struct({ id: Schema.String, result: Schema.String, @@ -21285,6 +23323,7 @@ export type V2ThreadListResponse__ThreadItem = readonly type: "fileChange"; } | { + readonly appContext?: V2ThreadListResponse__McpToolCallAppContext | null; readonly arguments: unknown; readonly durationMs?: number | null; readonly error?: V2ThreadListResponse__McpToolCallError | null; @@ -21331,13 +23370,15 @@ export type V2ThreadListResponse__ThreadItem = readonly action?: V2ThreadListResponse__WebSearchAction | null; readonly id: string; readonly query: string; + readonly results?: ReadonlyArray | null; readonly type: "webSearch"; } | { readonly id: string; - readonly path: V2ThreadListResponse__AbsolutePathBuf; + readonly path: V2ThreadListResponse__LegacyAppPathString; readonly type: "imageView"; } + | { readonly durationMs: number; readonly id: string; readonly type: "sleep" } | { readonly id: string; readonly result: string; @@ -21400,10 +23441,7 @@ export const V2ThreadListResponse__ThreadItem = Schema.Union( description: "A best-effort parsing of the command to understand the action(s) it will perform. This returns a list of CommandAction objects because a single shell command may be composed of many commands piped together.", }), - cwd: Schema.String.annotate({ - description: - "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", - }), + cwd: Schema.String.annotate({ description: "The command's working directory." }), durationMs: Schema.optionalKey( Schema.Union([ Schema.Number.annotate({ @@ -21451,6 +23489,9 @@ export const V2ThreadListResponse__ThreadItem = Schema.Union( type: Schema.Literal("fileChange").annotate({ title: "FileChangeThreadItemType" }), }).annotate({ title: "FileChangeThreadItem" }), Schema.Struct({ + appContext: Schema.optionalKey( + Schema.Union([V2ThreadListResponse__McpToolCallAppContext, Schema.Null]), + ), arguments: Schema.Unknown, durationMs: Schema.optionalKey( Schema.Union([ @@ -21465,7 +23506,14 @@ export const V2ThreadListResponse__ThreadItem = Schema.Union( Schema.Union([V2ThreadListResponse__McpToolCallError, Schema.Null]), ), id: Schema.String, - mcpAppResourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + mcpAppResourceUri: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Deprecated: use `appContext.resourceUri` instead.", + }), + Schema.Null, + ]), + ), pluginId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), result: Schema.optionalKey( Schema.Union([V2ThreadListResponse__McpToolCallResult, Schema.Null]), @@ -21561,13 +23609,32 @@ export const V2ThreadListResponse__ThreadItem = Schema.Union( ), id: Schema.String, query: Schema.String, + results: Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Unknown).annotate({ + description: + "Structured search results returned out-of-band by standalone web search.\n\nThese stay as opaque JSON at the extension/app-server boundary so new result fields and result types can pass through without a Codex release.", + }), + Schema.Null, + ]), + ), type: Schema.Literal("webSearch").annotate({ title: "WebSearchThreadItemType" }), }).annotate({ title: "WebSearchThreadItem" }), Schema.Struct({ id: Schema.String, - path: V2ThreadListResponse__AbsolutePathBuf, + path: V2ThreadListResponse__LegacyAppPathString, type: Schema.Literal("imageView").annotate({ title: "ImageViewThreadItemType" }), }).annotate({ title: "ImageViewThreadItem" }), + Schema.Struct({ + durationMs: Schema.Number.annotate({ format: "uint64" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(0)), + id: Schema.String, + type: Schema.Literal("sleep").annotate({ title: "SleepThreadItemType" }), + }).annotate({ + title: "SleepThreadItem", + description: "Display item emitted by the interruptible `clock.sleep` tool.", + }), Schema.Struct({ id: Schema.String, result: Schema.String, @@ -21661,6 +23728,7 @@ export type V2ThreadMetadataUpdateResponse__ThreadItem = readonly type: "fileChange"; } | { + readonly appContext?: V2ThreadMetadataUpdateResponse__McpToolCallAppContext | null; readonly arguments: unknown; readonly durationMs?: number | null; readonly error?: V2ThreadMetadataUpdateResponse__McpToolCallError | null; @@ -21709,13 +23777,15 @@ export type V2ThreadMetadataUpdateResponse__ThreadItem = readonly action?: V2ThreadMetadataUpdateResponse__WebSearchAction | null; readonly id: string; readonly query: string; + readonly results?: ReadonlyArray | null; readonly type: "webSearch"; } | { readonly id: string; - readonly path: V2ThreadMetadataUpdateResponse__AbsolutePathBuf; + readonly path: V2ThreadMetadataUpdateResponse__LegacyAppPathString; readonly type: "imageView"; } + | { readonly durationMs: number; readonly id: string; readonly type: "sleep" } | { readonly id: string; readonly result: string; @@ -21780,10 +23850,7 @@ export const V2ThreadMetadataUpdateResponse__ThreadItem = Schema.Union( description: "A best-effort parsing of the command to understand the action(s) it will perform. This returns a list of CommandAction objects because a single shell command may be composed of many commands piped together.", }), - cwd: Schema.String.annotate({ - description: - "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", - }), + cwd: Schema.String.annotate({ description: "The command's working directory." }), durationMs: Schema.optionalKey( Schema.Union([ Schema.Number.annotate({ @@ -21831,6 +23898,9 @@ export const V2ThreadMetadataUpdateResponse__ThreadItem = Schema.Union( type: Schema.Literal("fileChange").annotate({ title: "FileChangeThreadItemType" }), }).annotate({ title: "FileChangeThreadItem" }), Schema.Struct({ + appContext: Schema.optionalKey( + Schema.Union([V2ThreadMetadataUpdateResponse__McpToolCallAppContext, Schema.Null]), + ), arguments: Schema.Unknown, durationMs: Schema.optionalKey( Schema.Union([ @@ -21845,7 +23915,14 @@ export const V2ThreadMetadataUpdateResponse__ThreadItem = Schema.Union( Schema.Union([V2ThreadMetadataUpdateResponse__McpToolCallError, Schema.Null]), ), id: Schema.String, - mcpAppResourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + mcpAppResourceUri: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Deprecated: use `appContext.resourceUri` instead.", + }), + Schema.Null, + ]), + ), pluginId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), result: Schema.optionalKey( Schema.Union([V2ThreadMetadataUpdateResponse__McpToolCallResult, Schema.Null]), @@ -21942,13 +24019,32 @@ export const V2ThreadMetadataUpdateResponse__ThreadItem = Schema.Union( ), id: Schema.String, query: Schema.String, + results: Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Unknown).annotate({ + description: + "Structured search results returned out-of-band by standalone web search.\n\nThese stay as opaque JSON at the extension/app-server boundary so new result fields and result types can pass through without a Codex release.", + }), + Schema.Null, + ]), + ), type: Schema.Literal("webSearch").annotate({ title: "WebSearchThreadItemType" }), }).annotate({ title: "WebSearchThreadItem" }), Schema.Struct({ id: Schema.String, - path: V2ThreadMetadataUpdateResponse__AbsolutePathBuf, + path: V2ThreadMetadataUpdateResponse__LegacyAppPathString, type: Schema.Literal("imageView").annotate({ title: "ImageViewThreadItemType" }), }).annotate({ title: "ImageViewThreadItem" }), + Schema.Struct({ + durationMs: Schema.Number.annotate({ format: "uint64" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(0)), + id: Schema.String, + type: Schema.Literal("sleep").annotate({ title: "SleepThreadItemType" }), + }).annotate({ + title: "SleepThreadItem", + description: "Display item emitted by the interruptible `clock.sleep` tool.", + }), Schema.Struct({ id: Schema.String, result: Schema.String, @@ -22042,6 +24138,7 @@ export type V2ThreadReadResponse__ThreadItem = readonly type: "fileChange"; } | { + readonly appContext?: V2ThreadReadResponse__McpToolCallAppContext | null; readonly arguments: unknown; readonly durationMs?: number | null; readonly error?: V2ThreadReadResponse__McpToolCallError | null; @@ -22088,13 +24185,15 @@ export type V2ThreadReadResponse__ThreadItem = readonly action?: V2ThreadReadResponse__WebSearchAction | null; readonly id: string; readonly query: string; + readonly results?: ReadonlyArray | null; readonly type: "webSearch"; } | { readonly id: string; - readonly path: V2ThreadReadResponse__AbsolutePathBuf; + readonly path: V2ThreadReadResponse__LegacyAppPathString; readonly type: "imageView"; } + | { readonly durationMs: number; readonly id: string; readonly type: "sleep" } | { readonly id: string; readonly result: string; @@ -22157,10 +24256,7 @@ export const V2ThreadReadResponse__ThreadItem = Schema.Union( description: "A best-effort parsing of the command to understand the action(s) it will perform. This returns a list of CommandAction objects because a single shell command may be composed of many commands piped together.", }), - cwd: Schema.String.annotate({ - description: - "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", - }), + cwd: Schema.String.annotate({ description: "The command's working directory." }), durationMs: Schema.optionalKey( Schema.Union([ Schema.Number.annotate({ @@ -22208,6 +24304,9 @@ export const V2ThreadReadResponse__ThreadItem = Schema.Union( type: Schema.Literal("fileChange").annotate({ title: "FileChangeThreadItemType" }), }).annotate({ title: "FileChangeThreadItem" }), Schema.Struct({ + appContext: Schema.optionalKey( + Schema.Union([V2ThreadReadResponse__McpToolCallAppContext, Schema.Null]), + ), arguments: Schema.Unknown, durationMs: Schema.optionalKey( Schema.Union([ @@ -22222,7 +24321,14 @@ export const V2ThreadReadResponse__ThreadItem = Schema.Union( Schema.Union([V2ThreadReadResponse__McpToolCallError, Schema.Null]), ), id: Schema.String, - mcpAppResourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + mcpAppResourceUri: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Deprecated: use `appContext.resourceUri` instead.", + }), + Schema.Null, + ]), + ), pluginId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), result: Schema.optionalKey( Schema.Union([V2ThreadReadResponse__McpToolCallResult, Schema.Null]), @@ -22318,13 +24424,32 @@ export const V2ThreadReadResponse__ThreadItem = Schema.Union( ), id: Schema.String, query: Schema.String, + results: Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Unknown).annotate({ + description: + "Structured search results returned out-of-band by standalone web search.\n\nThese stay as opaque JSON at the extension/app-server boundary so new result fields and result types can pass through without a Codex release.", + }), + Schema.Null, + ]), + ), type: Schema.Literal("webSearch").annotate({ title: "WebSearchThreadItemType" }), }).annotate({ title: "WebSearchThreadItem" }), Schema.Struct({ id: Schema.String, - path: V2ThreadReadResponse__AbsolutePathBuf, + path: V2ThreadReadResponse__LegacyAppPathString, type: Schema.Literal("imageView").annotate({ title: "ImageViewThreadItemType" }), }).annotate({ title: "ImageViewThreadItem" }), + Schema.Struct({ + durationMs: Schema.Number.annotate({ format: "uint64" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(0)), + id: Schema.String, + type: Schema.Literal("sleep").annotate({ title: "SleepThreadItemType" }), + }).annotate({ + title: "SleepThreadItem", + description: "Display item emitted by the interruptible `clock.sleep` tool.", + }), Schema.Struct({ id: Schema.String, result: Schema.String, @@ -22426,6 +24551,7 @@ export type V2ThreadResumeResponse__ThreadItem = readonly type: "fileChange"; } | { + readonly appContext?: V2ThreadResumeResponse__McpToolCallAppContext | null; readonly arguments: unknown; readonly durationMs?: number | null; readonly error?: V2ThreadResumeResponse__McpToolCallError | null; @@ -22472,13 +24598,15 @@ export type V2ThreadResumeResponse__ThreadItem = readonly action?: V2ThreadResumeResponse__WebSearchAction | null; readonly id: string; readonly query: string; + readonly results?: ReadonlyArray | null; readonly type: "webSearch"; } | { readonly id: string; - readonly path: V2ThreadResumeResponse__AbsolutePathBuf; + readonly path: V2ThreadResumeResponse__LegacyAppPathString; readonly type: "imageView"; } + | { readonly durationMs: number; readonly id: string; readonly type: "sleep" } | { readonly id: string; readonly result: string; @@ -22541,10 +24669,7 @@ export const V2ThreadResumeResponse__ThreadItem = Schema.Union( description: "A best-effort parsing of the command to understand the action(s) it will perform. This returns a list of CommandAction objects because a single shell command may be composed of many commands piped together.", }), - cwd: Schema.String.annotate({ - description: - "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", - }), + cwd: Schema.String.annotate({ description: "The command's working directory." }), durationMs: Schema.optionalKey( Schema.Union([ Schema.Number.annotate({ @@ -22592,6 +24717,9 @@ export const V2ThreadResumeResponse__ThreadItem = Schema.Union( type: Schema.Literal("fileChange").annotate({ title: "FileChangeThreadItemType" }), }).annotate({ title: "FileChangeThreadItem" }), Schema.Struct({ + appContext: Schema.optionalKey( + Schema.Union([V2ThreadResumeResponse__McpToolCallAppContext, Schema.Null]), + ), arguments: Schema.Unknown, durationMs: Schema.optionalKey( Schema.Union([ @@ -22606,7 +24734,14 @@ export const V2ThreadResumeResponse__ThreadItem = Schema.Union( Schema.Union([V2ThreadResumeResponse__McpToolCallError, Schema.Null]), ), id: Schema.String, - mcpAppResourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + mcpAppResourceUri: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Deprecated: use `appContext.resourceUri` instead.", + }), + Schema.Null, + ]), + ), pluginId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), result: Schema.optionalKey( Schema.Union([V2ThreadResumeResponse__McpToolCallResult, Schema.Null]), @@ -22702,13 +24837,32 @@ export const V2ThreadResumeResponse__ThreadItem = Schema.Union( ), id: Schema.String, query: Schema.String, + results: Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Unknown).annotate({ + description: + "Structured search results returned out-of-band by standalone web search.\n\nThese stay as opaque JSON at the extension/app-server boundary so new result fields and result types can pass through without a Codex release.", + }), + Schema.Null, + ]), + ), type: Schema.Literal("webSearch").annotate({ title: "WebSearchThreadItemType" }), }).annotate({ title: "WebSearchThreadItem" }), Schema.Struct({ id: Schema.String, - path: V2ThreadResumeResponse__AbsolutePathBuf, + path: V2ThreadResumeResponse__LegacyAppPathString, type: Schema.Literal("imageView").annotate({ title: "ImageViewThreadItemType" }), }).annotate({ title: "ImageViewThreadItem" }), + Schema.Struct({ + durationMs: Schema.Number.annotate({ format: "uint64" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(0)), + id: Schema.String, + type: Schema.Literal("sleep").annotate({ title: "SleepThreadItemType" }), + }).annotate({ + title: "SleepThreadItem", + description: "Display item emitted by the interruptible `clock.sleep` tool.", + }), Schema.Struct({ id: Schema.String, result: Schema.String, @@ -22802,6 +24956,7 @@ export type V2ThreadRollbackResponse__ThreadItem = readonly type: "fileChange"; } | { + readonly appContext?: V2ThreadRollbackResponse__McpToolCallAppContext | null; readonly arguments: unknown; readonly durationMs?: number | null; readonly error?: V2ThreadRollbackResponse__McpToolCallError | null; @@ -22848,13 +25003,15 @@ export type V2ThreadRollbackResponse__ThreadItem = readonly action?: V2ThreadRollbackResponse__WebSearchAction | null; readonly id: string; readonly query: string; + readonly results?: ReadonlyArray | null; readonly type: "webSearch"; } | { readonly id: string; - readonly path: V2ThreadRollbackResponse__AbsolutePathBuf; + readonly path: V2ThreadRollbackResponse__LegacyAppPathString; readonly type: "imageView"; } + | { readonly durationMs: number; readonly id: string; readonly type: "sleep" } | { readonly id: string; readonly result: string; @@ -22919,10 +25076,7 @@ export const V2ThreadRollbackResponse__ThreadItem = Schema.Union( description: "A best-effort parsing of the command to understand the action(s) it will perform. This returns a list of CommandAction objects because a single shell command may be composed of many commands piped together.", }), - cwd: Schema.String.annotate({ - description: - "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", - }), + cwd: Schema.String.annotate({ description: "The command's working directory." }), durationMs: Schema.optionalKey( Schema.Union([ Schema.Number.annotate({ @@ -22970,6 +25124,9 @@ export const V2ThreadRollbackResponse__ThreadItem = Schema.Union( type: Schema.Literal("fileChange").annotate({ title: "FileChangeThreadItemType" }), }).annotate({ title: "FileChangeThreadItem" }), Schema.Struct({ + appContext: Schema.optionalKey( + Schema.Union([V2ThreadRollbackResponse__McpToolCallAppContext, Schema.Null]), + ), arguments: Schema.Unknown, durationMs: Schema.optionalKey( Schema.Union([ @@ -22984,7 +25141,14 @@ export const V2ThreadRollbackResponse__ThreadItem = Schema.Union( Schema.Union([V2ThreadRollbackResponse__McpToolCallError, Schema.Null]), ), id: Schema.String, - mcpAppResourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + mcpAppResourceUri: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Deprecated: use `appContext.resourceUri` instead.", + }), + Schema.Null, + ]), + ), pluginId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), result: Schema.optionalKey( Schema.Union([V2ThreadRollbackResponse__McpToolCallResult, Schema.Null]), @@ -23081,13 +25245,32 @@ export const V2ThreadRollbackResponse__ThreadItem = Schema.Union( ), id: Schema.String, query: Schema.String, + results: Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Unknown).annotate({ + description: + "Structured search results returned out-of-band by standalone web search.\n\nThese stay as opaque JSON at the extension/app-server boundary so new result fields and result types can pass through without a Codex release.", + }), + Schema.Null, + ]), + ), type: Schema.Literal("webSearch").annotate({ title: "WebSearchThreadItemType" }), }).annotate({ title: "WebSearchThreadItem" }), Schema.Struct({ id: Schema.String, - path: V2ThreadRollbackResponse__AbsolutePathBuf, + path: V2ThreadRollbackResponse__LegacyAppPathString, type: Schema.Literal("imageView").annotate({ title: "ImageViewThreadItemType" }), }).annotate({ title: "ImageViewThreadItem" }), + Schema.Struct({ + durationMs: Schema.Number.annotate({ format: "uint64" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(0)), + id: Schema.String, + type: Schema.Literal("sleep").annotate({ title: "SleepThreadItemType" }), + }).annotate({ + title: "SleepThreadItem", + description: "Display item emitted by the interruptible `clock.sleep` tool.", + }), Schema.Struct({ id: Schema.String, result: Schema.String, @@ -23190,6 +25373,7 @@ export type V2ThreadStartedNotification__ThreadItem = readonly type: "fileChange"; } | { + readonly appContext?: V2ThreadStartedNotification__McpToolCallAppContext | null; readonly arguments: unknown; readonly durationMs?: number | null; readonly error?: V2ThreadStartedNotification__McpToolCallError | null; @@ -23238,13 +25422,15 @@ export type V2ThreadStartedNotification__ThreadItem = readonly action?: V2ThreadStartedNotification__WebSearchAction | null; readonly id: string; readonly query: string; + readonly results?: ReadonlyArray | null; readonly type: "webSearch"; } | { readonly id: string; - readonly path: V2ThreadStartedNotification__AbsolutePathBuf; + readonly path: V2ThreadStartedNotification__LegacyAppPathString; readonly type: "imageView"; } + | { readonly durationMs: number; readonly id: string; readonly type: "sleep" } | { readonly id: string; readonly result: string; @@ -23309,10 +25495,7 @@ export const V2ThreadStartedNotification__ThreadItem = Schema.Union( description: "A best-effort parsing of the command to understand the action(s) it will perform. This returns a list of CommandAction objects because a single shell command may be composed of many commands piped together.", }), - cwd: Schema.String.annotate({ - description: - "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", - }), + cwd: Schema.String.annotate({ description: "The command's working directory." }), durationMs: Schema.optionalKey( Schema.Union([ Schema.Number.annotate({ @@ -23360,6 +25543,9 @@ export const V2ThreadStartedNotification__ThreadItem = Schema.Union( type: Schema.Literal("fileChange").annotate({ title: "FileChangeThreadItemType" }), }).annotate({ title: "FileChangeThreadItem" }), Schema.Struct({ + appContext: Schema.optionalKey( + Schema.Union([V2ThreadStartedNotification__McpToolCallAppContext, Schema.Null]), + ), arguments: Schema.Unknown, durationMs: Schema.optionalKey( Schema.Union([ @@ -23374,7 +25560,14 @@ export const V2ThreadStartedNotification__ThreadItem = Schema.Union( Schema.Union([V2ThreadStartedNotification__McpToolCallError, Schema.Null]), ), id: Schema.String, - mcpAppResourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + mcpAppResourceUri: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Deprecated: use `appContext.resourceUri` instead.", + }), + Schema.Null, + ]), + ), pluginId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), result: Schema.optionalKey( Schema.Union([V2ThreadStartedNotification__McpToolCallResult, Schema.Null]), @@ -23471,13 +25664,32 @@ export const V2ThreadStartedNotification__ThreadItem = Schema.Union( ), id: Schema.String, query: Schema.String, + results: Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Unknown).annotate({ + description: + "Structured search results returned out-of-band by standalone web search.\n\nThese stay as opaque JSON at the extension/app-server boundary so new result fields and result types can pass through without a Codex release.", + }), + Schema.Null, + ]), + ), type: Schema.Literal("webSearch").annotate({ title: "WebSearchThreadItemType" }), }).annotate({ title: "WebSearchThreadItem" }), Schema.Struct({ id: Schema.String, - path: V2ThreadStartedNotification__AbsolutePathBuf, + path: V2ThreadStartedNotification__LegacyAppPathString, type: Schema.Literal("imageView").annotate({ title: "ImageViewThreadItemType" }), }).annotate({ title: "ImageViewThreadItem" }), + Schema.Struct({ + durationMs: Schema.Number.annotate({ format: "uint64" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(0)), + id: Schema.String, + type: Schema.Literal("sleep").annotate({ title: "SleepThreadItemType" }), + }).annotate({ + title: "SleepThreadItem", + description: "Display item emitted by the interruptible `clock.sleep` tool.", + }), Schema.Struct({ id: Schema.String, result: Schema.String, @@ -23571,6 +25783,7 @@ export type V2ThreadStartResponse__ThreadItem = readonly type: "fileChange"; } | { + readonly appContext?: V2ThreadStartResponse__McpToolCallAppContext | null; readonly arguments: unknown; readonly durationMs?: number | null; readonly error?: V2ThreadStartResponse__McpToolCallError | null; @@ -23617,13 +25830,15 @@ export type V2ThreadStartResponse__ThreadItem = readonly action?: V2ThreadStartResponse__WebSearchAction | null; readonly id: string; readonly query: string; + readonly results?: ReadonlyArray | null; readonly type: "webSearch"; } | { readonly id: string; - readonly path: V2ThreadStartResponse__AbsolutePathBuf; + readonly path: V2ThreadStartResponse__LegacyAppPathString; readonly type: "imageView"; } + | { readonly durationMs: number; readonly id: string; readonly type: "sleep" } | { readonly id: string; readonly result: string; @@ -23686,10 +25901,7 @@ export const V2ThreadStartResponse__ThreadItem = Schema.Union( description: "A best-effort parsing of the command to understand the action(s) it will perform. This returns a list of CommandAction objects because a single shell command may be composed of many commands piped together.", }), - cwd: Schema.String.annotate({ - description: - "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", - }), + cwd: Schema.String.annotate({ description: "The command's working directory." }), durationMs: Schema.optionalKey( Schema.Union([ Schema.Number.annotate({ @@ -23737,6 +25949,9 @@ export const V2ThreadStartResponse__ThreadItem = Schema.Union( type: Schema.Literal("fileChange").annotate({ title: "FileChangeThreadItemType" }), }).annotate({ title: "FileChangeThreadItem" }), Schema.Struct({ + appContext: Schema.optionalKey( + Schema.Union([V2ThreadStartResponse__McpToolCallAppContext, Schema.Null]), + ), arguments: Schema.Unknown, durationMs: Schema.optionalKey( Schema.Union([ @@ -23751,7 +25966,14 @@ export const V2ThreadStartResponse__ThreadItem = Schema.Union( Schema.Union([V2ThreadStartResponse__McpToolCallError, Schema.Null]), ), id: Schema.String, - mcpAppResourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + mcpAppResourceUri: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Deprecated: use `appContext.resourceUri` instead.", + }), + Schema.Null, + ]), + ), pluginId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), result: Schema.optionalKey( Schema.Union([V2ThreadStartResponse__McpToolCallResult, Schema.Null]), @@ -23847,13 +26069,32 @@ export const V2ThreadStartResponse__ThreadItem = Schema.Union( ), id: Schema.String, query: Schema.String, + results: Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Unknown).annotate({ + description: + "Structured search results returned out-of-band by standalone web search.\n\nThese stay as opaque JSON at the extension/app-server boundary so new result fields and result types can pass through without a Codex release.", + }), + Schema.Null, + ]), + ), type: Schema.Literal("webSearch").annotate({ title: "WebSearchThreadItemType" }), }).annotate({ title: "WebSearchThreadItem" }), Schema.Struct({ id: Schema.String, - path: V2ThreadStartResponse__AbsolutePathBuf, + path: V2ThreadStartResponse__LegacyAppPathString, type: Schema.Literal("imageView").annotate({ title: "ImageViewThreadItemType" }), }).annotate({ title: "ImageViewThreadItem" }), + Schema.Struct({ + durationMs: Schema.Number.annotate({ format: "uint64" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(0)), + id: Schema.String, + type: Schema.Literal("sleep").annotate({ title: "SleepThreadItemType" }), + }).annotate({ + title: "SleepThreadItem", + description: "Display item emitted by the interruptible `clock.sleep` tool.", + }), Schema.Struct({ id: Schema.String, result: Schema.String, @@ -23947,6 +26188,7 @@ export type V2ThreadUnarchiveResponse__ThreadItem = readonly type: "fileChange"; } | { + readonly appContext?: V2ThreadUnarchiveResponse__McpToolCallAppContext | null; readonly arguments: unknown; readonly durationMs?: number | null; readonly error?: V2ThreadUnarchiveResponse__McpToolCallError | null; @@ -23993,13 +26235,15 @@ export type V2ThreadUnarchiveResponse__ThreadItem = readonly action?: V2ThreadUnarchiveResponse__WebSearchAction | null; readonly id: string; readonly query: string; + readonly results?: ReadonlyArray | null; readonly type: "webSearch"; } | { readonly id: string; - readonly path: V2ThreadUnarchiveResponse__AbsolutePathBuf; + readonly path: V2ThreadUnarchiveResponse__LegacyAppPathString; readonly type: "imageView"; } + | { readonly durationMs: number; readonly id: string; readonly type: "sleep" } | { readonly id: string; readonly result: string; @@ -24064,10 +26308,7 @@ export const V2ThreadUnarchiveResponse__ThreadItem = Schema.Union( description: "A best-effort parsing of the command to understand the action(s) it will perform. This returns a list of CommandAction objects because a single shell command may be composed of many commands piped together.", }), - cwd: Schema.String.annotate({ - description: - "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", - }), + cwd: Schema.String.annotate({ description: "The command's working directory." }), durationMs: Schema.optionalKey( Schema.Union([ Schema.Number.annotate({ @@ -24115,6 +26356,9 @@ export const V2ThreadUnarchiveResponse__ThreadItem = Schema.Union( type: Schema.Literal("fileChange").annotate({ title: "FileChangeThreadItemType" }), }).annotate({ title: "FileChangeThreadItem" }), Schema.Struct({ + appContext: Schema.optionalKey( + Schema.Union([V2ThreadUnarchiveResponse__McpToolCallAppContext, Schema.Null]), + ), arguments: Schema.Unknown, durationMs: Schema.optionalKey( Schema.Union([ @@ -24129,7 +26373,14 @@ export const V2ThreadUnarchiveResponse__ThreadItem = Schema.Union( Schema.Union([V2ThreadUnarchiveResponse__McpToolCallError, Schema.Null]), ), id: Schema.String, - mcpAppResourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + mcpAppResourceUri: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Deprecated: use `appContext.resourceUri` instead.", + }), + Schema.Null, + ]), + ), pluginId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), result: Schema.optionalKey( Schema.Union([V2ThreadUnarchiveResponse__McpToolCallResult, Schema.Null]), @@ -24226,13 +26477,32 @@ export const V2ThreadUnarchiveResponse__ThreadItem = Schema.Union( ), id: Schema.String, query: Schema.String, + results: Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Unknown).annotate({ + description: + "Structured search results returned out-of-band by standalone web search.\n\nThese stay as opaque JSON at the extension/app-server boundary so new result fields and result types can pass through without a Codex release.", + }), + Schema.Null, + ]), + ), type: Schema.Literal("webSearch").annotate({ title: "WebSearchThreadItemType" }), }).annotate({ title: "WebSearchThreadItem" }), Schema.Struct({ id: Schema.String, - path: V2ThreadUnarchiveResponse__AbsolutePathBuf, + path: V2ThreadUnarchiveResponse__LegacyAppPathString, type: Schema.Literal("imageView").annotate({ title: "ImageViewThreadItemType" }), }).annotate({ title: "ImageViewThreadItem" }), + Schema.Struct({ + durationMs: Schema.Number.annotate({ format: "uint64" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(0)), + id: Schema.String, + type: Schema.Literal("sleep").annotate({ title: "SleepThreadItemType" }), + }).annotate({ + title: "SleepThreadItem", + description: "Display item emitted by the interruptible `clock.sleep` tool.", + }), Schema.Struct({ id: Schema.String, result: Schema.String, @@ -24326,6 +26596,7 @@ export type V2TurnCompletedNotification__ThreadItem = readonly type: "fileChange"; } | { + readonly appContext?: V2TurnCompletedNotification__McpToolCallAppContext | null; readonly arguments: unknown; readonly durationMs?: number | null; readonly error?: V2TurnCompletedNotification__McpToolCallError | null; @@ -24374,13 +26645,15 @@ export type V2TurnCompletedNotification__ThreadItem = readonly action?: V2TurnCompletedNotification__WebSearchAction | null; readonly id: string; readonly query: string; + readonly results?: ReadonlyArray | null; readonly type: "webSearch"; } | { readonly id: string; - readonly path: V2TurnCompletedNotification__AbsolutePathBuf; + readonly path: V2TurnCompletedNotification__LegacyAppPathString; readonly type: "imageView"; } + | { readonly durationMs: number; readonly id: string; readonly type: "sleep" } | { readonly id: string; readonly result: string; @@ -24445,10 +26718,7 @@ export const V2TurnCompletedNotification__ThreadItem = Schema.Union( description: "A best-effort parsing of the command to understand the action(s) it will perform. This returns a list of CommandAction objects because a single shell command may be composed of many commands piped together.", }), - cwd: Schema.String.annotate({ - description: - "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", - }), + cwd: Schema.String.annotate({ description: "The command's working directory." }), durationMs: Schema.optionalKey( Schema.Union([ Schema.Number.annotate({ @@ -24496,6 +26766,9 @@ export const V2TurnCompletedNotification__ThreadItem = Schema.Union( type: Schema.Literal("fileChange").annotate({ title: "FileChangeThreadItemType" }), }).annotate({ title: "FileChangeThreadItem" }), Schema.Struct({ + appContext: Schema.optionalKey( + Schema.Union([V2TurnCompletedNotification__McpToolCallAppContext, Schema.Null]), + ), arguments: Schema.Unknown, durationMs: Schema.optionalKey( Schema.Union([ @@ -24510,7 +26783,14 @@ export const V2TurnCompletedNotification__ThreadItem = Schema.Union( Schema.Union([V2TurnCompletedNotification__McpToolCallError, Schema.Null]), ), id: Schema.String, - mcpAppResourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + mcpAppResourceUri: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Deprecated: use `appContext.resourceUri` instead.", + }), + Schema.Null, + ]), + ), pluginId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), result: Schema.optionalKey( Schema.Union([V2TurnCompletedNotification__McpToolCallResult, Schema.Null]), @@ -24607,13 +26887,32 @@ export const V2TurnCompletedNotification__ThreadItem = Schema.Union( ), id: Schema.String, query: Schema.String, + results: Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Unknown).annotate({ + description: + "Structured search results returned out-of-band by standalone web search.\n\nThese stay as opaque JSON at the extension/app-server boundary so new result fields and result types can pass through without a Codex release.", + }), + Schema.Null, + ]), + ), type: Schema.Literal("webSearch").annotate({ title: "WebSearchThreadItemType" }), }).annotate({ title: "WebSearchThreadItem" }), Schema.Struct({ id: Schema.String, - path: V2TurnCompletedNotification__AbsolutePathBuf, + path: V2TurnCompletedNotification__LegacyAppPathString, type: Schema.Literal("imageView").annotate({ title: "ImageViewThreadItemType" }), }).annotate({ title: "ImageViewThreadItem" }), + Schema.Struct({ + durationMs: Schema.Number.annotate({ format: "uint64" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(0)), + id: Schema.String, + type: Schema.Literal("sleep").annotate({ title: "SleepThreadItemType" }), + }).annotate({ + title: "SleepThreadItem", + description: "Display item emitted by the interruptible `clock.sleep` tool.", + }), Schema.Struct({ id: Schema.String, result: Schema.String, @@ -24707,6 +27006,7 @@ export type V2TurnStartedNotification__ThreadItem = readonly type: "fileChange"; } | { + readonly appContext?: V2TurnStartedNotification__McpToolCallAppContext | null; readonly arguments: unknown; readonly durationMs?: number | null; readonly error?: V2TurnStartedNotification__McpToolCallError | null; @@ -24753,13 +27053,15 @@ export type V2TurnStartedNotification__ThreadItem = readonly action?: V2TurnStartedNotification__WebSearchAction | null; readonly id: string; readonly query: string; + readonly results?: ReadonlyArray | null; readonly type: "webSearch"; } | { readonly id: string; - readonly path: V2TurnStartedNotification__AbsolutePathBuf; + readonly path: V2TurnStartedNotification__LegacyAppPathString; readonly type: "imageView"; } + | { readonly durationMs: number; readonly id: string; readonly type: "sleep" } | { readonly id: string; readonly result: string; @@ -24824,10 +27126,7 @@ export const V2TurnStartedNotification__ThreadItem = Schema.Union( description: "A best-effort parsing of the command to understand the action(s) it will perform. This returns a list of CommandAction objects because a single shell command may be composed of many commands piped together.", }), - cwd: Schema.String.annotate({ - description: - "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", - }), + cwd: Schema.String.annotate({ description: "The command's working directory." }), durationMs: Schema.optionalKey( Schema.Union([ Schema.Number.annotate({ @@ -24875,6 +27174,9 @@ export const V2TurnStartedNotification__ThreadItem = Schema.Union( type: Schema.Literal("fileChange").annotate({ title: "FileChangeThreadItemType" }), }).annotate({ title: "FileChangeThreadItem" }), Schema.Struct({ + appContext: Schema.optionalKey( + Schema.Union([V2TurnStartedNotification__McpToolCallAppContext, Schema.Null]), + ), arguments: Schema.Unknown, durationMs: Schema.optionalKey( Schema.Union([ @@ -24889,7 +27191,14 @@ export const V2TurnStartedNotification__ThreadItem = Schema.Union( Schema.Union([V2TurnStartedNotification__McpToolCallError, Schema.Null]), ), id: Schema.String, - mcpAppResourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + mcpAppResourceUri: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Deprecated: use `appContext.resourceUri` instead.", + }), + Schema.Null, + ]), + ), pluginId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), result: Schema.optionalKey( Schema.Union([V2TurnStartedNotification__McpToolCallResult, Schema.Null]), @@ -24986,13 +27295,32 @@ export const V2TurnStartedNotification__ThreadItem = Schema.Union( ), id: Schema.String, query: Schema.String, + results: Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Unknown).annotate({ + description: + "Structured search results returned out-of-band by standalone web search.\n\nThese stay as opaque JSON at the extension/app-server boundary so new result fields and result types can pass through without a Codex release.", + }), + Schema.Null, + ]), + ), type: Schema.Literal("webSearch").annotate({ title: "WebSearchThreadItemType" }), }).annotate({ title: "WebSearchThreadItem" }), Schema.Struct({ id: Schema.String, - path: V2TurnStartedNotification__AbsolutePathBuf, + path: V2TurnStartedNotification__LegacyAppPathString, type: Schema.Literal("imageView").annotate({ title: "ImageViewThreadItemType" }), }).annotate({ title: "ImageViewThreadItem" }), + Schema.Struct({ + durationMs: Schema.Number.annotate({ format: "uint64" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(0)), + id: Schema.String, + type: Schema.Literal("sleep").annotate({ title: "SleepThreadItemType" }), + }).annotate({ + title: "SleepThreadItem", + description: "Display item emitted by the interruptible `clock.sleep` tool.", + }), Schema.Struct({ id: Schema.String, result: Schema.String, @@ -25086,6 +27414,7 @@ export type V2TurnStartResponse__ThreadItem = readonly type: "fileChange"; } | { + readonly appContext?: V2TurnStartResponse__McpToolCallAppContext | null; readonly arguments: unknown; readonly durationMs?: number | null; readonly error?: V2TurnStartResponse__McpToolCallError | null; @@ -25132,13 +27461,15 @@ export type V2TurnStartResponse__ThreadItem = readonly action?: V2TurnStartResponse__WebSearchAction | null; readonly id: string; readonly query: string; + readonly results?: ReadonlyArray | null; readonly type: "webSearch"; } | { readonly id: string; - readonly path: V2TurnStartResponse__AbsolutePathBuf; + readonly path: V2TurnStartResponse__LegacyAppPathString; readonly type: "imageView"; } + | { readonly durationMs: number; readonly id: string; readonly type: "sleep" } | { readonly id: string; readonly result: string; @@ -25201,10 +27532,7 @@ export const V2TurnStartResponse__ThreadItem = Schema.Union( description: "A best-effort parsing of the command to understand the action(s) it will perform. This returns a list of CommandAction objects because a single shell command may be composed of many commands piped together.", }), - cwd: Schema.String.annotate({ - description: - "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", - }), + cwd: Schema.String.annotate({ description: "The command's working directory." }), durationMs: Schema.optionalKey( Schema.Union([ Schema.Number.annotate({ @@ -25252,6 +27580,9 @@ export const V2TurnStartResponse__ThreadItem = Schema.Union( type: Schema.Literal("fileChange").annotate({ title: "FileChangeThreadItemType" }), }).annotate({ title: "FileChangeThreadItem" }), Schema.Struct({ + appContext: Schema.optionalKey( + Schema.Union([V2TurnStartResponse__McpToolCallAppContext, Schema.Null]), + ), arguments: Schema.Unknown, durationMs: Schema.optionalKey( Schema.Union([ @@ -25264,7 +27595,14 @@ export const V2TurnStartResponse__ThreadItem = Schema.Union( ), error: Schema.optionalKey(Schema.Union([V2TurnStartResponse__McpToolCallError, Schema.Null])), id: Schema.String, - mcpAppResourceUri: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + mcpAppResourceUri: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Deprecated: use `appContext.resourceUri` instead.", + }), + Schema.Null, + ]), + ), pluginId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), result: Schema.optionalKey( Schema.Union([V2TurnStartResponse__McpToolCallResult, Schema.Null]), @@ -25358,13 +27696,32 @@ export const V2TurnStartResponse__ThreadItem = Schema.Union( action: Schema.optionalKey(Schema.Union([V2TurnStartResponse__WebSearchAction, Schema.Null])), id: Schema.String, query: Schema.String, + results: Schema.optionalKey( + Schema.Union([ + Schema.Array(Schema.Unknown).annotate({ + description: + "Structured search results returned out-of-band by standalone web search.\n\nThese stay as opaque JSON at the extension/app-server boundary so new result fields and result types can pass through without a Codex release.", + }), + Schema.Null, + ]), + ), type: Schema.Literal("webSearch").annotate({ title: "WebSearchThreadItemType" }), }).annotate({ title: "WebSearchThreadItem" }), Schema.Struct({ id: Schema.String, - path: V2TurnStartResponse__AbsolutePathBuf, + path: V2TurnStartResponse__LegacyAppPathString, type: Schema.Literal("imageView").annotate({ title: "ImageViewThreadItemType" }), }).annotate({ title: "ImageViewThreadItem" }), + Schema.Struct({ + durationMs: Schema.Number.annotate({ format: "uint64" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(0)), + id: Schema.String, + type: Schema.Literal("sleep").annotate({ title: "SleepThreadItemType" }), + }).annotate({ + title: "SleepThreadItem", + description: "Display item emitted by the interruptible `clock.sleep` tool.", + }), Schema.Struct({ id: Schema.String, result: Schema.String, @@ -25401,51 +27758,38 @@ export const V2TurnStartResponse__ThreadItem = Schema.Union( export type ClientRequest__ExternalAgentConfigImportParams = { readonly migrationItems: ReadonlyArray; + readonly migrationSource?: string | null; + readonly source?: string | null; }; export const ClientRequest__ExternalAgentConfigImportParams = Schema.Struct({ migrationItems: Schema.Array(ClientRequest__ExternalAgentConfigMigrationItem), + migrationSource: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: + "Migration-source selector used to produce the migration items. Pass the same value to detection and import; missing or unrecognized values use the default source.", + }), + Schema.Null, + ]), + ), + source: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Optional identifier for the product that initiated the import.", + }), + Schema.Null, + ]), + ), }); -export type CommandExecutionRequestApprovalParams__AdditionalFileSystemPermissions = { - readonly entries?: ReadonlyArray | null; - readonly globScanMaxDepth?: number | null; - readonly read?: ReadonlyArray | null; - readonly write?: ReadonlyArray | null; +export type CommandExecutionRequestApprovalParams__FileSystemSandboxEntry = { + readonly access: CommandExecutionRequestApprovalParams__FileSystemAccessMode; + readonly path: CommandExecutionRequestApprovalParams__FileSystemPath; }; -export const CommandExecutionRequestApprovalParams__AdditionalFileSystemPermissions = Schema.Struct( - { - entries: Schema.optionalKey( - Schema.Union([ - Schema.Array(CommandExecutionRequestApprovalParams__FileSystemSandboxEntry), - Schema.Null, - ]), - ), - globScanMaxDepth: Schema.optionalKey( - Schema.Union([ - Schema.Number.annotate({ format: "uint" }) - .check(Schema.isInt()) - .check(Schema.isGreaterThanOrEqualTo(1)), - Schema.Null, - ]), - ), - read: Schema.optionalKey( - Schema.Union([ - Schema.Array(CommandExecutionRequestApprovalParams__AbsolutePathBuf).annotate({ - description: "This will be removed in favor of `entries`.", - }), - Schema.Null, - ]), - ), - write: Schema.optionalKey( - Schema.Union([ - Schema.Array(CommandExecutionRequestApprovalParams__AbsolutePathBuf).annotate({ - description: "This will be removed in favor of `entries`.", - }), - Schema.Null, - ]), - ), - }, -); +export const CommandExecutionRequestApprovalParams__FileSystemSandboxEntry = Schema.Struct({ + access: CommandExecutionRequestApprovalParams__FileSystemAccessMode, + path: CommandExecutionRequestApprovalParams__FileSystemPath, +}); export type McpServerElicitationRequestParams__McpElicitationMultiSelectEnumSchema = | McpServerElicitationRequestParams__McpElicitationUntitledMultiSelectEnumSchema @@ -25455,82 +27799,22 @@ export const McpServerElicitationRequestParams__McpElicitationMultiSelectEnumSch McpServerElicitationRequestParams__McpElicitationTitledMultiSelectEnumSchema, ]); -export type PermissionsRequestApprovalParams__AdditionalFileSystemPermissions = { - readonly entries?: ReadonlyArray | null; - readonly globScanMaxDepth?: number | null; - readonly read?: ReadonlyArray | null; - readonly write?: ReadonlyArray | null; +export type PermissionsRequestApprovalParams__FileSystemSandboxEntry = { + readonly access: PermissionsRequestApprovalParams__FileSystemAccessMode; + readonly path: PermissionsRequestApprovalParams__FileSystemPath; }; -export const PermissionsRequestApprovalParams__AdditionalFileSystemPermissions = Schema.Struct({ - entries: Schema.optionalKey( - Schema.Union([ - Schema.Array(PermissionsRequestApprovalParams__FileSystemSandboxEntry), - Schema.Null, - ]), - ), - globScanMaxDepth: Schema.optionalKey( - Schema.Union([ - Schema.Number.annotate({ format: "uint" }) - .check(Schema.isInt()) - .check(Schema.isGreaterThanOrEqualTo(1)), - Schema.Null, - ]), - ), - read: Schema.optionalKey( - Schema.Union([ - Schema.Array(PermissionsRequestApprovalParams__AbsolutePathBuf).annotate({ - description: "This will be removed in favor of `entries`.", - }), - Schema.Null, - ]), - ), - write: Schema.optionalKey( - Schema.Union([ - Schema.Array(PermissionsRequestApprovalParams__AbsolutePathBuf).annotate({ - description: "This will be removed in favor of `entries`.", - }), - Schema.Null, - ]), - ), +export const PermissionsRequestApprovalParams__FileSystemSandboxEntry = Schema.Struct({ + access: PermissionsRequestApprovalParams__FileSystemAccessMode, + path: PermissionsRequestApprovalParams__FileSystemPath, }); -export type PermissionsRequestApprovalResponse__AdditionalFileSystemPermissions = { - readonly entries?: ReadonlyArray | null; - readonly globScanMaxDepth?: number | null; - readonly read?: ReadonlyArray | null; - readonly write?: ReadonlyArray | null; +export type PermissionsRequestApprovalResponse__FileSystemSandboxEntry = { + readonly access: PermissionsRequestApprovalResponse__FileSystemAccessMode; + readonly path: PermissionsRequestApprovalResponse__FileSystemPath; }; -export const PermissionsRequestApprovalResponse__AdditionalFileSystemPermissions = Schema.Struct({ - entries: Schema.optionalKey( - Schema.Union([ - Schema.Array(PermissionsRequestApprovalResponse__FileSystemSandboxEntry), - Schema.Null, - ]), - ), - globScanMaxDepth: Schema.optionalKey( - Schema.Union([ - Schema.Number.annotate({ format: "uint" }) - .check(Schema.isInt()) - .check(Schema.isGreaterThanOrEqualTo(1)), - Schema.Null, - ]), - ), - read: Schema.optionalKey( - Schema.Union([ - Schema.Array(PermissionsRequestApprovalResponse__AbsolutePathBuf).annotate({ - description: "This will be removed in favor of `entries`.", - }), - Schema.Null, - ]), - ), - write: Schema.optionalKey( - Schema.Union([ - Schema.Array(PermissionsRequestApprovalResponse__AbsolutePathBuf).annotate({ - description: "This will be removed in favor of `entries`.", - }), - Schema.Null, - ]), - ), +export const PermissionsRequestApprovalResponse__FileSystemSandboxEntry = Schema.Struct({ + access: PermissionsRequestApprovalResponse__FileSystemAccessMode, + path: PermissionsRequestApprovalResponse__FileSystemPath, }); export type ServerNotification__AppListUpdatedNotification = { @@ -25540,40 +27824,22 @@ export const ServerNotification__AppListUpdatedNotification = Schema.Struct({ data: Schema.Array(ServerNotification__AppInfo), }).annotate({ description: "EXPERIMENTAL - notification emitted when the app list changes." }); -export type ServerNotification__AdditionalFileSystemPermissions = { - readonly entries?: ReadonlyArray | null; - readonly globScanMaxDepth?: number | null; - readonly read?: ReadonlyArray | null; - readonly write?: ReadonlyArray | null; +export type ServerNotification__ExternalAgentConfigImportCompletedNotification = { + readonly importId: string; + readonly itemTypeResults: ReadonlyArray; }; -export const ServerNotification__AdditionalFileSystemPermissions = Schema.Struct({ - entries: Schema.optionalKey( - Schema.Union([Schema.Array(ServerNotification__FileSystemSandboxEntry), Schema.Null]), - ), - globScanMaxDepth: Schema.optionalKey( - Schema.Union([ - Schema.Number.annotate({ format: "uint" }) - .check(Schema.isInt()) - .check(Schema.isGreaterThanOrEqualTo(1)), - Schema.Null, - ]), - ), - read: Schema.optionalKey( - Schema.Union([ - Schema.Array(ServerNotification__AbsolutePathBuf).annotate({ - description: "This will be removed in favor of `entries`.", - }), - Schema.Null, - ]), - ), - write: Schema.optionalKey( - Schema.Union([ - Schema.Array(ServerNotification__AbsolutePathBuf).annotate({ - description: "This will be removed in favor of `entries`.", - }), - Schema.Null, - ]), - ), +export const ServerNotification__ExternalAgentConfigImportCompletedNotification = Schema.Struct({ + importId: Schema.String, + itemTypeResults: Schema.Array(ServerNotification__ExternalAgentConfigImportTypeResult), +}); + +export type ServerNotification__ExternalAgentConfigImportProgressNotification = { + readonly importId: string; + readonly itemTypeResults: ReadonlyArray; +}; +export const ServerNotification__ExternalAgentConfigImportProgressNotification = Schema.Struct({ + importId: Schema.String, + itemTypeResults: Schema.Array(ServerNotification__ExternalAgentConfigImportTypeResult), }); export type ServerNotification__HookCompletedNotification = { @@ -25598,6 +27864,15 @@ export const ServerNotification__HookStartedNotification = Schema.Struct({ turnId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), }); +export type ServerNotification__FileSystemSandboxEntry = { + readonly access: ServerNotification__FileSystemAccessMode; + readonly path: ServerNotification__FileSystemPath; +}; +export const ServerNotification__FileSystemSandboxEntry = Schema.Struct({ + access: ServerNotification__FileSystemAccessMode, + path: ServerNotification__FileSystemPath, +}); + export type ServerNotification__ErrorNotification = { readonly error: ServerNotification__TurnError; readonly threadId: string; @@ -25708,7 +27983,9 @@ export const ServerNotification__Turn = Schema.Struct({ description: "Only populated when the Turn's status is failed.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this turn. Codex-generated turn IDs are UUIDv7.", + }), items: Schema.Array(ServerNotification__ThreadItem).annotate({ description: "Thread items currently included in this turn payload.", }), @@ -25730,40 +28007,13 @@ export const ServerNotification__Turn = Schema.Struct({ status: ServerNotification__TurnStatus, }); -export type ServerRequest__AdditionalFileSystemPermissions = { - readonly entries?: ReadonlyArray | null; - readonly globScanMaxDepth?: number | null; - readonly read?: ReadonlyArray | null; - readonly write?: ReadonlyArray | null; +export type ServerRequest__FileSystemSandboxEntry = { + readonly access: ServerRequest__FileSystemAccessMode; + readonly path: ServerRequest__FileSystemPath; }; -export const ServerRequest__AdditionalFileSystemPermissions = Schema.Struct({ - entries: Schema.optionalKey( - Schema.Union([Schema.Array(ServerRequest__FileSystemSandboxEntry), Schema.Null]), - ), - globScanMaxDepth: Schema.optionalKey( - Schema.Union([ - Schema.Number.annotate({ format: "uint" }) - .check(Schema.isInt()) - .check(Schema.isGreaterThanOrEqualTo(1)), - Schema.Null, - ]), - ), - read: Schema.optionalKey( - Schema.Union([ - Schema.Array(ServerRequest__AbsolutePathBuf).annotate({ - description: "This will be removed in favor of `entries`.", - }), - Schema.Null, - ]), - ), - write: Schema.optionalKey( - Schema.Union([ - Schema.Array(ServerRequest__AbsolutePathBuf).annotate({ - description: "This will be removed in favor of `entries`.", - }), - Schema.Null, - ]), - ), +export const ServerRequest__FileSystemSandboxEntry = Schema.Struct({ + access: ServerRequest__FileSystemAccessMode, + path: ServerRequest__FileSystemPath, }); export type ServerRequest__McpElicitationMultiSelectEnumSchema = @@ -25868,6 +28118,58 @@ export const V2ConfigReadResponse__Config = Schema.StructWithRest( [Schema.Record(Schema.String, Schema.Unknown)], ); +export type V2ConfigRequirementsReadResponse__ConfigRequirements = { + readonly allowAppshots?: boolean | null; + readonly allowManagedHooksOnly?: boolean | null; + readonly allowRemoteControl?: boolean | null; + readonly allowedApprovalPolicies?: ReadonlyArray | null; + readonly allowedPermissionProfiles?: { readonly [x: string]: boolean } | null; + readonly allowedSandboxModes?: ReadonlyArray | null; + readonly allowedWebSearchModes?: ReadonlyArray | null; + readonly allowedWindowsSandboxImplementations?: ReadonlyArray | null; + readonly computerUse?: V2ConfigRequirementsReadResponse__ComputerUseRequirements | null; + readonly defaultPermissions?: string | null; + readonly enforceResidency?: V2ConfigRequirementsReadResponse__ResidencyRequirement | null; + readonly featureRequirements?: { readonly [x: string]: boolean } | null; + readonly models?: V2ConfigRequirementsReadResponse__ModelsRequirements | null; +}; +export const V2ConfigRequirementsReadResponse__ConfigRequirements = Schema.Struct({ + allowAppshots: Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), + allowManagedHooksOnly: Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), + allowRemoteControl: Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), + allowedApprovalPolicies: Schema.optionalKey( + Schema.Union([Schema.Array(V2ConfigRequirementsReadResponse__AskForApproval), Schema.Null]), + ), + allowedPermissionProfiles: Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Boolean), Schema.Null]), + ), + allowedSandboxModes: Schema.optionalKey( + Schema.Union([Schema.Array(V2ConfigRequirementsReadResponse__SandboxMode), Schema.Null]), + ), + allowedWebSearchModes: Schema.optionalKey( + Schema.Union([Schema.Array(V2ConfigRequirementsReadResponse__WebSearchMode), Schema.Null]), + ), + allowedWindowsSandboxImplementations: Schema.optionalKey( + Schema.Union([ + Schema.Array(V2ConfigRequirementsReadResponse__WindowsSandboxSetupMode), + Schema.Null, + ]), + ), + computerUse: Schema.optionalKey( + Schema.Union([V2ConfigRequirementsReadResponse__ComputerUseRequirements, Schema.Null]), + ), + defaultPermissions: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + enforceResidency: Schema.optionalKey( + Schema.Union([V2ConfigRequirementsReadResponse__ResidencyRequirement, Schema.Null]), + ), + featureRequirements: Schema.optionalKey( + Schema.Union([Schema.Record(Schema.String, Schema.Boolean), Schema.Null]), + ), + models: Schema.optionalKey( + Schema.Union([V2ConfigRequirementsReadResponse__ModelsRequirements, Schema.Null]), + ), +}); + export type V2ConfigWriteResponse__OverriddenMetadata = { readonly effectiveValue: unknown; readonly message: string; @@ -25879,84 +28181,24 @@ export const V2ConfigWriteResponse__OverriddenMetadata = Schema.Struct({ overridingLayer: V2ConfigWriteResponse__ConfigLayerMetadata, }); -export type V2ItemGuardianApprovalReviewCompletedNotification__AdditionalFileSystemPermissions = { - readonly entries?: ReadonlyArray | null; - readonly globScanMaxDepth?: number | null; - readonly read?: ReadonlyArray | null; - readonly write?: ReadonlyArray | null; +export type V2ItemGuardianApprovalReviewCompletedNotification__FileSystemSandboxEntry = { + readonly access: V2ItemGuardianApprovalReviewCompletedNotification__FileSystemAccessMode; + readonly path: V2ItemGuardianApprovalReviewCompletedNotification__FileSystemPath; }; -export const V2ItemGuardianApprovalReviewCompletedNotification__AdditionalFileSystemPermissions = +export const V2ItemGuardianApprovalReviewCompletedNotification__FileSystemSandboxEntry = Schema.Struct({ - entries: Schema.optionalKey( - Schema.Union([ - Schema.Array(V2ItemGuardianApprovalReviewCompletedNotification__FileSystemSandboxEntry), - Schema.Null, - ]), - ), - globScanMaxDepth: Schema.optionalKey( - Schema.Union([ - Schema.Number.annotate({ format: "uint" }) - .check(Schema.isInt()) - .check(Schema.isGreaterThanOrEqualTo(1)), - Schema.Null, - ]), - ), - read: Schema.optionalKey( - Schema.Union([ - Schema.Array(V2ItemGuardianApprovalReviewCompletedNotification__AbsolutePathBuf).annotate({ - description: "This will be removed in favor of `entries`.", - }), - Schema.Null, - ]), - ), - write: Schema.optionalKey( - Schema.Union([ - Schema.Array(V2ItemGuardianApprovalReviewCompletedNotification__AbsolutePathBuf).annotate({ - description: "This will be removed in favor of `entries`.", - }), - Schema.Null, - ]), - ), + access: V2ItemGuardianApprovalReviewCompletedNotification__FileSystemAccessMode, + path: V2ItemGuardianApprovalReviewCompletedNotification__FileSystemPath, }); -export type V2ItemGuardianApprovalReviewStartedNotification__AdditionalFileSystemPermissions = { - readonly entries?: ReadonlyArray | null; - readonly globScanMaxDepth?: number | null; - readonly read?: ReadonlyArray | null; - readonly write?: ReadonlyArray | null; +export type V2ItemGuardianApprovalReviewStartedNotification__FileSystemSandboxEntry = { + readonly access: V2ItemGuardianApprovalReviewStartedNotification__FileSystemAccessMode; + readonly path: V2ItemGuardianApprovalReviewStartedNotification__FileSystemPath; }; -export const V2ItemGuardianApprovalReviewStartedNotification__AdditionalFileSystemPermissions = +export const V2ItemGuardianApprovalReviewStartedNotification__FileSystemSandboxEntry = Schema.Struct({ - entries: Schema.optionalKey( - Schema.Union([ - Schema.Array(V2ItemGuardianApprovalReviewStartedNotification__FileSystemSandboxEntry), - Schema.Null, - ]), - ), - globScanMaxDepth: Schema.optionalKey( - Schema.Union([ - Schema.Number.annotate({ format: "uint" }) - .check(Schema.isInt()) - .check(Schema.isGreaterThanOrEqualTo(1)), - Schema.Null, - ]), - ), - read: Schema.optionalKey( - Schema.Union([ - Schema.Array(V2ItemGuardianApprovalReviewStartedNotification__AbsolutePathBuf).annotate({ - description: "This will be removed in favor of `entries`.", - }), - Schema.Null, - ]), - ), - write: Schema.optionalKey( - Schema.Union([ - Schema.Array(V2ItemGuardianApprovalReviewStartedNotification__AbsolutePathBuf).annotate({ - description: "This will be removed in favor of `entries`.", - }), - Schema.Null, - ]), - ), + access: V2ItemGuardianApprovalReviewStartedNotification__FileSystemAccessMode, + path: V2ItemGuardianApprovalReviewStartedNotification__FileSystemPath, }); export type V2PluginInstalledResponse__PluginSummary = { @@ -25965,14 +28207,17 @@ export type V2PluginInstalledResponse__PluginSummary = { readonly enabled: boolean; readonly id: string; readonly installPolicy: V2PluginInstalledResponse__PluginInstallPolicy; + readonly installPolicySource?: V2PluginInstalledResponse__PluginInstallPolicySource | null; readonly installed: boolean; readonly interface?: V2PluginInstalledResponse__PluginInterface | null; readonly keywords?: ReadonlyArray; readonly localVersion?: string | null; + readonly mustShowInstallationInterstitial?: boolean | null; readonly name: string; readonly remotePluginId?: string | null; readonly shareContext?: V2PluginInstalledResponse__PluginShareContext | null; readonly source: V2PluginInstalledResponse__PluginSource; + readonly version?: string | null; }; export const V2PluginInstalledResponse__PluginSummary = Schema.Struct({ authPolicy: V2PluginInstalledResponse__PluginAuthPolicy, @@ -25985,6 +28230,9 @@ export const V2PluginInstalledResponse__PluginSummary = Schema.Struct({ enabled: Schema.Boolean, id: Schema.String, installPolicy: V2PluginInstalledResponse__PluginInstallPolicy, + installPolicySource: Schema.optionalKey( + Schema.Union([V2PluginInstalledResponse__PluginInstallPolicySource, Schema.Null]), + ), installed: Schema.Boolean, interface: Schema.optionalKey( Schema.Union([V2PluginInstalledResponse__PluginInterface, Schema.Null]), @@ -25998,6 +28246,7 @@ export const V2PluginInstalledResponse__PluginSummary = Schema.Struct({ Schema.Null, ]), ), + mustShowInstallationInterstitial: Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), name: Schema.String, remotePluginId: Schema.optionalKey( Schema.Union([ @@ -26011,6 +28260,14 @@ export const V2PluginInstalledResponse__PluginSummary = Schema.Struct({ }), ), source: V2PluginInstalledResponse__PluginSource, + version: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Version advertised by the remote marketplace backend when available.", + }), + Schema.Null, + ]), + ), }); export type V2PluginListResponse__PluginSummary = { @@ -26019,14 +28276,17 @@ export type V2PluginListResponse__PluginSummary = { readonly enabled: boolean; readonly id: string; readonly installPolicy: V2PluginListResponse__PluginInstallPolicy; + readonly installPolicySource?: V2PluginListResponse__PluginInstallPolicySource | null; readonly installed: boolean; readonly interface?: V2PluginListResponse__PluginInterface | null; readonly keywords?: ReadonlyArray; readonly localVersion?: string | null; + readonly mustShowInstallationInterstitial?: boolean | null; readonly name: string; readonly remotePluginId?: string | null; readonly shareContext?: V2PluginListResponse__PluginShareContext | null; readonly source: V2PluginListResponse__PluginSource; + readonly version?: string | null; }; export const V2PluginListResponse__PluginSummary = Schema.Struct({ authPolicy: V2PluginListResponse__PluginAuthPolicy, @@ -26039,6 +28299,9 @@ export const V2PluginListResponse__PluginSummary = Schema.Struct({ enabled: Schema.Boolean, id: Schema.String, installPolicy: V2PluginListResponse__PluginInstallPolicy, + installPolicySource: Schema.optionalKey( + Schema.Union([V2PluginListResponse__PluginInstallPolicySource, Schema.Null]), + ), installed: Schema.Boolean, interface: Schema.optionalKey(Schema.Union([V2PluginListResponse__PluginInterface, Schema.Null])), keywords: Schema.optionalKey(Schema.Array(Schema.String).annotate({ default: [] })), @@ -26050,6 +28313,7 @@ export const V2PluginListResponse__PluginSummary = Schema.Struct({ Schema.Null, ]), ), + mustShowInstallationInterstitial: Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), name: Schema.String, remotePluginId: Schema.optionalKey( Schema.Union([ @@ -26063,6 +28327,14 @@ export const V2PluginListResponse__PluginSummary = Schema.Struct({ }), ), source: V2PluginListResponse__PluginSource, + version: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Version advertised by the remote marketplace backend when available.", + }), + Schema.Null, + ]), + ), }); export type V2PluginReadResponse__PluginSummary = { @@ -26071,14 +28343,17 @@ export type V2PluginReadResponse__PluginSummary = { readonly enabled: boolean; readonly id: string; readonly installPolicy: V2PluginReadResponse__PluginInstallPolicy; + readonly installPolicySource?: V2PluginReadResponse__PluginInstallPolicySource | null; readonly installed: boolean; readonly interface?: V2PluginReadResponse__PluginInterface | null; readonly keywords?: ReadonlyArray; readonly localVersion?: string | null; + readonly mustShowInstallationInterstitial?: boolean | null; readonly name: string; readonly remotePluginId?: string | null; readonly shareContext?: V2PluginReadResponse__PluginShareContext | null; readonly source: V2PluginReadResponse__PluginSource; + readonly version?: string | null; }; export const V2PluginReadResponse__PluginSummary = Schema.Struct({ authPolicy: V2PluginReadResponse__PluginAuthPolicy, @@ -26091,6 +28366,9 @@ export const V2PluginReadResponse__PluginSummary = Schema.Struct({ enabled: Schema.Boolean, id: Schema.String, installPolicy: V2PluginReadResponse__PluginInstallPolicy, + installPolicySource: Schema.optionalKey( + Schema.Union([V2PluginReadResponse__PluginInstallPolicySource, Schema.Null]), + ), installed: Schema.Boolean, interface: Schema.optionalKey(Schema.Union([V2PluginReadResponse__PluginInterface, Schema.Null])), keywords: Schema.optionalKey(Schema.Array(Schema.String).annotate({ default: [] })), @@ -26102,6 +28380,7 @@ export const V2PluginReadResponse__PluginSummary = Schema.Struct({ Schema.Null, ]), ), + mustShowInstallationInterstitial: Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), name: Schema.String, remotePluginId: Schema.optionalKey( Schema.Union([ @@ -26115,6 +28394,14 @@ export const V2PluginReadResponse__PluginSummary = Schema.Struct({ }), ), source: V2PluginReadResponse__PluginSource, + version: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Version advertised by the remote marketplace backend when available.", + }), + Schema.Null, + ]), + ), }); export type V2PluginShareListResponse__PluginSummary = { @@ -26123,14 +28410,17 @@ export type V2PluginShareListResponse__PluginSummary = { readonly enabled: boolean; readonly id: string; readonly installPolicy: V2PluginShareListResponse__PluginInstallPolicy; + readonly installPolicySource?: V2PluginShareListResponse__PluginInstallPolicySource | null; readonly installed: boolean; readonly interface?: V2PluginShareListResponse__PluginInterface | null; readonly keywords?: ReadonlyArray; readonly localVersion?: string | null; + readonly mustShowInstallationInterstitial?: boolean | null; readonly name: string; readonly remotePluginId?: string | null; readonly shareContext?: V2PluginShareListResponse__PluginShareContext | null; readonly source: V2PluginShareListResponse__PluginSource; + readonly version?: string | null; }; export const V2PluginShareListResponse__PluginSummary = Schema.Struct({ authPolicy: V2PluginShareListResponse__PluginAuthPolicy, @@ -26143,6 +28433,9 @@ export const V2PluginShareListResponse__PluginSummary = Schema.Struct({ enabled: Schema.Boolean, id: Schema.String, installPolicy: V2PluginShareListResponse__PluginInstallPolicy, + installPolicySource: Schema.optionalKey( + Schema.Union([V2PluginShareListResponse__PluginInstallPolicySource, Schema.Null]), + ), installed: Schema.Boolean, interface: Schema.optionalKey( Schema.Union([V2PluginShareListResponse__PluginInterface, Schema.Null]), @@ -26156,6 +28449,7 @@ export const V2PluginShareListResponse__PluginSummary = Schema.Struct({ Schema.Null, ]), ), + mustShowInstallationInterstitial: Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null])), name: Schema.String, remotePluginId: Schema.optionalKey( Schema.Union([ @@ -26169,12 +28463,21 @@ export const V2PluginShareListResponse__PluginSummary = Schema.Struct({ }), ), source: V2PluginShareListResponse__PluginSource, + version: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Version advertised by the remote marketplace backend when available.", + }), + Schema.Null, + ]), + ), }); export type V2RawResponseItemCompletedNotification__ResponseItem = | { readonly content: ReadonlyArray; readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough | null; readonly phase?: V2RawResponseItemCompletedNotification__MessagePhase | null; readonly role: string; readonly type: "message"; @@ -26182,12 +28485,16 @@ export type V2RawResponseItemCompletedNotification__ResponseItem = | { readonly author: string; readonly content: ReadonlyArray; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough | null; readonly recipient: string; readonly type: "agent_message"; } | { readonly content?: ReadonlyArray | null; readonly encrypted_content?: string | null; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough | null; readonly summary: ReadonlyArray; readonly type: "reasoning"; } @@ -26195,6 +28502,7 @@ export type V2RawResponseItemCompletedNotification__ResponseItem = readonly action: V2RawResponseItemCompletedNotification__LocalShellAction; readonly call_id?: string | null; readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough | null; readonly status: V2RawResponseItemCompletedNotification__LocalShellStatus; readonly type: "local_shell_call"; } @@ -26202,6 +28510,7 @@ export type V2RawResponseItemCompletedNotification__ResponseItem = readonly arguments: string; readonly call_id: string; readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough | null; readonly name: string; readonly namespace?: string | null; readonly type: "function_call"; @@ -26211,11 +28520,14 @@ export type V2RawResponseItemCompletedNotification__ResponseItem = readonly call_id?: string | null; readonly execution: string; readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough | null; readonly status?: string | null; readonly type: "tool_search_call"; } | { readonly call_id: string; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough | null; readonly output: V2RawResponseItemCompletedNotification__FunctionCallOutputBody; readonly type: "function_call_output"; } @@ -26223,12 +28535,16 @@ export type V2RawResponseItemCompletedNotification__ResponseItem = readonly call_id: string; readonly id?: string | null; readonly input: string; + readonly internal_chat_message_metadata_passthrough?: V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough | null; readonly name: string; + readonly namespace?: string | null; readonly status?: string | null; readonly type: "custom_tool_call"; } | { readonly call_id: string; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough | null; readonly name?: string | null; readonly output: V2RawResponseItemCompletedNotification__FunctionCallOutputBody; readonly type: "custom_tool_call_output"; @@ -26236,6 +28552,8 @@ export type V2RawResponseItemCompletedNotification__ResponseItem = | { readonly call_id?: string | null; readonly execution: string; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough | null; readonly status: string; readonly tools: ReadonlyArray; readonly type: "tool_search_output"; @@ -26243,26 +28561,42 @@ export type V2RawResponseItemCompletedNotification__ResponseItem = | { readonly action?: V2RawResponseItemCompletedNotification__ResponsesApiWebSearchAction | null; readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough | null; readonly status?: string | null; readonly type: "web_search_call"; } | { - readonly id: string; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough | null; readonly result: string; readonly revised_prompt?: string | null; readonly status: string; readonly type: "image_generation_call"; } - | { readonly encrypted_content: string; readonly type: "compaction" } + | { + readonly encrypted_content: string; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough | null; + readonly type: "compaction"; + } | { readonly type: "compaction_trigger" } - | { readonly encrypted_content?: string | null; readonly type: "context_compaction" } + | { + readonly encrypted_content?: string | null; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough | null; + readonly type: "context_compaction"; + } | { readonly type: "other" }; export const V2RawResponseItemCompletedNotification__ResponseItem = Schema.Union( [ Schema.Struct({ content: Schema.Array(V2RawResponseItemCompletedNotification__ContentItem), - id: Schema.optionalKey( - Schema.Union([Schema.String.annotate({ writeOnly: true }), Schema.Null]), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ + V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough, + Schema.Null, + ]), ), phase: Schema.optionalKey( Schema.Union([V2RawResponseItemCompletedNotification__MessagePhase, Schema.Null]), @@ -26273,6 +28607,13 @@ export const V2RawResponseItemCompletedNotification__ResponseItem = Schema.Union Schema.Struct({ author: Schema.String, content: Schema.Array(V2RawResponseItemCompletedNotification__AgentMessageInputContent), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ + V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough, + Schema.Null, + ]), + ), recipient: Schema.String, type: Schema.Literal("agent_message").annotate({ title: "AgentMessageResponseItemType" }), }).annotate({ title: "AgentMessageResponseItem" }), @@ -26284,6 +28625,13 @@ export const V2RawResponseItemCompletedNotification__ResponseItem = Schema.Union ]), ), encrypted_content: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ + V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough, + Schema.Null, + ]), + ), summary: Schema.Array(V2RawResponseItemCompletedNotification__ReasoningItemReasoningSummary), type: Schema.Literal("reasoning").annotate({ title: "ReasoningResponseItemType" }), }).annotate({ title: "ReasoningResponseItem" }), @@ -26299,11 +28647,16 @@ export const V2RawResponseItemCompletedNotification__ResponseItem = Schema.Union Schema.Union([ Schema.String.annotate({ description: "Legacy id field retained for compatibility with older payloads.", - writeOnly: true, }), Schema.Null, ]), ), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ + V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough, + Schema.Null, + ]), + ), status: V2RawResponseItemCompletedNotification__LocalShellStatus, type: Schema.Literal("local_shell_call").annotate({ title: "LocalShellCallResponseItemType", @@ -26312,8 +28665,12 @@ export const V2RawResponseItemCompletedNotification__ResponseItem = Schema.Union Schema.Struct({ arguments: Schema.String, call_id: Schema.String, - id: Schema.optionalKey( - Schema.Union([Schema.String.annotate({ writeOnly: true }), Schema.Null]), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ + V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough, + Schema.Null, + ]), ), name: Schema.String, namespace: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), @@ -26323,8 +28680,12 @@ export const V2RawResponseItemCompletedNotification__ResponseItem = Schema.Union arguments: Schema.Unknown, call_id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), execution: Schema.String, - id: Schema.optionalKey( - Schema.Union([Schema.String.annotate({ writeOnly: true }), Schema.Null]), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ + V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough, + Schema.Null, + ]), ), status: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), type: Schema.Literal("tool_search_call").annotate({ @@ -26333,6 +28694,13 @@ export const V2RawResponseItemCompletedNotification__ResponseItem = Schema.Union }).annotate({ title: "ToolSearchCallResponseItem" }), Schema.Struct({ call_id: Schema.String, + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ + V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough, + Schema.Null, + ]), + ), output: V2RawResponseItemCompletedNotification__FunctionCallOutputBody, type: Schema.Literal("function_call_output").annotate({ title: "FunctionCallOutputResponseItemType", @@ -26340,11 +28708,16 @@ export const V2RawResponseItemCompletedNotification__ResponseItem = Schema.Union }).annotate({ title: "FunctionCallOutputResponseItem" }), Schema.Struct({ call_id: Schema.String, - id: Schema.optionalKey( - Schema.Union([Schema.String.annotate({ writeOnly: true }), Schema.Null]), - ), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), input: Schema.String, + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ + V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough, + Schema.Null, + ]), + ), name: Schema.String, + namespace: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), status: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), type: Schema.Literal("custom_tool_call").annotate({ title: "CustomToolCallResponseItemType", @@ -26352,6 +28725,13 @@ export const V2RawResponseItemCompletedNotification__ResponseItem = Schema.Union }).annotate({ title: "CustomToolCallResponseItem" }), Schema.Struct({ call_id: Schema.String, + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ + V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough, + Schema.Null, + ]), + ), name: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), output: V2RawResponseItemCompletedNotification__FunctionCallOutputBody, type: Schema.Literal("custom_tool_call_output").annotate({ @@ -26361,6 +28741,13 @@ export const V2RawResponseItemCompletedNotification__ResponseItem = Schema.Union Schema.Struct({ call_id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), execution: Schema.String, + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ + V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough, + Schema.Null, + ]), + ), status: Schema.String, tools: Schema.Array(Schema.Unknown), type: Schema.Literal("tool_search_output").annotate({ @@ -26374,14 +28761,24 @@ export const V2RawResponseItemCompletedNotification__ResponseItem = Schema.Union Schema.Null, ]), ), - id: Schema.optionalKey( - Schema.Union([Schema.String.annotate({ writeOnly: true }), Schema.Null]), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ + V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough, + Schema.Null, + ]), ), status: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), type: Schema.Literal("web_search_call").annotate({ title: "WebSearchCallResponseItemType" }), }).annotate({ title: "WebSearchCallResponseItem" }), Schema.Struct({ - id: Schema.String, + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ + V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough, + Schema.Null, + ]), + ), result: Schema.String, revised_prompt: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), status: Schema.String, @@ -26391,6 +28788,13 @@ export const V2RawResponseItemCompletedNotification__ResponseItem = Schema.Union }).annotate({ title: "ImageGenerationCallResponseItem" }), Schema.Struct({ encrypted_content: Schema.String, + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ + V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough, + Schema.Null, + ]), + ), type: Schema.Literal("compaction").annotate({ title: "CompactionResponseItemType" }), }).annotate({ title: "CompactionResponseItem" }), Schema.Struct({ @@ -26400,6 +28804,13 @@ export const V2RawResponseItemCompletedNotification__ResponseItem = Schema.Union }).annotate({ title: "CompactionTriggerResponseItem" }), Schema.Struct({ encrypted_content: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ + V2RawResponseItemCompletedNotification__InternalChatMessageMetadataPassthrough, + Schema.Null, + ]), + ), type: Schema.Literal("context_compaction").annotate({ title: "ContextCompactionResponseItemType", }), @@ -26445,7 +28856,9 @@ export const V2ReviewStartResponse__Turn = Schema.Struct({ description: "Only populated when the Turn's status is failed.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this turn. Codex-generated turn IDs are UUIDv7.", + }), items: Schema.Array(V2ReviewStartResponse__ThreadItem).annotate({ description: "Thread items currently included in this turn payload.", }), @@ -26512,7 +28925,9 @@ export const V2ThreadForkResponse__Turn = Schema.Struct({ description: "Only populated when the Turn's status is failed.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this turn. Codex-generated turn IDs are UUIDv7.", + }), items: Schema.Array(V2ThreadForkResponse__ThreadItem).annotate({ description: "Thread items currently included in this turn payload.", }), @@ -26568,7 +28983,9 @@ export const V2ThreadListResponse__Turn = Schema.Struct({ description: "Only populated when the Turn's status is failed.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this turn. Codex-generated turn IDs are UUIDv7.", + }), items: Schema.Array(V2ThreadListResponse__ThreadItem).annotate({ description: "Thread items currently included in this turn payload.", }), @@ -26624,7 +29041,9 @@ export const V2ThreadMetadataUpdateResponse__Turn = Schema.Struct({ description: "Only populated when the Turn's status is failed.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this turn. Codex-generated turn IDs are UUIDv7.", + }), items: Schema.Array(V2ThreadMetadataUpdateResponse__ThreadItem).annotate({ description: "Thread items currently included in this turn payload.", }), @@ -26680,7 +29099,9 @@ export const V2ThreadReadResponse__Turn = Schema.Struct({ description: "Only populated when the Turn's status is failed.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this turn. Codex-generated turn IDs are UUIDv7.", + }), items: Schema.Array(V2ThreadReadResponse__ThreadItem).annotate({ description: "Thread items currently included in this turn payload.", }), @@ -26736,7 +29157,9 @@ export const V2ThreadResumeResponse__Turn = Schema.Struct({ description: "Only populated when the Turn's status is failed.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this turn. Codex-generated turn IDs are UUIDv7.", + }), items: Schema.Array(V2ThreadResumeResponse__ThreadItem).annotate({ description: "Thread items currently included in this turn payload.", }), @@ -26792,7 +29215,9 @@ export const V2ThreadRollbackResponse__Turn = Schema.Struct({ description: "Only populated when the Turn's status is failed.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this turn. Codex-generated turn IDs are UUIDv7.", + }), items: Schema.Array(V2ThreadRollbackResponse__ThreadItem).annotate({ description: "Thread items currently included in this turn payload.", }), @@ -26885,7 +29310,9 @@ export const V2ThreadStartedNotification__Turn = Schema.Struct({ description: "Only populated when the Turn's status is failed.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this turn. Codex-generated turn IDs are UUIDv7.", + }), items: Schema.Array(V2ThreadStartedNotification__ThreadItem).annotate({ description: "Thread items currently included in this turn payload.", }), @@ -26941,7 +29368,9 @@ export const V2ThreadStartResponse__Turn = Schema.Struct({ description: "Only populated when the Turn's status is failed.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this turn. Codex-generated turn IDs are UUIDv7.", + }), items: Schema.Array(V2ThreadStartResponse__ThreadItem).annotate({ description: "Thread items currently included in this turn payload.", }), @@ -26997,7 +29426,9 @@ export const V2ThreadUnarchiveResponse__Turn = Schema.Struct({ description: "Only populated when the Turn's status is failed.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this turn. Codex-generated turn IDs are UUIDv7.", + }), items: Schema.Array(V2ThreadUnarchiveResponse__ThreadItem).annotate({ description: "Thread items currently included in this turn payload.", }), @@ -27053,7 +29484,9 @@ export const V2TurnCompletedNotification__Turn = Schema.Struct({ description: "Only populated when the Turn's status is failed.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this turn. Codex-generated turn IDs are UUIDv7.", + }), items: Schema.Array(V2TurnCompletedNotification__ThreadItem).annotate({ description: "Thread items currently included in this turn payload.", }), @@ -27109,7 +29542,9 @@ export const V2TurnStartedNotification__Turn = Schema.Struct({ description: "Only populated when the Turn's status is failed.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this turn. Codex-generated turn IDs are UUIDv7.", + }), items: Schema.Array(V2TurnStartedNotification__ThreadItem).annotate({ description: "Thread items currently included in this turn payload.", }), @@ -27165,7 +29600,9 @@ export const V2TurnStartResponse__Turn = Schema.Struct({ description: "Only populated when the Turn's status is failed.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this turn. Codex-generated turn IDs are UUIDv7.", + }), items: Schema.Array(V2TurnStartResponse__ThreadItem).annotate({ description: "Thread items currently included in this turn payload.", }), @@ -27187,6 +29624,47 @@ export const V2TurnStartResponse__Turn = Schema.Struct({ status: V2TurnStartResponse__TurnStatus, }); +export type CommandExecutionRequestApprovalParams__AdditionalFileSystemPermissions = { + readonly entries?: ReadonlyArray | null; + readonly globScanMaxDepth?: number | null; + readonly read?: ReadonlyArray | null; + readonly write?: ReadonlyArray | null; +}; +export const CommandExecutionRequestApprovalParams__AdditionalFileSystemPermissions = Schema.Struct( + { + entries: Schema.optionalKey( + Schema.Union([ + Schema.Array(CommandExecutionRequestApprovalParams__FileSystemSandboxEntry), + Schema.Null, + ]), + ), + globScanMaxDepth: Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ format: "uint" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(1)), + Schema.Null, + ]), + ), + read: Schema.optionalKey( + Schema.Union([ + Schema.Array(CommandExecutionRequestApprovalParams__LegacyAppPathString).annotate({ + description: "This will be removed in favor of `entries`.", + }), + Schema.Null, + ]), + ), + write: Schema.optionalKey( + Schema.Union([ + Schema.Array(CommandExecutionRequestApprovalParams__LegacyAppPathString).annotate({ + description: "This will be removed in favor of `entries`.", + }), + Schema.Null, + ]), + ), + }, +); + export type McpServerElicitationRequestParams__McpElicitationEnumSchema = | McpServerElicitationRequestParams__McpElicitationSingleSelectEnumSchema | McpServerElicitationRequestParams__McpElicitationMultiSelectEnumSchema @@ -27197,45 +29675,117 @@ export const McpServerElicitationRequestParams__McpElicitationEnumSchema = Schem McpServerElicitationRequestParams__McpElicitationLegacyTitledEnumSchema, ]); -export type PermissionsRequestApprovalParams__RequestPermissionProfile = { - readonly fileSystem?: PermissionsRequestApprovalParams__AdditionalFileSystemPermissions | null; - readonly network?: PermissionsRequestApprovalParams__AdditionalNetworkPermissions | null; +export type PermissionsRequestApprovalParams__AdditionalFileSystemPermissions = { + readonly entries?: ReadonlyArray | null; + readonly globScanMaxDepth?: number | null; + readonly read?: ReadonlyArray | null; + readonly write?: ReadonlyArray | null; }; -export const PermissionsRequestApprovalParams__RequestPermissionProfile = Schema.Struct({ - fileSystem: Schema.optionalKey( - Schema.Union([PermissionsRequestApprovalParams__AdditionalFileSystemPermissions, Schema.Null]), +export const PermissionsRequestApprovalParams__AdditionalFileSystemPermissions = Schema.Struct({ + entries: Schema.optionalKey( + Schema.Union([ + Schema.Array(PermissionsRequestApprovalParams__FileSystemSandboxEntry), + Schema.Null, + ]), ), - network: Schema.optionalKey( - Schema.Union([PermissionsRequestApprovalParams__AdditionalNetworkPermissions, Schema.Null]), + globScanMaxDepth: Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ format: "uint" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(1)), + Schema.Null, + ]), + ), + read: Schema.optionalKey( + Schema.Union([ + Schema.Array(PermissionsRequestApprovalParams__LegacyAppPathString).annotate({ + description: "This will be removed in favor of `entries`.", + }), + Schema.Null, + ]), + ), + write: Schema.optionalKey( + Schema.Union([ + Schema.Array(PermissionsRequestApprovalParams__LegacyAppPathString).annotate({ + description: "This will be removed in favor of `entries`.", + }), + Schema.Null, + ]), ), }); -export type PermissionsRequestApprovalResponse__GrantedPermissionProfile = { - readonly fileSystem?: PermissionsRequestApprovalResponse__AdditionalFileSystemPermissions | null; - readonly network?: PermissionsRequestApprovalResponse__AdditionalNetworkPermissions | null; +export type PermissionsRequestApprovalResponse__AdditionalFileSystemPermissions = { + readonly entries?: ReadonlyArray | null; + readonly globScanMaxDepth?: number | null; + readonly read?: ReadonlyArray | null; + readonly write?: ReadonlyArray | null; }; -export const PermissionsRequestApprovalResponse__GrantedPermissionProfile = Schema.Struct({ - fileSystem: Schema.optionalKey( +export const PermissionsRequestApprovalResponse__AdditionalFileSystemPermissions = Schema.Struct({ + entries: Schema.optionalKey( Schema.Union([ - PermissionsRequestApprovalResponse__AdditionalFileSystemPermissions, + Schema.Array(PermissionsRequestApprovalResponse__FileSystemSandboxEntry), Schema.Null, ]), ), - network: Schema.optionalKey( - Schema.Union([PermissionsRequestApprovalResponse__AdditionalNetworkPermissions, Schema.Null]), + globScanMaxDepth: Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ format: "uint" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(1)), + Schema.Null, + ]), + ), + read: Schema.optionalKey( + Schema.Union([ + Schema.Array(PermissionsRequestApprovalResponse__LegacyAppPathString).annotate({ + description: "This will be removed in favor of `entries`.", + }), + Schema.Null, + ]), + ), + write: Schema.optionalKey( + Schema.Union([ + Schema.Array(PermissionsRequestApprovalResponse__LegacyAppPathString).annotate({ + description: "This will be removed in favor of `entries`.", + }), + Schema.Null, + ]), ), }); -export type ServerNotification__RequestPermissionProfile = { - readonly fileSystem?: ServerNotification__AdditionalFileSystemPermissions | null; - readonly network?: ServerNotification__AdditionalNetworkPermissions | null; +export type ServerNotification__AdditionalFileSystemPermissions = { + readonly entries?: ReadonlyArray | null; + readonly globScanMaxDepth?: number | null; + readonly read?: ReadonlyArray | null; + readonly write?: ReadonlyArray | null; }; -export const ServerNotification__RequestPermissionProfile = Schema.Struct({ - fileSystem: Schema.optionalKey( - Schema.Union([ServerNotification__AdditionalFileSystemPermissions, Schema.Null]), +export const ServerNotification__AdditionalFileSystemPermissions = Schema.Struct({ + entries: Schema.optionalKey( + Schema.Union([Schema.Array(ServerNotification__FileSystemSandboxEntry), Schema.Null]), ), - network: Schema.optionalKey( - Schema.Union([ServerNotification__AdditionalNetworkPermissions, Schema.Null]), + globScanMaxDepth: Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ format: "uint" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(1)), + Schema.Null, + ]), + ), + read: Schema.optionalKey( + Schema.Union([ + Schema.Array(ServerNotification__LegacyAppPathString).annotate({ + description: "This will be removed in favor of `entries`.", + }), + Schema.Null, + ]), + ), + write: Schema.optionalKey( + Schema.Union([ + Schema.Array(ServerNotification__LegacyAppPathString).annotate({ + description: "This will be removed in favor of `entries`.", + }), + Schema.Null, + ]), ), }); @@ -27263,6 +29813,7 @@ export type ServerNotification__Thread = { readonly parentThreadId?: string | null; readonly path?: string | null; readonly preview: string; + readonly recencyAt?: number | null; readonly sessionId: string; readonly source: | "cli" @@ -27329,7 +29880,9 @@ export const ServerNotification__Thread = Schema.Struct({ description: "Optional Git metadata captured when the thread was created.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this thread. Codex-generated thread IDs are UUIDv7.", + }), modelProvider: Schema.String.annotate({ description: "Model provider used for this thread (for example, 'openai').", }), @@ -27357,6 +29910,15 @@ export const ServerNotification__Thread = Schema.Struct({ preview: Schema.String.annotate({ description: "Usually the first user message in the thread, if available.", }), + recencyAt: Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + description: "Unix timestamp (in seconds) used for thread recency ordering.", + format: "int64", + }).check(Schema.isInt()), + Schema.Null, + ]), + ), sessionId: Schema.String.annotate({ description: "Session id shared by threads that belong to the same session tree.", }), @@ -27423,16 +29985,39 @@ export const ServerNotification__TurnStartedNotification = Schema.Struct({ turn: ServerNotification__Turn, }); -export type ServerRequest__RequestPermissionProfile = { - readonly fileSystem?: ServerRequest__AdditionalFileSystemPermissions | null; - readonly network?: ServerRequest__AdditionalNetworkPermissions | null; +export type ServerRequest__AdditionalFileSystemPermissions = { + readonly entries?: ReadonlyArray | null; + readonly globScanMaxDepth?: number | null; + readonly read?: ReadonlyArray | null; + readonly write?: ReadonlyArray | null; }; -export const ServerRequest__RequestPermissionProfile = Schema.Struct({ - fileSystem: Schema.optionalKey( - Schema.Union([ServerRequest__AdditionalFileSystemPermissions, Schema.Null]), +export const ServerRequest__AdditionalFileSystemPermissions = Schema.Struct({ + entries: Schema.optionalKey( + Schema.Union([Schema.Array(ServerRequest__FileSystemSandboxEntry), Schema.Null]), ), - network: Schema.optionalKey( - Schema.Union([ServerRequest__AdditionalNetworkPermissions, Schema.Null]), + globScanMaxDepth: Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ format: "uint" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(1)), + Schema.Null, + ]), + ), + read: Schema.optionalKey( + Schema.Union([ + Schema.Array(ServerRequest__LegacyAppPathString).annotate({ + description: "This will be removed in favor of `entries`.", + }), + Schema.Null, + ]), + ), + write: Schema.optionalKey( + Schema.Union([ + Schema.Array(ServerRequest__LegacyAppPathString).annotate({ + description: "This will be removed in favor of `entries`.", + }), + Schema.Null, + ]), ), }); @@ -27446,41 +30031,81 @@ export const ServerRequest__McpElicitationEnumSchema = Schema.Union([ ServerRequest__McpElicitationLegacyTitledEnumSchema, ]); -export type V2ItemGuardianApprovalReviewCompletedNotification__RequestPermissionProfile = { - readonly fileSystem?: V2ItemGuardianApprovalReviewCompletedNotification__AdditionalFileSystemPermissions | null; - readonly network?: V2ItemGuardianApprovalReviewCompletedNotification__AdditionalNetworkPermissions | null; +export type V2ItemGuardianApprovalReviewCompletedNotification__AdditionalFileSystemPermissions = { + readonly entries?: ReadonlyArray | null; + readonly globScanMaxDepth?: number | null; + readonly read?: ReadonlyArray | null; + readonly write?: ReadonlyArray | null; }; -export const V2ItemGuardianApprovalReviewCompletedNotification__RequestPermissionProfile = +export const V2ItemGuardianApprovalReviewCompletedNotification__AdditionalFileSystemPermissions = Schema.Struct({ - fileSystem: Schema.optionalKey( + entries: Schema.optionalKey( Schema.Union([ - V2ItemGuardianApprovalReviewCompletedNotification__AdditionalFileSystemPermissions, + Schema.Array(V2ItemGuardianApprovalReviewCompletedNotification__FileSystemSandboxEntry), Schema.Null, ]), ), - network: Schema.optionalKey( + globScanMaxDepth: Schema.optionalKey( Schema.Union([ - V2ItemGuardianApprovalReviewCompletedNotification__AdditionalNetworkPermissions, + Schema.Number.annotate({ format: "uint" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(1)), + Schema.Null, + ]), + ), + read: Schema.optionalKey( + Schema.Union([ + Schema.Array( + V2ItemGuardianApprovalReviewCompletedNotification__LegacyAppPathString, + ).annotate({ description: "This will be removed in favor of `entries`." }), + Schema.Null, + ]), + ), + write: Schema.optionalKey( + Schema.Union([ + Schema.Array( + V2ItemGuardianApprovalReviewCompletedNotification__LegacyAppPathString, + ).annotate({ description: "This will be removed in favor of `entries`." }), Schema.Null, ]), ), }); -export type V2ItemGuardianApprovalReviewStartedNotification__RequestPermissionProfile = { - readonly fileSystem?: V2ItemGuardianApprovalReviewStartedNotification__AdditionalFileSystemPermissions | null; - readonly network?: V2ItemGuardianApprovalReviewStartedNotification__AdditionalNetworkPermissions | null; +export type V2ItemGuardianApprovalReviewStartedNotification__AdditionalFileSystemPermissions = { + readonly entries?: ReadonlyArray | null; + readonly globScanMaxDepth?: number | null; + readonly read?: ReadonlyArray | null; + readonly write?: ReadonlyArray | null; }; -export const V2ItemGuardianApprovalReviewStartedNotification__RequestPermissionProfile = +export const V2ItemGuardianApprovalReviewStartedNotification__AdditionalFileSystemPermissions = Schema.Struct({ - fileSystem: Schema.optionalKey( + entries: Schema.optionalKey( Schema.Union([ - V2ItemGuardianApprovalReviewStartedNotification__AdditionalFileSystemPermissions, + Schema.Array(V2ItemGuardianApprovalReviewStartedNotification__FileSystemSandboxEntry), Schema.Null, ]), ), - network: Schema.optionalKey( + globScanMaxDepth: Schema.optionalKey( Schema.Union([ - V2ItemGuardianApprovalReviewStartedNotification__AdditionalNetworkPermissions, + Schema.Number.annotate({ format: "uint" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(1)), + Schema.Null, + ]), + ), + read: Schema.optionalKey( + Schema.Union([ + Schema.Array(V2ItemGuardianApprovalReviewStartedNotification__LegacyAppPathString).annotate( + { description: "This will be removed in favor of `entries`." }, + ), + Schema.Null, + ]), + ), + write: Schema.optionalKey( + Schema.Union([ + Schema.Array(V2ItemGuardianApprovalReviewStartedNotification__LegacyAppPathString).annotate( + { description: "This will be removed in favor of `entries`." }, + ), Schema.Null, ]), ), @@ -27534,6 +30159,8 @@ export type V2PluginReadResponse__PluginDetail = { readonly marketplaceName: string; readonly marketplacePath?: V2PluginReadResponse__AbsolutePathBuf | null; readonly mcpServers: ReadonlyArray; + readonly scheduledTasks?: ReadonlyArray | null; + readonly shareUrl?: string | null; readonly skills: ReadonlyArray; readonly summary: V2PluginReadResponse__PluginSummary; }; @@ -27547,6 +30174,10 @@ export const V2PluginReadResponse__PluginDetail = Schema.Struct({ Schema.Union([V2PluginReadResponse__AbsolutePathBuf, Schema.Null]), ), mcpServers: Schema.Array(Schema.String), + scheduledTasks: Schema.optionalKey( + Schema.Union([Schema.Array(V2PluginReadResponse__ScheduledTaskSummary), Schema.Null]), + ), + shareUrl: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), skills: Schema.Array(V2PluginReadResponse__SkillSummary), summary: V2PluginReadResponse__PluginSummary, }); @@ -27577,6 +30208,7 @@ export type V2ThreadForkResponse__Thread = { readonly parentThreadId?: string | null; readonly path?: string | null; readonly preview: string; + readonly recencyAt?: number | null; readonly sessionId: string; readonly source: | "cli" @@ -27643,7 +30275,9 @@ export const V2ThreadForkResponse__Thread = Schema.Struct({ description: "Optional Git metadata captured when the thread was created.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this thread. Codex-generated thread IDs are UUIDv7.", + }), modelProvider: Schema.String.annotate({ description: "Model provider used for this thread (for example, 'openai').", }), @@ -27671,6 +30305,15 @@ export const V2ThreadForkResponse__Thread = Schema.Struct({ preview: Schema.String.annotate({ description: "Usually the first user message in the thread, if available.", }), + recencyAt: Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + description: "Unix timestamp (in seconds) used for thread recency ordering.", + format: "int64", + }).check(Schema.isInt()), + Schema.Null, + ]), + ), sessionId: Schema.String.annotate({ description: "Session id shared by threads that belong to the same session tree.", }), @@ -27734,6 +30377,7 @@ export type V2ThreadListResponse__Thread = { readonly parentThreadId?: string | null; readonly path?: string | null; readonly preview: string; + readonly recencyAt?: number | null; readonly sessionId: string; readonly source: | "cli" @@ -27800,7 +30444,9 @@ export const V2ThreadListResponse__Thread = Schema.Struct({ description: "Optional Git metadata captured when the thread was created.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this thread. Codex-generated thread IDs are UUIDv7.", + }), modelProvider: Schema.String.annotate({ description: "Model provider used for this thread (for example, 'openai').", }), @@ -27828,6 +30474,15 @@ export const V2ThreadListResponse__Thread = Schema.Struct({ preview: Schema.String.annotate({ description: "Usually the first user message in the thread, if available.", }), + recencyAt: Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + description: "Unix timestamp (in seconds) used for thread recency ordering.", + format: "int64", + }).check(Schema.isInt()), + Schema.Null, + ]), + ), sessionId: Schema.String.annotate({ description: "Session id shared by threads that belong to the same session tree.", }), @@ -27891,6 +30546,7 @@ export type V2ThreadMetadataUpdateResponse__Thread = { readonly parentThreadId?: string | null; readonly path?: string | null; readonly preview: string; + readonly recencyAt?: number | null; readonly sessionId: string; readonly source: | "cli" @@ -27957,7 +30613,9 @@ export const V2ThreadMetadataUpdateResponse__Thread = Schema.Struct({ description: "Optional Git metadata captured when the thread was created.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this thread. Codex-generated thread IDs are UUIDv7.", + }), modelProvider: Schema.String.annotate({ description: "Model provider used for this thread (for example, 'openai').", }), @@ -27985,6 +30643,15 @@ export const V2ThreadMetadataUpdateResponse__Thread = Schema.Struct({ preview: Schema.String.annotate({ description: "Usually the first user message in the thread, if available.", }), + recencyAt: Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + description: "Unix timestamp (in seconds) used for thread recency ordering.", + format: "int64", + }).check(Schema.isInt()), + Schema.Null, + ]), + ), sessionId: Schema.String.annotate({ description: "Session id shared by threads that belong to the same session tree.", }), @@ -28048,6 +30715,7 @@ export type V2ThreadReadResponse__Thread = { readonly parentThreadId?: string | null; readonly path?: string | null; readonly preview: string; + readonly recencyAt?: number | null; readonly sessionId: string; readonly source: | "cli" @@ -28114,7 +30782,9 @@ export const V2ThreadReadResponse__Thread = Schema.Struct({ description: "Optional Git metadata captured when the thread was created.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this thread. Codex-generated thread IDs are UUIDv7.", + }), modelProvider: Schema.String.annotate({ description: "Model provider used for this thread (for example, 'openai').", }), @@ -28142,6 +30812,15 @@ export const V2ThreadReadResponse__Thread = Schema.Struct({ preview: Schema.String.annotate({ description: "Usually the first user message in the thread, if available.", }), + recencyAt: Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + description: "Unix timestamp (in seconds) used for thread recency ordering.", + format: "int64", + }).check(Schema.isInt()), + Schema.Null, + ]), + ), sessionId: Schema.String.annotate({ description: "Session id shared by threads that belong to the same session tree.", }), @@ -28205,6 +30884,7 @@ export type V2ThreadResumeResponse__Thread = { readonly parentThreadId?: string | null; readonly path?: string | null; readonly preview: string; + readonly recencyAt?: number | null; readonly sessionId: string; readonly source: | "cli" @@ -28271,7 +30951,9 @@ export const V2ThreadResumeResponse__Thread = Schema.Struct({ description: "Optional Git metadata captured when the thread was created.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this thread. Codex-generated thread IDs are UUIDv7.", + }), modelProvider: Schema.String.annotate({ description: "Model provider used for this thread (for example, 'openai').", }), @@ -28299,6 +30981,15 @@ export const V2ThreadResumeResponse__Thread = Schema.Struct({ preview: Schema.String.annotate({ description: "Usually the first user message in the thread, if available.", }), + recencyAt: Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + description: "Unix timestamp (in seconds) used for thread recency ordering.", + format: "int64", + }).check(Schema.isInt()), + Schema.Null, + ]), + ), sessionId: Schema.String.annotate({ description: "Session id shared by threads that belong to the same session tree.", }), @@ -28362,6 +31053,7 @@ export type V2ThreadStartedNotification__Thread = { readonly parentThreadId?: string | null; readonly path?: string | null; readonly preview: string; + readonly recencyAt?: number | null; readonly sessionId: string; readonly source: | "cli" @@ -28428,7 +31120,9 @@ export const V2ThreadStartedNotification__Thread = Schema.Struct({ description: "Optional Git metadata captured when the thread was created.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this thread. Codex-generated thread IDs are UUIDv7.", + }), modelProvider: Schema.String.annotate({ description: "Model provider used for this thread (for example, 'openai').", }), @@ -28456,6 +31150,15 @@ export const V2ThreadStartedNotification__Thread = Schema.Struct({ preview: Schema.String.annotate({ description: "Usually the first user message in the thread, if available.", }), + recencyAt: Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + description: "Unix timestamp (in seconds) used for thread recency ordering.", + format: "int64", + }).check(Schema.isInt()), + Schema.Null, + ]), + ), sessionId: Schema.String.annotate({ description: "Session id shared by threads that belong to the same session tree.", }), @@ -28519,6 +31222,7 @@ export type V2ThreadStartResponse__Thread = { readonly parentThreadId?: string | null; readonly path?: string | null; readonly preview: string; + readonly recencyAt?: number | null; readonly sessionId: string; readonly source: | "cli" @@ -28585,7 +31289,9 @@ export const V2ThreadStartResponse__Thread = Schema.Struct({ description: "Optional Git metadata captured when the thread was created.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this thread. Codex-generated thread IDs are UUIDv7.", + }), modelProvider: Schema.String.annotate({ description: "Model provider used for this thread (for example, 'openai').", }), @@ -28613,6 +31319,15 @@ export const V2ThreadStartResponse__Thread = Schema.Struct({ preview: Schema.String.annotate({ description: "Usually the first user message in the thread, if available.", }), + recencyAt: Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + description: "Unix timestamp (in seconds) used for thread recency ordering.", + format: "int64", + }).check(Schema.isInt()), + Schema.Null, + ]), + ), sessionId: Schema.String.annotate({ description: "Session id shared by threads that belong to the same session tree.", }), @@ -28676,6 +31391,7 @@ export type V2ThreadUnarchiveResponse__Thread = { readonly parentThreadId?: string | null; readonly path?: string | null; readonly preview: string; + readonly recencyAt?: number | null; readonly sessionId: string; readonly source: | "cli" @@ -28742,7 +31458,9 @@ export const V2ThreadUnarchiveResponse__Thread = Schema.Struct({ description: "Optional Git metadata captured when the thread was created.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this thread. Codex-generated thread IDs are UUIDv7.", + }), modelProvider: Schema.String.annotate({ description: "Model provider used for this thread (for example, 'openai').", }), @@ -28770,6 +31488,15 @@ export const V2ThreadUnarchiveResponse__Thread = Schema.Struct({ preview: Schema.String.annotate({ description: "Usually the first user message in the thread, if available.", }), + recencyAt: Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + description: "Unix timestamp (in seconds) used for thread recency ordering.", + format: "int64", + }).check(Schema.isInt()), + Schema.Null, + ]), + ), sessionId: Schema.String.annotate({ description: "Session id shared by threads that belong to the same session tree.", }), @@ -28830,6 +31557,141 @@ export const McpServerElicitationRequestParams__McpElicitationPrimitiveSchema = McpServerElicitationRequestParams__McpElicitationBooleanSchema, ]); +export type PermissionsRequestApprovalParams__RequestPermissionProfile = { + readonly fileSystem?: PermissionsRequestApprovalParams__AdditionalFileSystemPermissions | null; + readonly network?: PermissionsRequestApprovalParams__AdditionalNetworkPermissions | null; +}; +export const PermissionsRequestApprovalParams__RequestPermissionProfile = Schema.Struct({ + fileSystem: Schema.optionalKey( + Schema.Union([PermissionsRequestApprovalParams__AdditionalFileSystemPermissions, Schema.Null]), + ), + network: Schema.optionalKey( + Schema.Union([PermissionsRequestApprovalParams__AdditionalNetworkPermissions, Schema.Null]), + ), +}); + +export type PermissionsRequestApprovalResponse__GrantedPermissionProfile = { + readonly fileSystem?: PermissionsRequestApprovalResponse__AdditionalFileSystemPermissions | null; + readonly network?: PermissionsRequestApprovalResponse__AdditionalNetworkPermissions | null; +}; +export const PermissionsRequestApprovalResponse__GrantedPermissionProfile = Schema.Struct({ + fileSystem: Schema.optionalKey( + Schema.Union([ + PermissionsRequestApprovalResponse__AdditionalFileSystemPermissions, + Schema.Null, + ]), + ), + network: Schema.optionalKey( + Schema.Union([PermissionsRequestApprovalResponse__AdditionalNetworkPermissions, Schema.Null]), + ), +}); + +export type ServerNotification__RequestPermissionProfile = { + readonly fileSystem?: ServerNotification__AdditionalFileSystemPermissions | null; + readonly network?: ServerNotification__AdditionalNetworkPermissions | null; +}; +export const ServerNotification__RequestPermissionProfile = Schema.Struct({ + fileSystem: Schema.optionalKey( + Schema.Union([ServerNotification__AdditionalFileSystemPermissions, Schema.Null]), + ), + network: Schema.optionalKey( + Schema.Union([ServerNotification__AdditionalNetworkPermissions, Schema.Null]), + ), +}); + +export type ServerNotification__ThreadStartedNotification = { + readonly thread: ServerNotification__Thread; +}; +export const ServerNotification__ThreadStartedNotification = Schema.Struct({ + thread: ServerNotification__Thread, +}); + +export type ServerRequest__RequestPermissionProfile = { + readonly fileSystem?: ServerRequest__AdditionalFileSystemPermissions | null; + readonly network?: ServerRequest__AdditionalNetworkPermissions | null; +}; +export const ServerRequest__RequestPermissionProfile = Schema.Struct({ + fileSystem: Schema.optionalKey( + Schema.Union([ServerRequest__AdditionalFileSystemPermissions, Schema.Null]), + ), + network: Schema.optionalKey( + Schema.Union([ServerRequest__AdditionalNetworkPermissions, Schema.Null]), + ), +}); + +export type ServerRequest__McpElicitationPrimitiveSchema = + | ServerRequest__McpElicitationEnumSchema + | ServerRequest__McpElicitationStringSchema + | ServerRequest__McpElicitationNumberSchema + | ServerRequest__McpElicitationBooleanSchema; +export const ServerRequest__McpElicitationPrimitiveSchema = Schema.Union([ + ServerRequest__McpElicitationEnumSchema, + ServerRequest__McpElicitationStringSchema, + ServerRequest__McpElicitationNumberSchema, + ServerRequest__McpElicitationBooleanSchema, +]); + +export type V2ItemGuardianApprovalReviewCompletedNotification__RequestPermissionProfile = { + readonly fileSystem?: V2ItemGuardianApprovalReviewCompletedNotification__AdditionalFileSystemPermissions | null; + readonly network?: V2ItemGuardianApprovalReviewCompletedNotification__AdditionalNetworkPermissions | null; +}; +export const V2ItemGuardianApprovalReviewCompletedNotification__RequestPermissionProfile = + Schema.Struct({ + fileSystem: Schema.optionalKey( + Schema.Union([ + V2ItemGuardianApprovalReviewCompletedNotification__AdditionalFileSystemPermissions, + Schema.Null, + ]), + ), + network: Schema.optionalKey( + Schema.Union([ + V2ItemGuardianApprovalReviewCompletedNotification__AdditionalNetworkPermissions, + Schema.Null, + ]), + ), + }); + +export type V2ItemGuardianApprovalReviewStartedNotification__RequestPermissionProfile = { + readonly fileSystem?: V2ItemGuardianApprovalReviewStartedNotification__AdditionalFileSystemPermissions | null; + readonly network?: V2ItemGuardianApprovalReviewStartedNotification__AdditionalNetworkPermissions | null; +}; +export const V2ItemGuardianApprovalReviewStartedNotification__RequestPermissionProfile = + Schema.Struct({ + fileSystem: Schema.optionalKey( + Schema.Union([ + V2ItemGuardianApprovalReviewStartedNotification__AdditionalFileSystemPermissions, + Schema.Null, + ]), + ), + network: Schema.optionalKey( + Schema.Union([ + V2ItemGuardianApprovalReviewStartedNotification__AdditionalNetworkPermissions, + Schema.Null, + ]), + ), + }); + +export type McpServerElicitationRequestParams__McpElicitationSchema = { + readonly $schema?: string | null; + readonly properties: { + readonly [x: string]: McpServerElicitationRequestParams__McpElicitationPrimitiveSchema; + }; + readonly required?: ReadonlyArray | null; + readonly type: McpServerElicitationRequestParams__McpElicitationObjectType; +}; +export const McpServerElicitationRequestParams__McpElicitationSchema = Schema.Struct({ + $schema: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + properties: Schema.Record( + Schema.String, + McpServerElicitationRequestParams__McpElicitationPrimitiveSchema, + ), + required: Schema.optionalKey(Schema.Union([Schema.Array(Schema.String), Schema.Null])), + type: McpServerElicitationRequestParams__McpElicitationObjectType, +}).annotate({ + description: + "Typed form schema for MCP `elicitation/create` requests.\n\nThis matches the `requestedSchema` shape from the MCP 2025-11-25 `ElicitRequestFormParams` schema.", +}); + export type ServerNotification__GuardianApprovalReviewAction = | { readonly command: string; @@ -28925,13 +31787,6 @@ export const ServerNotification__GuardianApprovalReviewAction = Schema.Union( { mode: "oneOf" }, ); -export type ServerNotification__ThreadStartedNotification = { - readonly thread: ServerNotification__Thread; -}; -export const ServerNotification__ThreadStartedNotification = Schema.Struct({ - thread: ServerNotification__Thread, -}); - export type ServerRequest__PermissionsRequestApprovalParams = { readonly cwd: ServerRequest__AbsolutePathBuf; readonly environmentId?: string | null; @@ -28956,17 +31811,21 @@ export const ServerRequest__PermissionsRequestApprovalParams = Schema.Struct({ turnId: Schema.String, }); -export type ServerRequest__McpElicitationPrimitiveSchema = - | ServerRequest__McpElicitationEnumSchema - | ServerRequest__McpElicitationStringSchema - | ServerRequest__McpElicitationNumberSchema - | ServerRequest__McpElicitationBooleanSchema; -export const ServerRequest__McpElicitationPrimitiveSchema = Schema.Union([ - ServerRequest__McpElicitationEnumSchema, - ServerRequest__McpElicitationStringSchema, - ServerRequest__McpElicitationNumberSchema, - ServerRequest__McpElicitationBooleanSchema, -]); +export type ServerRequest__McpElicitationSchema = { + readonly $schema?: string | null; + readonly properties: { readonly [x: string]: ServerRequest__McpElicitationPrimitiveSchema }; + readonly required?: ReadonlyArray | null; + readonly type: ServerRequest__McpElicitationObjectType; +}; +export const ServerRequest__McpElicitationSchema = Schema.Struct({ + $schema: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + properties: Schema.Record(Schema.String, ServerRequest__McpElicitationPrimitiveSchema), + required: Schema.optionalKey(Schema.Union([Schema.Array(Schema.String), Schema.Null])), + type: ServerRequest__McpElicitationObjectType, +}).annotate({ + description: + "Typed form schema for MCP `elicitation/create` requests.\n\nThis matches the `requestedSchema` shape from the MCP 2025-11-25 `ElicitRequestFormParams` schema.", +}); export type V2ItemGuardianApprovalReviewCompletedNotification__GuardianApprovalReviewAction = | { @@ -29164,27 +32023,6 @@ export const V2ItemGuardianApprovalReviewStartedNotification__GuardianApprovalRe { mode: "oneOf" }, ); -export type McpServerElicitationRequestParams__McpElicitationSchema = { - readonly $schema?: string | null; - readonly properties: { - readonly [x: string]: McpServerElicitationRequestParams__McpElicitationPrimitiveSchema; - }; - readonly required?: ReadonlyArray | null; - readonly type: McpServerElicitationRequestParams__McpElicitationObjectType; -}; -export const McpServerElicitationRequestParams__McpElicitationSchema = Schema.Struct({ - $schema: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), - properties: Schema.Record( - Schema.String, - McpServerElicitationRequestParams__McpElicitationPrimitiveSchema, - ), - required: Schema.optionalKey(Schema.Union([Schema.Array(Schema.String), Schema.Null])), - type: McpServerElicitationRequestParams__McpElicitationObjectType, -}).annotate({ - description: - "Typed form schema for MCP `elicitation/create` requests.\n\nThis matches the `requestedSchema` shape from the MCP 2025-11-25 `ElicitRequestFormParams` schema.", -}); - export type ServerNotification__ItemGuardianApprovalReviewCompletedNotification = { readonly action: ServerNotification__GuardianApprovalReviewAction; readonly completedAtMs: number; @@ -29258,22 +32096,6 @@ export const ServerNotification__ItemGuardianApprovalReviewStartedNotification = "[UNSTABLE] Temporary notification payload for approval auto-review. This shape is expected to change soon.", }); -export type ServerRequest__McpElicitationSchema = { - readonly $schema?: string | null; - readonly properties: { readonly [x: string]: ServerRequest__McpElicitationPrimitiveSchema }; - readonly required?: ReadonlyArray | null; - readonly type: ServerRequest__McpElicitationObjectType; -}; -export const ServerRequest__McpElicitationSchema = Schema.Struct({ - $schema: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), - properties: Schema.Record(Schema.String, ServerRequest__McpElicitationPrimitiveSchema), - required: Schema.optionalKey(Schema.Union([Schema.Array(Schema.String), Schema.Null])), - type: ServerRequest__McpElicitationObjectType, -}).annotate({ - description: - "Typed form schema for MCP `elicitation/create` requests.\n\nThis matches the `requestedSchema` shape from the MCP 2025-11-25 `ElicitRequestFormParams` schema.", -}); - export type ServerRequest__McpServerElicitationRequestParams = | { readonly _meta?: unknown; @@ -29284,6 +32106,15 @@ export type ServerRequest__McpServerElicitationRequestParams = readonly threadId: string; readonly turnId?: string | null; } + | { + readonly _meta?: unknown; + readonly message: string; + readonly mode: "openai/form"; + readonly requestedSchema: unknown; + readonly serverName: string; + readonly threadId: string; + readonly turnId?: string | null; + } | { readonly _meta?: unknown; readonly elicitationId: string; @@ -29313,6 +32144,23 @@ export const ServerRequest__McpServerElicitationRequestParams = Schema.Union( ]), ), }), + Schema.Struct({ + _meta: Schema.optionalKey(Schema.Unknown), + message: Schema.String, + mode: Schema.Literal("openai/form"), + requestedSchema: Schema.Unknown, + serverName: Schema.String, + threadId: Schema.String, + turnId: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: + "Active Codex turn when this elicitation was observed, if app-server could correlate one.\n\nThis is nullable because MCP models elicitation as a standalone server-to-client request identified by the MCP server request id. It may be triggered during a turn, but turn context is app-server correlation rather than part of the protocol identity of the elicitation itself.", + }), + Schema.Null, + ]), + ), + }), Schema.Struct({ _meta: Schema.optionalKey(Schema.Unknown), elicitationId: Schema.String, @@ -29604,11 +32452,21 @@ export type ClientRequest = readonly method: "plugin/share/delete"; readonly params: ClientRequest__PluginShareDeleteParams; } + | { + readonly id: ClientRequest__RequestId; + readonly method: "app/read"; + readonly params: ClientRequest__AppsReadParams; + } | { readonly id: ClientRequest__RequestId; readonly method: "app/list"; readonly params: ClientRequest__AppsListParams; } + | { + readonly id: ClientRequest__RequestId; + readonly method: "app/installed"; + readonly params: ClientRequest__AppsInstalledParams; + } | { readonly id: ClientRequest__RequestId; readonly method: "fs/readFile"; @@ -29769,11 +32627,21 @@ export type ClientRequest = readonly method: "account/rateLimits/read"; readonly params?: null; } + | { + readonly id: ClientRequest__RequestId; + readonly method: "account/rateLimitResetCredit/consume"; + readonly params: ClientRequest__ConsumeAccountRateLimitResetCreditParams; + } | { readonly id: ClientRequest__RequestId; readonly method: "account/usage/read"; readonly params?: null; } + | { + readonly id: ClientRequest__RequestId; + readonly method: "account/workspaceMessages/read"; + readonly params?: null; + } | { readonly id: ClientRequest__RequestId; readonly method: "account/sendAddCreditsNudgeEmail"; @@ -29819,6 +32687,11 @@ export type ClientRequest = readonly method: "externalAgentConfig/import"; readonly params: ClientRequest__ExternalAgentConfigImportParams; } + | { + readonly id: ClientRequest__RequestId; + readonly method: "externalAgentConfig/import/readHistories"; + readonly params?: null; + } | { readonly id: ClientRequest__RequestId; readonly method: "config/value/write"; @@ -30068,11 +32941,21 @@ export const ClientRequest = Schema.Union( }), params: ClientRequest__PluginShareDeleteParams, }).annotate({ title: "Plugin/share/deleteRequest" }), + Schema.Struct({ + id: ClientRequest__RequestId, + method: Schema.Literal("app/read").annotate({ title: "App/readRequestMethod" }), + params: ClientRequest__AppsReadParams, + }).annotate({ title: "App/readRequest" }), Schema.Struct({ id: ClientRequest__RequestId, method: Schema.Literal("app/list").annotate({ title: "App/listRequestMethod" }), params: ClientRequest__AppsListParams, }).annotate({ title: "App/listRequest" }), + Schema.Struct({ + id: ClientRequest__RequestId, + method: Schema.Literal("app/installed").annotate({ title: "App/installedRequestMethod" }), + params: ClientRequest__AppsInstalledParams, + }).annotate({ title: "App/installedRequest" }), Schema.Struct({ id: ClientRequest__RequestId, method: Schema.Literal("fs/readFile").annotate({ title: "Fs/readFileRequestMethod" }), @@ -30269,6 +33152,13 @@ export const ClientRequest = Schema.Union( }), params: Schema.optionalKey(Schema.Null), }).annotate({ title: "Account/rateLimits/readRequest" }), + Schema.Struct({ + id: ClientRequest__RequestId, + method: Schema.Literal("account/rateLimitResetCredit/consume").annotate({ + title: "Account/rateLimitResetCredit/consumeRequestMethod", + }), + params: ClientRequest__ConsumeAccountRateLimitResetCreditParams, + }).annotate({ title: "Account/rateLimitResetCredit/consumeRequest" }), Schema.Struct({ id: ClientRequest__RequestId, method: Schema.Literal("account/usage/read").annotate({ @@ -30276,6 +33166,13 @@ export const ClientRequest = Schema.Union( }), params: Schema.optionalKey(Schema.Null), }).annotate({ title: "Account/usage/readRequest" }), + Schema.Struct({ + id: ClientRequest__RequestId, + method: Schema.Literal("account/workspaceMessages/read").annotate({ + title: "Account/workspaceMessages/readRequestMethod", + }), + params: Schema.optionalKey(Schema.Null), + }).annotate({ title: "Account/workspaceMessages/readRequest" }), Schema.Struct({ id: ClientRequest__RequestId, method: Schema.Literal("account/sendAddCreditsNudgeEmail").annotate({ @@ -30346,6 +33243,13 @@ export const ClientRequest = Schema.Union( }), params: ClientRequest__ExternalAgentConfigImportParams, }).annotate({ title: "ExternalAgentConfig/importRequest" }), + Schema.Struct({ + id: ClientRequest__RequestId, + method: Schema.Literal("externalAgentConfig/import/readHistories").annotate({ + title: "ExternalAgentConfig/import/readHistoriesRequestMethod", + }), + params: Schema.optionalKey(Schema.Null), + }).annotate({ title: "ExternalAgentConfig/import/readHistoriesRequest" }), Schema.Struct({ id: ClientRequest__RequestId, method: Schema.Literal("config/value/write").annotate({ @@ -30409,7 +33313,9 @@ export const ClientRequest__CapabilityRootLocation = Schema.Union( [ Schema.Struct({ environmentId: Schema.String, - path: Schema.String, + path: Schema.String.annotate({ + description: "Absolute path for the root in the selected environment.", + }), type: Schema.Literal("environment").annotate({ title: "EnvironmentCapabilityRootLocationType", }), @@ -30421,6 +33327,13 @@ export const ClientRequest__CapabilityRootLocation = Schema.Union( { mode: "oneOf" }, ).annotate({ description: "Location used to resolve a selected capability root." }); +export type ClientRequest__CodexResponseHandoffMode = "thinking" | "commentary" | "bemTags"; +export const ClientRequest__CodexResponseHandoffMode = Schema.Literals([ + "thinking", + "commentary", + "bemTags", +]); + export type ClientRequest__CollaborationMode = { readonly mode: ClientRequest__ModeKind; readonly settings: ClientRequest__Settings; @@ -30430,19 +33343,52 @@ export const ClientRequest__CollaborationMode = Schema.Struct({ settings: ClientRequest__Settings, }).annotate({ description: "Collaboration mode for a Codex session." }); -export type ClientRequest__DynamicToolSpec = { - readonly deferLoading?: boolean; - readonly description: string; - readonly inputSchema: unknown; - readonly name: string; - readonly namespace?: string | null; -}; -export const ClientRequest__DynamicToolSpec = Schema.Struct({ - deferLoading: Schema.optionalKey(Schema.Boolean), - description: Schema.String, - inputSchema: Schema.Unknown, - name: Schema.String, - namespace: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), +export type ClientRequest__DynamicToolSpec = + | { + readonly deferLoading?: boolean; + readonly description: string; + readonly inputSchema: unknown; + readonly name: string; + readonly type: "function"; + } + | { + readonly description: string; + readonly name: string; + readonly tools: ReadonlyArray; + readonly type: "namespace"; + }; +export const ClientRequest__DynamicToolSpec = Schema.Union( + [ + Schema.Struct({ + deferLoading: Schema.optionalKey(Schema.Boolean), + description: Schema.String, + inputSchema: Schema.Unknown, + name: Schema.String, + type: Schema.Literal("function").annotate({ title: "FunctionDynamicToolSpecType" }), + }).annotate({ title: "FunctionDynamicToolSpec" }), + Schema.Struct({ + description: Schema.String, + name: Schema.String, + tools: Schema.Array(ClientRequest__DynamicToolNamespaceTool), + type: Schema.Literal("namespace").annotate({ title: "NamespaceDynamicToolSpecType" }), + }).annotate({ title: "NamespaceDynamicToolSpec" }), + ], + { mode: "oneOf" }, +); + +export type ClientRequest__MultiAgentMode = + | "explicitRequestOnly" + | "proactive" + | { readonly custom: string }; +export const ClientRequest__MultiAgentMode = Schema.Union( + [ + Schema.Literals(["explicitRequestOnly", "proactive"]), + Schema.Struct({ custom: Schema.String }).annotate({ title: "CustomMultiAgentMode" }), + ], + { mode: "oneOf" }, +).annotate({ + description: + "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 ClientRequest__NetworkAccess = "restricted" | "enabled"; @@ -30464,8 +33410,8 @@ export const ClientRequest__ProcessTerminalSize = Schema.Struct({ .check(Schema.isGreaterThanOrEqualTo(0)), }).annotate({ description: "PTY size in character cells for `process/spawn` PTY sessions." }); -export type ClientRequest__RealtimeConversationVersion = "v1" | "v2"; -export const ClientRequest__RealtimeConversationVersion = Schema.Literals(["v1", "v2"]); +export type ClientRequest__RealtimeConversationVersion = "v1" | "v2" | "v3"; +export const ClientRequest__RealtimeConversationVersion = Schema.Literals(["v1", "v2", "v3"]); export type ClientRequest__RealtimeOutputModality = "text" | "audio"; export const ClientRequest__RealtimeOutputModality = Schema.Literals(["text", "audio"]); @@ -30512,10 +33458,21 @@ export const ClientRequest__RealtimeVoice = Schema.Literals([ "verse", ]); +export type ClientRequest__RemoteControlDisableParams = { readonly ephemeral?: boolean }; +export const ClientRequest__RemoteControlDisableParams = Schema.Struct({ + ephemeral: Schema.optionalKey(Schema.Boolean), +}); + +export type ClientRequest__RemoteControlEnableParams = { readonly ephemeral?: boolean }; +export const ClientRequest__RemoteControlEnableParams = Schema.Struct({ + ephemeral: Schema.optionalKey(Schema.Boolean), +}); + export type ClientRequest__ResponseItem = | { readonly content: ReadonlyArray; readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: ClientRequest__InternalChatMessageMetadataPassthrough | null; readonly phase?: ClientRequest__MessagePhase | null; readonly role: string; readonly type: "message"; @@ -30523,12 +33480,16 @@ export type ClientRequest__ResponseItem = | { readonly author: string; readonly content: ReadonlyArray; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: ClientRequest__InternalChatMessageMetadataPassthrough | null; readonly recipient: string; readonly type: "agent_message"; } | { readonly content?: ReadonlyArray | null; readonly encrypted_content?: string | null; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: ClientRequest__InternalChatMessageMetadataPassthrough | null; readonly summary: ReadonlyArray; readonly type: "reasoning"; } @@ -30536,6 +33497,7 @@ export type ClientRequest__ResponseItem = readonly action: ClientRequest__LocalShellAction; readonly call_id?: string | null; readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: ClientRequest__InternalChatMessageMetadataPassthrough | null; readonly status: ClientRequest__LocalShellStatus; readonly type: "local_shell_call"; } @@ -30543,6 +33505,7 @@ export type ClientRequest__ResponseItem = readonly arguments: string; readonly call_id: string; readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: ClientRequest__InternalChatMessageMetadataPassthrough | null; readonly name: string; readonly namespace?: string | null; readonly type: "function_call"; @@ -30552,11 +33515,14 @@ export type ClientRequest__ResponseItem = readonly call_id?: string | null; readonly execution: string; readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: ClientRequest__InternalChatMessageMetadataPassthrough | null; readonly status?: string | null; readonly type: "tool_search_call"; } | { readonly call_id: string; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: ClientRequest__InternalChatMessageMetadataPassthrough | null; readonly output: ClientRequest__FunctionCallOutputBody; readonly type: "function_call_output"; } @@ -30564,12 +33530,16 @@ export type ClientRequest__ResponseItem = readonly call_id: string; readonly id?: string | null; readonly input: string; + readonly internal_chat_message_metadata_passthrough?: ClientRequest__InternalChatMessageMetadataPassthrough | null; readonly name: string; + readonly namespace?: string | null; readonly status?: string | null; readonly type: "custom_tool_call"; } | { readonly call_id: string; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: ClientRequest__InternalChatMessageMetadataPassthrough | null; readonly name?: string | null; readonly output: ClientRequest__FunctionCallOutputBody; readonly type: "custom_tool_call_output"; @@ -30577,6 +33547,8 @@ export type ClientRequest__ResponseItem = | { readonly call_id?: string | null; readonly execution: string; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: ClientRequest__InternalChatMessageMetadataPassthrough | null; readonly status: string; readonly tools: ReadonlyArray; readonly type: "tool_search_output"; @@ -30584,26 +33556,39 @@ export type ClientRequest__ResponseItem = | { readonly action?: ClientRequest__ResponsesApiWebSearchAction | null; readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: ClientRequest__InternalChatMessageMetadataPassthrough | null; readonly status?: string | null; readonly type: "web_search_call"; } | { - readonly id: string; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: ClientRequest__InternalChatMessageMetadataPassthrough | null; readonly result: string; readonly revised_prompt?: string | null; readonly status: string; readonly type: "image_generation_call"; } - | { readonly encrypted_content: string; readonly type: "compaction" } + | { + readonly encrypted_content: string; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: ClientRequest__InternalChatMessageMetadataPassthrough | null; + readonly type: "compaction"; + } | { readonly type: "compaction_trigger" } - | { readonly encrypted_content?: string | null; readonly type: "context_compaction" } + | { + readonly encrypted_content?: string | null; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: ClientRequest__InternalChatMessageMetadataPassthrough | null; + readonly type: "context_compaction"; + } | { readonly type: "other" }; export const ClientRequest__ResponseItem = Schema.Union( [ Schema.Struct({ content: Schema.Array(ClientRequest__ContentItem), - id: Schema.optionalKey( - Schema.Union([Schema.String.annotate({ writeOnly: true }), Schema.Null]), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ClientRequest__InternalChatMessageMetadataPassthrough, Schema.Null]), ), phase: Schema.optionalKey(Schema.Union([ClientRequest__MessagePhase, Schema.Null])), role: Schema.String, @@ -30612,6 +33597,10 @@ export const ClientRequest__ResponseItem = Schema.Union( Schema.Struct({ author: Schema.String, content: Schema.Array(ClientRequest__AgentMessageInputContent), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ClientRequest__InternalChatMessageMetadataPassthrough, Schema.Null]), + ), recipient: Schema.String, type: Schema.Literal("agent_message").annotate({ title: "AgentMessageResponseItemType" }), }).annotate({ title: "AgentMessageResponseItem" }), @@ -30620,6 +33609,10 @@ export const ClientRequest__ResponseItem = Schema.Union( Schema.Union([Schema.Array(ClientRequest__ReasoningItemContent), Schema.Null]), ), encrypted_content: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ClientRequest__InternalChatMessageMetadataPassthrough, Schema.Null]), + ), summary: Schema.Array(ClientRequest__ReasoningItemReasoningSummary), type: Schema.Literal("reasoning").annotate({ title: "ReasoningResponseItemType" }), }).annotate({ title: "ReasoningResponseItem" }), @@ -30635,11 +33628,13 @@ export const ClientRequest__ResponseItem = Schema.Union( Schema.Union([ Schema.String.annotate({ description: "Legacy id field retained for compatibility with older payloads.", - writeOnly: true, }), Schema.Null, ]), ), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ClientRequest__InternalChatMessageMetadataPassthrough, Schema.Null]), + ), status: ClientRequest__LocalShellStatus, type: Schema.Literal("local_shell_call").annotate({ title: "LocalShellCallResponseItemType", @@ -30648,8 +33643,9 @@ export const ClientRequest__ResponseItem = Schema.Union( Schema.Struct({ arguments: Schema.String, call_id: Schema.String, - id: Schema.optionalKey( - Schema.Union([Schema.String.annotate({ writeOnly: true }), Schema.Null]), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ClientRequest__InternalChatMessageMetadataPassthrough, Schema.Null]), ), name: Schema.String, namespace: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), @@ -30659,8 +33655,9 @@ export const ClientRequest__ResponseItem = Schema.Union( arguments: Schema.Unknown, call_id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), execution: Schema.String, - id: Schema.optionalKey( - Schema.Union([Schema.String.annotate({ writeOnly: true }), Schema.Null]), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ClientRequest__InternalChatMessageMetadataPassthrough, Schema.Null]), ), status: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), type: Schema.Literal("tool_search_call").annotate({ @@ -30669,6 +33666,10 @@ export const ClientRequest__ResponseItem = Schema.Union( }).annotate({ title: "ToolSearchCallResponseItem" }), Schema.Struct({ call_id: Schema.String, + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ClientRequest__InternalChatMessageMetadataPassthrough, Schema.Null]), + ), output: ClientRequest__FunctionCallOutputBody, type: Schema.Literal("function_call_output").annotate({ title: "FunctionCallOutputResponseItemType", @@ -30676,11 +33677,13 @@ export const ClientRequest__ResponseItem = Schema.Union( }).annotate({ title: "FunctionCallOutputResponseItem" }), Schema.Struct({ call_id: Schema.String, - id: Schema.optionalKey( - Schema.Union([Schema.String.annotate({ writeOnly: true }), Schema.Null]), - ), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), input: Schema.String, + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ClientRequest__InternalChatMessageMetadataPassthrough, Schema.Null]), + ), name: Schema.String, + namespace: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), status: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), type: Schema.Literal("custom_tool_call").annotate({ title: "CustomToolCallResponseItemType", @@ -30688,6 +33691,10 @@ export const ClientRequest__ResponseItem = Schema.Union( }).annotate({ title: "CustomToolCallResponseItem" }), Schema.Struct({ call_id: Schema.String, + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ClientRequest__InternalChatMessageMetadataPassthrough, Schema.Null]), + ), name: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), output: ClientRequest__FunctionCallOutputBody, type: Schema.Literal("custom_tool_call_output").annotate({ @@ -30697,6 +33704,10 @@ export const ClientRequest__ResponseItem = Schema.Union( Schema.Struct({ call_id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), execution: Schema.String, + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ClientRequest__InternalChatMessageMetadataPassthrough, Schema.Null]), + ), status: Schema.String, tools: Schema.Array(Schema.Unknown), type: Schema.Literal("tool_search_output").annotate({ @@ -30707,14 +33718,18 @@ export const ClientRequest__ResponseItem = Schema.Union( action: Schema.optionalKey( Schema.Union([ClientRequest__ResponsesApiWebSearchAction, Schema.Null]), ), - id: Schema.optionalKey( - Schema.Union([Schema.String.annotate({ writeOnly: true }), Schema.Null]), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ClientRequest__InternalChatMessageMetadataPassthrough, Schema.Null]), ), status: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), type: Schema.Literal("web_search_call").annotate({ title: "WebSearchCallResponseItemType" }), }).annotate({ title: "WebSearchCallResponseItem" }), Schema.Struct({ - id: Schema.String, + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ClientRequest__InternalChatMessageMetadataPassthrough, Schema.Null]), + ), result: Schema.String, revised_prompt: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), status: Schema.String, @@ -30724,6 +33739,10 @@ export const ClientRequest__ResponseItem = Schema.Union( }).annotate({ title: "ImageGenerationCallResponseItem" }), Schema.Struct({ encrypted_content: Schema.String, + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ClientRequest__InternalChatMessageMetadataPassthrough, Schema.Null]), + ), type: Schema.Literal("compaction").annotate({ title: "CompactionResponseItemType" }), }).annotate({ title: "CompactionResponseItem" }), Schema.Struct({ @@ -30733,6 +33752,10 @@ export const ClientRequest__ResponseItem = Schema.Union( }).annotate({ title: "CompactionTriggerResponseItem" }), Schema.Struct({ encrypted_content: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([ClientRequest__InternalChatMessageMetadataPassthrough, Schema.Null]), + ), type: Schema.Literal("context_compaction").annotate({ title: "ContextCompactionResponseItemType", }), @@ -30760,7 +33783,9 @@ export const ClientRequest__SelectedCapabilityRoot = Schema.Struct({ [ Schema.Struct({ environmentId: Schema.String, - path: Schema.String, + path: Schema.String.annotate({ + description: "Absolute path for the root in the selected environment.", + }), type: Schema.Literal("environment").annotate({ title: "EnvironmentCapabilityRootLocationType", }), @@ -30775,6 +33800,9 @@ export const ClientRequest__SelectedCapabilityRoot = Schema.Struct({ description: "A user-selected root that can expose one or more runtime capabilities.", }); +export type ClientRequest__ThreadHistoryMode = "legacy" | "paginated"; +export const ClientRequest__ThreadHistoryMode = Schema.Literals(["legacy", "paginated"]); + export type ClientRequest__ThreadMemoryMode = "enabled" | "disabled"; export const ClientRequest__ThreadMemoryMode = Schema.Literals(["enabled", "disabled"]); @@ -30804,6 +33832,17 @@ export const ClientRequest__ThreadRealtimeAudioChunk = Schema.Struct({ ), }).annotate({ description: "EXPERIMENTAL - thread realtime audio chunk." }); +export type ClientRequest__ThreadRealtimeInitialItem = { + readonly role: ClientRequest__ConversationTextRole; + readonly text: string; +}; +export const ClientRequest__ThreadRealtimeInitialItem = Schema.Struct({ + role: ClientRequest__ConversationTextRole, + text: Schema.String, +}).annotate({ + description: "EXPERIMENTAL - role-bearing text item included when a realtime V3 session starts.", +}); + export type ClientRequest__ThreadRealtimeStartTransport = | { readonly type: "websocket" } | { readonly sdp: string; readonly type: "webrtc" }; @@ -30852,19 +33891,29 @@ export const ClientRequest__ThreadResumeInitialTurnsPageParams = Schema.Struct({ }); export type ClientRequest__TurnEnvironmentParams = { - readonly cwd: ClientRequest__AbsolutePathBuf; + readonly cwd: ClientRequest__LegacyAppPathString; readonly environmentId: string; + readonly runtimeWorkspaceRoots?: ReadonlyArray | null; }; export const ClientRequest__TurnEnvironmentParams = Schema.Struct({ - cwd: ClientRequest__AbsolutePathBuf, + cwd: ClientRequest__LegacyAppPathString, environmentId: Schema.String, + runtimeWorkspaceRoots: Schema.optionalKey( + Schema.Union([ + Schema.Array(ClientRequest__LegacyAppPathString).annotate({ + description: "Environment-native runtime workspace roots. Omitted defaults to `cwd`.", + }), + Schema.Null, + ]), + ), }); export type CommandExecutionRequestApprovalParams = { readonly approvalId?: string | null; readonly command?: string | null; readonly commandActions?: ReadonlyArray | null; - readonly cwd?: CommandExecutionRequestApprovalParams__AbsolutePathBuf | null; + readonly cwd?: CommandExecutionRequestApprovalParams__LegacyAppPathString | null; + readonly environmentId?: string | null; readonly itemId: string; readonly networkApprovalContext?: CommandExecutionRequestApprovalParams__NetworkApprovalContext | null; readonly proposedExecpolicyAmendment?: ReadonlyArray | null; @@ -30899,9 +33948,16 @@ export const CommandExecutionRequestApprovalParams = Schema.Struct({ ]), ), cwd: Schema.optionalKey( - Schema.Union([CommandExecutionRequestApprovalParams__AbsolutePathBuf, Schema.Null]).annotate({ - description: "The command's working directory.", - }), + Schema.Union([ + CommandExecutionRequestApprovalParams__LegacyAppPathString, + Schema.Null, + ]).annotate({ description: "The command's working directory." }), + ), + environmentId: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ description: "Environment in which the command will run." }), + Schema.Null, + ]), ), itemId: Schema.String, networkApprovalContext: Schema.optionalKey( @@ -31283,6 +34339,15 @@ export type McpServerElicitationRequestParams = readonly threadId: string; readonly turnId?: string | null; } + | { + readonly _meta?: unknown; + readonly message: string; + readonly mode: "openai/form"; + readonly requestedSchema: unknown; + readonly serverName: string; + readonly threadId: string; + readonly turnId?: string | null; + } | { readonly _meta?: unknown; readonly elicitationId: string; @@ -31312,6 +34377,23 @@ export const McpServerElicitationRequestParams = Schema.Union( ]), ), }).annotate({ title: "McpServerElicitationRequestParams" }), + Schema.Struct({ + _meta: Schema.optionalKey(Schema.Unknown), + message: Schema.String, + mode: Schema.Literal("openai/form"), + requestedSchema: Schema.Unknown, + serverName: Schema.String, + threadId: Schema.String, + turnId: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: + "Active Codex turn when this elicitation was observed, if app-server could correlate one.\n\nThis is nullable because MCP models elicitation as a standalone server-to-client request identified by the MCP server request id. It may be triggered during a turn, but turn context is app-server correlation rather than part of the protocol identity of the elicitation itself.", + }), + Schema.Null, + ]), + ), + }).annotate({ title: "McpServerElicitationRequestParams" }), Schema.Struct({ _meta: Schema.optionalKey(Schema.Unknown), elicitationId: Schema.String, @@ -31410,677 +34492,1469 @@ export const RequestId = Schema.Union([ ]).annotate({ title: "RequestId" }); export type ServerNotification = - | { readonly method: "error"; readonly params: ServerNotification__ErrorNotification } + | { + readonly method: "error"; + readonly params: ServerNotification__ErrorNotification; + readonly emittedAtMs?: number; + } | { readonly method: "thread/started"; readonly params: ServerNotification__ThreadStartedNotification; + readonly emittedAtMs?: number; } | { readonly method: "thread/status/changed"; readonly params: ServerNotification__ThreadStatusChangedNotification; + readonly emittedAtMs?: number; } | { readonly method: "thread/archived"; readonly params: ServerNotification__ThreadArchivedNotification; + readonly emittedAtMs?: number; } | { readonly method: "thread/deleted"; readonly params: ServerNotification__ThreadDeletedNotification; + readonly emittedAtMs?: number; } | { readonly method: "thread/unarchived"; readonly params: ServerNotification__ThreadUnarchivedNotification; + readonly emittedAtMs?: number; } | { readonly method: "thread/closed"; readonly params: ServerNotification__ThreadClosedNotification; + readonly emittedAtMs?: number; } | { readonly method: "skills/changed"; readonly params: ServerNotification__SkillsChangedNotification; + readonly emittedAtMs?: number; } | { readonly method: "thread/name/updated"; readonly params: ServerNotification__ThreadNameUpdatedNotification; + readonly emittedAtMs?: number; } | { readonly method: "thread/goal/updated"; readonly params: ServerNotification__ThreadGoalUpdatedNotification; + readonly emittedAtMs?: number; } | { readonly method: "thread/goal/cleared"; readonly params: ServerNotification__ThreadGoalClearedNotification; + readonly emittedAtMs?: number; + } + | { + readonly method: "thread/environment/connected"; + readonly params: ServerNotification__EnvironmentConnectionNotification; + readonly emittedAtMs?: number; + } + | { + readonly method: "thread/environment/disconnected"; + readonly params: ServerNotification__EnvironmentConnectionNotification; + readonly emittedAtMs?: number; } | { readonly method: "thread/settings/updated"; readonly params: ServerNotification__ThreadSettingsUpdatedNotification; + readonly emittedAtMs?: number; } | { readonly method: "thread/tokenUsage/updated"; readonly params: ServerNotification__ThreadTokenUsageUpdatedNotification; + readonly emittedAtMs?: number; } | { readonly method: "turn/started"; readonly params: ServerNotification__TurnStartedNotification; + readonly emittedAtMs?: number; } | { readonly method: "hook/started"; readonly params: ServerNotification__HookStartedNotification; + readonly emittedAtMs?: number; } | { readonly method: "turn/completed"; readonly params: ServerNotification__TurnCompletedNotification; + readonly emittedAtMs?: number; } | { readonly method: "hook/completed"; readonly params: ServerNotification__HookCompletedNotification; + readonly emittedAtMs?: number; } | { readonly method: "turn/diff/updated"; readonly params: ServerNotification__TurnDiffUpdatedNotification; + readonly emittedAtMs?: number; } | { readonly method: "turn/plan/updated"; readonly params: ServerNotification__TurnPlanUpdatedNotification; + readonly emittedAtMs?: number; } | { readonly method: "item/started"; readonly params: ServerNotification__ItemStartedNotification; + readonly emittedAtMs?: number; } | { readonly method: "item/autoApprovalReview/started"; readonly params: ServerNotification__ItemGuardianApprovalReviewStartedNotification; + readonly emittedAtMs?: number; } | { readonly method: "item/autoApprovalReview/completed"; readonly params: ServerNotification__ItemGuardianApprovalReviewCompletedNotification; + readonly emittedAtMs?: number; } | { readonly method: "item/completed"; readonly params: ServerNotification__ItemCompletedNotification; + readonly emittedAtMs?: number; } | { readonly method: "item/agentMessage/delta"; readonly params: ServerNotification__AgentMessageDeltaNotification; + readonly emittedAtMs?: number; } | { readonly method: "item/plan/delta"; readonly params: ServerNotification__PlanDeltaNotification; + readonly emittedAtMs?: number; } | { readonly method: "command/exec/outputDelta"; readonly params: ServerNotification__CommandExecOutputDeltaNotification; + readonly emittedAtMs?: number; } | { readonly method: "process/outputDelta"; readonly params: ServerNotification__ProcessOutputDeltaNotification; + readonly emittedAtMs?: number; } | { readonly method: "process/exited"; readonly params: ServerNotification__ProcessExitedNotification; + readonly emittedAtMs?: number; } | { readonly method: "item/commandExecution/outputDelta"; readonly params: ServerNotification__CommandExecutionOutputDeltaNotification; + readonly emittedAtMs?: number; } | { readonly method: "item/commandExecution/terminalInteraction"; readonly params: ServerNotification__TerminalInteractionNotification; + readonly emittedAtMs?: number; } | { readonly method: "item/fileChange/outputDelta"; readonly params: ServerNotification__FileChangeOutputDeltaNotification; + readonly emittedAtMs?: number; } | { readonly method: "item/fileChange/patchUpdated"; readonly params: ServerNotification__FileChangePatchUpdatedNotification; + readonly emittedAtMs?: number; } | { readonly method: "serverRequest/resolved"; readonly params: ServerNotification__ServerRequestResolvedNotification; + readonly emittedAtMs?: number; } | { readonly method: "item/mcpToolCall/progress"; readonly params: ServerNotification__McpToolCallProgressNotification; + readonly emittedAtMs?: number; } | { readonly method: "mcpServer/oauthLogin/completed"; readonly params: ServerNotification__McpServerOauthLoginCompletedNotification; + readonly emittedAtMs?: number; } | { readonly method: "mcpServer/startupStatus/updated"; readonly params: ServerNotification__McpServerStatusUpdatedNotification; + readonly emittedAtMs?: number; } | { readonly method: "account/updated"; readonly params: ServerNotification__AccountUpdatedNotification; + readonly emittedAtMs?: number; } | { readonly method: "account/rateLimits/updated"; readonly params: ServerNotification__AccountRateLimitsUpdatedNotification; + readonly emittedAtMs?: number; } | { readonly method: "app/list/updated"; readonly params: ServerNotification__AppListUpdatedNotification; + readonly emittedAtMs?: number; } | { readonly method: "remoteControl/status/changed"; readonly params: ServerNotification__RemoteControlStatusChangedNotification; + readonly emittedAtMs?: number; + } + | { + readonly method: "externalAgentConfig/import/progress"; + readonly params: ServerNotification__ExternalAgentConfigImportProgressNotification; + readonly emittedAtMs?: number; } | { readonly method: "externalAgentConfig/import/completed"; readonly params: ServerNotification__ExternalAgentConfigImportCompletedNotification; + readonly emittedAtMs?: number; + } + | { + readonly method: "fs/changed"; + readonly params: ServerNotification__FsChangedNotification; + readonly emittedAtMs?: number; } - | { readonly method: "fs/changed"; readonly params: ServerNotification__FsChangedNotification } | { readonly method: "item/reasoning/summaryTextDelta"; readonly params: ServerNotification__ReasoningSummaryTextDeltaNotification; + readonly emittedAtMs?: number; } | { readonly method: "item/reasoning/summaryPartAdded"; readonly params: ServerNotification__ReasoningSummaryPartAddedNotification; + readonly emittedAtMs?: number; } | { readonly method: "item/reasoning/textDelta"; readonly params: ServerNotification__ReasoningTextDeltaNotification; + readonly emittedAtMs?: number; } | { readonly method: "thread/compacted"; readonly params: ServerNotification__ContextCompactedNotification; + readonly emittedAtMs?: number; } | { readonly method: "model/rerouted"; readonly params: ServerNotification__ModelReroutedNotification; + readonly emittedAtMs?: number; } | { readonly method: "model/verification"; readonly params: ServerNotification__ModelVerificationNotification; + readonly emittedAtMs?: number; } | { readonly method: "turn/moderationMetadata"; readonly params: ServerNotification__TurnModerationMetadataNotification; + readonly emittedAtMs?: number; + } + | { + readonly method: "model/safetyBuffering/updated"; + readonly params: ServerNotification__ModelSafetyBufferingUpdatedNotification; + readonly emittedAtMs?: number; + } + | { + readonly method: "warning"; + readonly params: ServerNotification__WarningNotification; + readonly emittedAtMs?: number; } - | { readonly method: "warning"; readonly params: ServerNotification__WarningNotification } | { readonly method: "guardianWarning"; readonly params: ServerNotification__GuardianWarningNotification; + readonly emittedAtMs?: number; } | { readonly method: "deprecationNotice"; readonly params: ServerNotification__DeprecationNoticeNotification; + readonly emittedAtMs?: number; } | { readonly method: "configWarning"; readonly params: ServerNotification__ConfigWarningNotification; + readonly emittedAtMs?: number; } | { readonly method: "fuzzyFileSearch/sessionUpdated"; readonly params: ServerNotification__FuzzyFileSearchSessionUpdatedNotification; + readonly emittedAtMs?: number; } | { readonly method: "fuzzyFileSearch/sessionCompleted"; readonly params: ServerNotification__FuzzyFileSearchSessionCompletedNotification; + readonly emittedAtMs?: number; } | { readonly method: "thread/realtime/started"; readonly params: ServerNotification__ThreadRealtimeStartedNotification; + readonly emittedAtMs?: number; } | { readonly method: "thread/realtime/itemAdded"; readonly params: ServerNotification__ThreadRealtimeItemAddedNotification; + readonly emittedAtMs?: number; } | { readonly method: "thread/realtime/transcript/delta"; readonly params: ServerNotification__ThreadRealtimeTranscriptDeltaNotification; + readonly emittedAtMs?: number; } | { readonly method: "thread/realtime/transcript/done"; readonly params: ServerNotification__ThreadRealtimeTranscriptDoneNotification; + readonly emittedAtMs?: number; } | { readonly method: "thread/realtime/outputAudio/delta"; readonly params: ServerNotification__ThreadRealtimeOutputAudioDeltaNotification; + readonly emittedAtMs?: number; } | { readonly method: "thread/realtime/sdp"; readonly params: ServerNotification__ThreadRealtimeSdpNotification; + readonly emittedAtMs?: number; } | { readonly method: "thread/realtime/error"; readonly params: ServerNotification__ThreadRealtimeErrorNotification; + readonly emittedAtMs?: number; } | { readonly method: "thread/realtime/closed"; readonly params: ServerNotification__ThreadRealtimeClosedNotification; + readonly emittedAtMs?: number; } | { readonly method: "windows/worldWritableWarning"; readonly params: ServerNotification__WindowsWorldWritableWarningNotification; + readonly emittedAtMs?: number; } | { readonly method: "windowsSandbox/setupCompleted"; readonly params: ServerNotification__WindowsSandboxSetupCompletedNotification; + readonly emittedAtMs?: number; } | { readonly method: "account/login/completed"; readonly params: ServerNotification__AccountLoginCompletedNotification; + readonly emittedAtMs?: number; }; export const ServerNotification = Schema.Union( [ Schema.Struct({ method: Schema.Literal("error").annotate({ title: "ErrorNotificationMethod" }), params: ServerNotification__ErrorNotification, - }).annotate({ title: "ErrorNotification", description: "NEW NOTIFICATIONS" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("thread/started").annotate({ title: "Thread/startedNotificationMethod", }), params: ServerNotification__ThreadStartedNotification, - }).annotate({ title: "Thread/startedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("thread/status/changed").annotate({ title: "Thread/status/changedNotificationMethod", }), params: ServerNotification__ThreadStatusChangedNotification, - }).annotate({ title: "Thread/status/changedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("thread/archived").annotate({ title: "Thread/archivedNotificationMethod", }), params: ServerNotification__ThreadArchivedNotification, - }).annotate({ title: "Thread/archivedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("thread/deleted").annotate({ title: "Thread/deletedNotificationMethod", }), params: ServerNotification__ThreadDeletedNotification, - }).annotate({ title: "Thread/deletedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("thread/unarchived").annotate({ title: "Thread/unarchivedNotificationMethod", }), params: ServerNotification__ThreadUnarchivedNotification, - }).annotate({ title: "Thread/unarchivedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("thread/closed").annotate({ title: "Thread/closedNotificationMethod", }), params: ServerNotification__ThreadClosedNotification, - }).annotate({ title: "Thread/closedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("skills/changed").annotate({ title: "Skills/changedNotificationMethod", }), params: ServerNotification__SkillsChangedNotification, - }).annotate({ title: "Skills/changedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("thread/name/updated").annotate({ title: "Thread/name/updatedNotificationMethod", }), params: ServerNotification__ThreadNameUpdatedNotification, - }).annotate({ title: "Thread/name/updatedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("thread/goal/updated").annotate({ title: "Thread/goal/updatedNotificationMethod", }), params: ServerNotification__ThreadGoalUpdatedNotification, - }).annotate({ title: "Thread/goal/updatedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("thread/goal/cleared").annotate({ title: "Thread/goal/clearedNotificationMethod", }), params: ServerNotification__ThreadGoalClearedNotification, - }).annotate({ title: "Thread/goal/clearedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), + Schema.Struct({ + method: Schema.Literal("thread/environment/connected").annotate({ + title: "Thread/environment/connectedNotificationMethod", + }), + params: ServerNotification__EnvironmentConnectionNotification, + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), + Schema.Struct({ + method: Schema.Literal("thread/environment/disconnected").annotate({ + title: "Thread/environment/disconnectedNotificationMethod", + }), + params: ServerNotification__EnvironmentConnectionNotification, + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("thread/settings/updated").annotate({ title: "Thread/settings/updatedNotificationMethod", }), params: ServerNotification__ThreadSettingsUpdatedNotification, - }).annotate({ title: "Thread/settings/updatedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("thread/tokenUsage/updated").annotate({ title: "Thread/tokenUsage/updatedNotificationMethod", }), params: ServerNotification__ThreadTokenUsageUpdatedNotification, - }).annotate({ title: "Thread/tokenUsage/updatedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("turn/started").annotate({ title: "Turn/startedNotificationMethod" }), params: ServerNotification__TurnStartedNotification, - }).annotate({ title: "Turn/startedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("hook/started").annotate({ title: "Hook/startedNotificationMethod" }), params: ServerNotification__HookStartedNotification, - }).annotate({ title: "Hook/startedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("turn/completed").annotate({ title: "Turn/completedNotificationMethod", }), params: ServerNotification__TurnCompletedNotification, - }).annotate({ title: "Turn/completedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("hook/completed").annotate({ title: "Hook/completedNotificationMethod", }), params: ServerNotification__HookCompletedNotification, - }).annotate({ title: "Hook/completedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("turn/diff/updated").annotate({ title: "Turn/diff/updatedNotificationMethod", }), params: ServerNotification__TurnDiffUpdatedNotification, - }).annotate({ title: "Turn/diff/updatedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("turn/plan/updated").annotate({ title: "Turn/plan/updatedNotificationMethod", }), params: ServerNotification__TurnPlanUpdatedNotification, - }).annotate({ title: "Turn/plan/updatedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("item/started").annotate({ title: "Item/startedNotificationMethod" }), params: ServerNotification__ItemStartedNotification, - }).annotate({ title: "Item/startedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("item/autoApprovalReview/started").annotate({ title: "Item/autoApprovalReview/startedNotificationMethod", }), params: ServerNotification__ItemGuardianApprovalReviewStartedNotification, - }).annotate({ title: "Item/autoApprovalReview/startedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("item/autoApprovalReview/completed").annotate({ title: "Item/autoApprovalReview/completedNotificationMethod", }), params: ServerNotification__ItemGuardianApprovalReviewCompletedNotification, - }).annotate({ title: "Item/autoApprovalReview/completedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("item/completed").annotate({ title: "Item/completedNotificationMethod", }), params: ServerNotification__ItemCompletedNotification, - }).annotate({ title: "Item/completedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("item/agentMessage/delta").annotate({ title: "Item/agentMessage/deltaNotificationMethod", }), params: ServerNotification__AgentMessageDeltaNotification, - }).annotate({ title: "Item/agentMessage/deltaNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("item/plan/delta").annotate({ title: "Item/plan/deltaNotificationMethod", }), params: ServerNotification__PlanDeltaNotification, + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), }).annotate({ - title: "Item/plan/deltaNotification", - description: "EXPERIMENTAL - proposed plan streaming deltas for plan items.", + title: "ServerNotification", + description: "Notification sent from the server to the client.", }), Schema.Struct({ method: Schema.Literal("command/exec/outputDelta").annotate({ title: "Command/exec/outputDeltaNotificationMethod", }), params: ServerNotification__CommandExecOutputDeltaNotification, + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), }).annotate({ - title: "Command/exec/outputDeltaNotification", - description: - "Stream base64-encoded stdout/stderr chunks for a running `command/exec` session.", + title: "ServerNotification", + description: "Notification sent from the server to the client.", }), Schema.Struct({ method: Schema.Literal("process/outputDelta").annotate({ title: "Process/outputDeltaNotificationMethod", }), params: ServerNotification__ProcessOutputDeltaNotification, + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), }).annotate({ - title: "Process/outputDeltaNotification", - description: - "Stream base64-encoded stdout/stderr chunks for a running `process/spawn` session.", + title: "ServerNotification", + description: "Notification sent from the server to the client.", }), Schema.Struct({ method: Schema.Literal("process/exited").annotate({ title: "Process/exitedNotificationMethod", }), params: ServerNotification__ProcessExitedNotification, + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), }).annotate({ - title: "Process/exitedNotification", - description: "Final exit notification for a `process/spawn` session.", + title: "ServerNotification", + description: "Notification sent from the server to the client.", }), Schema.Struct({ method: Schema.Literal("item/commandExecution/outputDelta").annotate({ title: "Item/commandExecution/outputDeltaNotificationMethod", }), params: ServerNotification__CommandExecutionOutputDeltaNotification, - }).annotate({ title: "Item/commandExecution/outputDeltaNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("item/commandExecution/terminalInteraction").annotate({ title: "Item/commandExecution/terminalInteractionNotificationMethod", }), params: ServerNotification__TerminalInteractionNotification, - }).annotate({ title: "Item/commandExecution/terminalInteractionNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("item/fileChange/outputDelta").annotate({ title: "Item/fileChange/outputDeltaNotificationMethod", }), params: ServerNotification__FileChangeOutputDeltaNotification, + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), }).annotate({ - title: "Item/fileChange/outputDeltaNotification", - description: "Deprecated legacy apply_patch output stream notification.", + title: "ServerNotification", + description: "Notification sent from the server to the client.", }), Schema.Struct({ method: Schema.Literal("item/fileChange/patchUpdated").annotate({ title: "Item/fileChange/patchUpdatedNotificationMethod", }), params: ServerNotification__FileChangePatchUpdatedNotification, - }).annotate({ title: "Item/fileChange/patchUpdatedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("serverRequest/resolved").annotate({ title: "ServerRequest/resolvedNotificationMethod", }), params: ServerNotification__ServerRequestResolvedNotification, - }).annotate({ title: "ServerRequest/resolvedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("item/mcpToolCall/progress").annotate({ title: "Item/mcpToolCall/progressNotificationMethod", }), params: ServerNotification__McpToolCallProgressNotification, - }).annotate({ title: "Item/mcpToolCall/progressNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("mcpServer/oauthLogin/completed").annotate({ title: "McpServer/oauthLogin/completedNotificationMethod", }), params: ServerNotification__McpServerOauthLoginCompletedNotification, - }).annotate({ title: "McpServer/oauthLogin/completedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("mcpServer/startupStatus/updated").annotate({ title: "McpServer/startupStatus/updatedNotificationMethod", }), params: ServerNotification__McpServerStatusUpdatedNotification, - }).annotate({ title: "McpServer/startupStatus/updatedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("account/updated").annotate({ title: "Account/updatedNotificationMethod", }), params: ServerNotification__AccountUpdatedNotification, - }).annotate({ title: "Account/updatedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("account/rateLimits/updated").annotate({ title: "Account/rateLimits/updatedNotificationMethod", }), params: ServerNotification__AccountRateLimitsUpdatedNotification, - }).annotate({ title: "Account/rateLimits/updatedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("app/list/updated").annotate({ title: "App/list/updatedNotificationMethod", }), params: ServerNotification__AppListUpdatedNotification, - }).annotate({ title: "App/list/updatedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("remoteControl/status/changed").annotate({ title: "RemoteControl/status/changedNotificationMethod", }), params: ServerNotification__RemoteControlStatusChangedNotification, - }).annotate({ title: "RemoteControl/status/changedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), + Schema.Struct({ + method: Schema.Literal("externalAgentConfig/import/progress").annotate({ + title: "ExternalAgentConfig/import/progressNotificationMethod", + }), + params: ServerNotification__ExternalAgentConfigImportProgressNotification, + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("externalAgentConfig/import/completed").annotate({ title: "ExternalAgentConfig/import/completedNotificationMethod", }), params: ServerNotification__ExternalAgentConfigImportCompletedNotification, - }).annotate({ title: "ExternalAgentConfig/import/completedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("fs/changed").annotate({ title: "Fs/changedNotificationMethod" }), params: ServerNotification__FsChangedNotification, - }).annotate({ title: "Fs/changedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("item/reasoning/summaryTextDelta").annotate({ title: "Item/reasoning/summaryTextDeltaNotificationMethod", }), params: ServerNotification__ReasoningSummaryTextDeltaNotification, - }).annotate({ title: "Item/reasoning/summaryTextDeltaNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("item/reasoning/summaryPartAdded").annotate({ title: "Item/reasoning/summaryPartAddedNotificationMethod", }), params: ServerNotification__ReasoningSummaryPartAddedNotification, - }).annotate({ title: "Item/reasoning/summaryPartAddedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("item/reasoning/textDelta").annotate({ title: "Item/reasoning/textDeltaNotificationMethod", }), params: ServerNotification__ReasoningTextDeltaNotification, - }).annotate({ title: "Item/reasoning/textDeltaNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("thread/compacted").annotate({ title: "Thread/compactedNotificationMethod", }), params: ServerNotification__ContextCompactedNotification, + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), }).annotate({ - title: "Thread/compactedNotification", - description: "Deprecated: Use `ContextCompaction` item type instead.", + title: "ServerNotification", + description: "Notification sent from the server to the client.", }), Schema.Struct({ method: Schema.Literal("model/rerouted").annotate({ title: "Model/reroutedNotificationMethod", }), params: ServerNotification__ModelReroutedNotification, - }).annotate({ title: "Model/reroutedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("model/verification").annotate({ title: "Model/verificationNotificationMethod", }), params: ServerNotification__ModelVerificationNotification, - }).annotate({ title: "Model/verificationNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("turn/moderationMetadata").annotate({ title: "Turn/moderationMetadataNotificationMethod", }), params: ServerNotification__TurnModerationMetadataNotification, - }).annotate({ title: "Turn/moderationMetadataNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), + Schema.Struct({ + method: Schema.Literal("model/safetyBuffering/updated").annotate({ + title: "Model/safetyBuffering/updatedNotificationMethod", + }), + params: ServerNotification__ModelSafetyBufferingUpdatedNotification, + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("warning").annotate({ title: "WarningNotificationMethod" }), params: ServerNotification__WarningNotification, - }).annotate({ title: "WarningNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("guardianWarning").annotate({ title: "GuardianWarningNotificationMethod", }), params: ServerNotification__GuardianWarningNotification, - }).annotate({ title: "GuardianWarningNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("deprecationNotice").annotate({ title: "DeprecationNoticeNotificationMethod", }), params: ServerNotification__DeprecationNoticeNotification, - }).annotate({ title: "DeprecationNoticeNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("configWarning").annotate({ title: "ConfigWarningNotificationMethod", }), params: ServerNotification__ConfigWarningNotification, - }).annotate({ title: "ConfigWarningNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("fuzzyFileSearch/sessionUpdated").annotate({ title: "FuzzyFileSearch/sessionUpdatedNotificationMethod", }), params: ServerNotification__FuzzyFileSearchSessionUpdatedNotification, - }).annotate({ title: "FuzzyFileSearch/sessionUpdatedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("fuzzyFileSearch/sessionCompleted").annotate({ title: "FuzzyFileSearch/sessionCompletedNotificationMethod", }), params: ServerNotification__FuzzyFileSearchSessionCompletedNotification, - }).annotate({ title: "FuzzyFileSearch/sessionCompletedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("thread/realtime/started").annotate({ title: "Thread/realtime/startedNotificationMethod", }), params: ServerNotification__ThreadRealtimeStartedNotification, - }).annotate({ title: "Thread/realtime/startedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("thread/realtime/itemAdded").annotate({ title: "Thread/realtime/itemAddedNotificationMethod", }), params: ServerNotification__ThreadRealtimeItemAddedNotification, - }).annotate({ title: "Thread/realtime/itemAddedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("thread/realtime/transcript/delta").annotate({ title: "Thread/realtime/transcript/deltaNotificationMethod", }), params: ServerNotification__ThreadRealtimeTranscriptDeltaNotification, - }).annotate({ title: "Thread/realtime/transcript/deltaNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("thread/realtime/transcript/done").annotate({ title: "Thread/realtime/transcript/doneNotificationMethod", }), params: ServerNotification__ThreadRealtimeTranscriptDoneNotification, - }).annotate({ title: "Thread/realtime/transcript/doneNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("thread/realtime/outputAudio/delta").annotate({ title: "Thread/realtime/outputAudio/deltaNotificationMethod", }), params: ServerNotification__ThreadRealtimeOutputAudioDeltaNotification, - }).annotate({ title: "Thread/realtime/outputAudio/deltaNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("thread/realtime/sdp").annotate({ title: "Thread/realtime/sdpNotificationMethod", }), params: ServerNotification__ThreadRealtimeSdpNotification, - }).annotate({ title: "Thread/realtime/sdpNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("thread/realtime/error").annotate({ title: "Thread/realtime/errorNotificationMethod", }), params: ServerNotification__ThreadRealtimeErrorNotification, - }).annotate({ title: "Thread/realtime/errorNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("thread/realtime/closed").annotate({ title: "Thread/realtime/closedNotificationMethod", }), params: ServerNotification__ThreadRealtimeClosedNotification, - }).annotate({ title: "Thread/realtime/closedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("windows/worldWritableWarning").annotate({ title: "Windows/worldWritableWarningNotificationMethod", }), params: ServerNotification__WindowsWorldWritableWarningNotification, + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), }).annotate({ - title: "Windows/worldWritableWarningNotification", - description: - "Notifies the user of world-writable directories on Windows, which cannot be protected by the sandbox.", + title: "ServerNotification", + description: "Notification sent from the server to the client.", }), Schema.Struct({ method: Schema.Literal("windowsSandbox/setupCompleted").annotate({ title: "WindowsSandbox/setupCompletedNotificationMethod", }), params: ServerNotification__WindowsSandboxSetupCompletedNotification, - }).annotate({ title: "WindowsSandbox/setupCompletedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), Schema.Struct({ method: Schema.Literal("account/login/completed").annotate({ title: "Account/login/completedNotificationMethod", }), params: ServerNotification__AccountLoginCompletedNotification, - }).annotate({ title: "Account/login/completedNotification" }), + emittedAtMs: Schema.optionalKey( + Schema.Number.annotate({ + description: + "Unix timestamp (in milliseconds) when app-server emitted this notification.", + format: "int64", + }).check(Schema.isInt()), + ), + }).annotate({ + title: "ServerNotification", + description: "Notification sent from the server to the client.", + }), ], { mode: "oneOf" }, -).annotate({ - title: "ServerNotification", - description: "Notification sent from the server to the client.", -}); +); export type ServerNotification__ByteRange = { readonly end: number; readonly start: number }; export const ServerNotification__ByteRange = Schema.Struct({ @@ -32157,6 +36031,21 @@ export const ServerNotification__HookSource = Schema.Literals([ "unknown", ]); +export type ServerNotification__MultiAgentMode = + | "explicitRequestOnly" + | "proactive" + | { readonly custom: string }; +export const ServerNotification__MultiAgentMode = Schema.Union( + [ + Schema.Literals(["explicitRequestOnly", "proactive"]), + Schema.Struct({ custom: Schema.String }).annotate({ title: "CustomMultiAgentMode" }), + ], + { mode: "oneOf" }, +).annotate({ + description: + "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 ServerNotification__NetworkAccess = "restricted" | "enabled"; export const ServerNotification__NetworkAccess = Schema.Literals(["restricted", "enabled"]); @@ -32185,6 +36074,14 @@ export const ServerNotification__SessionSource = Schema.Union( { mode: "oneOf" }, ); +export type ServerNotification__ThreadExtra = {}; +export const ServerNotification__ThreadExtra = Schema.Struct({}).annotate({ + description: "Extra app-server data for a thread.", +}); + +export type ServerNotification__ThreadHistoryMode = "legacy" | "paginated"; +export const ServerNotification__ThreadHistoryMode = Schema.Literals(["legacy", "paginated"]); + export type ServerNotification__TurnItemsView = "notLoaded" | "summary" | "full"; export const ServerNotification__TurnItemsView = Schema.Literals(["notLoaded", "summary", "full"]); @@ -32412,12 +36309,21 @@ export const ServerRequest__CommandExecutionApprovalDecision = Schema.Union( ); export type ToolRequestUserInputParams = { + readonly autoResolutionMs?: number | null; readonly itemId: string; readonly questions: ReadonlyArray; readonly threadId: string; readonly turnId: string; }; export const ToolRequestUserInputParams = Schema.Struct({ + autoResolutionMs: Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ format: "uint64" }) + .check(Schema.isInt()) + .check(Schema.isGreaterThanOrEqualTo(0)), + Schema.Null, + ]), + ), itemId: Schema.String, questions: Schema.Array(ToolRequestUserInputParams__ToolRequestUserInputQuestion), threadId: Schema.String, @@ -32532,6 +36438,40 @@ export const V2AppListUpdatedNotification = Schema.Struct({ description: "EXPERIMENTAL - notification emitted when the app list changes.", }); +export type V2AppsInstalledParams = { + readonly forceRefresh?: boolean; + readonly threadId?: string | null; +}; +export const V2AppsInstalledParams = Schema.Struct({ + forceRefresh: Schema.optionalKey( + Schema.Boolean.annotate({ + description: + "When true and Apps are permitted, refresh and publish the hosted connector runtime tool snapshot first.", + }), + ), + threadId: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Optional loaded thread id used to evaluate effective app configuration.", + }), + Schema.Null, + ]), + ), +}).annotate({ + title: "AppsInstalledParams", + description: "Read the committed installed connector runtime snapshot.", +}); + +export type V2AppsInstalledResponse = { + readonly apps: ReadonlyArray; +}; +export const V2AppsInstalledResponse = Schema.Struct({ + apps: Schema.Array(V2AppsInstalledResponse__InstalledApp), +}).annotate({ + title: "AppsInstalledResponse", + description: "The installed connectors in one committed runtime snapshot.", +}); + export type V2AppsListParams = { readonly cursor?: string | null; readonly forceRefetch?: boolean; @@ -32594,6 +36534,35 @@ export const V2AppsListResponse = Schema.Struct({ ), }).annotate({ title: "AppsListResponse", description: "EXPERIMENTAL - app list response." }); +export type V2AppsReadParams = { + readonly appIds: ReadonlyArray; + readonly includeTools?: boolean; +}; +export const V2AppsReadParams = Schema.Struct({ + appIds: Schema.Array(Schema.String).annotate({ + description: + "App ids to read. The server accepts at most 100 ids and deduplicates repeated ids while preserving their first-request order.", + }), + includeTools: Schema.optionalKey( + Schema.Boolean.annotate({ + description: + "When true, include display-only public tool summaries in the returned metadata.", + }), + ), +}).annotate({ + title: "AppsReadParams", + description: "EXPERIMENTAL - read metadata for specific apps/connectors.", +}); + +export type V2AppsReadResponse = { + readonly apps: ReadonlyArray; + readonly missingAppIds: ReadonlyArray; +}; +export const V2AppsReadResponse = Schema.Struct({ + apps: Schema.Array(V2AppsReadResponse__ConnectorMetadata), + missingAppIds: Schema.Array(Schema.String), +}).annotate({ title: "AppsReadResponse", description: "EXPERIMENTAL - app/read response." }); + export type V2CancelLoginAccountParams = { readonly loginId: string }; export const V2CancelLoginAccountParams = Schema.Struct({ loginId: Schema.String }).annotate({ title: "CancelLoginAccountParams", @@ -33017,6 +36986,7 @@ export type V2ConfigRequirementsReadResponse__ManagedHooksRequirements = { readonly PostToolUse: ReadonlyArray; readonly PreCompact: ReadonlyArray; readonly PreToolUse: ReadonlyArray; + readonly SessionEnd?: ReadonlyArray; readonly SessionStart: ReadonlyArray; readonly Stop: ReadonlyArray; readonly SubagentStart: ReadonlyArray; @@ -33031,6 +37001,11 @@ export const V2ConfigRequirementsReadResponse__ManagedHooksRequirements = Schema PostToolUse: Schema.Array(V2ConfigRequirementsReadResponse__ConfiguredHookMatcherGroup), PreCompact: Schema.Array(V2ConfigRequirementsReadResponse__ConfiguredHookMatcherGroup), PreToolUse: Schema.Array(V2ConfigRequirementsReadResponse__ConfiguredHookMatcherGroup), + SessionEnd: Schema.optionalKey( + Schema.Array(V2ConfigRequirementsReadResponse__ConfiguredHookMatcherGroup).annotate({ + default: [], + }), + ), SessionStart: Schema.Array(V2ConfigRequirementsReadResponse__ConfiguredHookMatcherGroup), Stop: Schema.Array(V2ConfigRequirementsReadResponse__ConfiguredHookMatcherGroup), SubagentStart: Schema.Array(V2ConfigRequirementsReadResponse__ConfiguredHookMatcherGroup), @@ -33206,6 +37181,33 @@ export const V2ConfigWriteResponse = Schema.Struct({ version: Schema.String, }).annotate({ title: "ConfigWriteResponse" }); +export type V2ConsumeAccountRateLimitResetCreditParams = { + readonly creditId?: string | null; + readonly idempotencyKey: string; +}; +export const V2ConsumeAccountRateLimitResetCreditParams = Schema.Struct({ + creditId: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: + "Opaque reset-credit identifier to redeem. When omitted, the backend selects the next available credit.", + }), + Schema.Null, + ]), + ), + idempotencyKey: Schema.String.annotate({ + description: + "Identifies one logical reset attempt. A UUID is recommended; reuse the same value when retrying that attempt.", + }), +}).annotate({ title: "ConsumeAccountRateLimitResetCreditParams" }); + +export type V2ConsumeAccountRateLimitResetCreditResponse = { + readonly outcome: V2ConsumeAccountRateLimitResetCreditResponse__ConsumeAccountRateLimitResetCreditOutcome; +}; +export const V2ConsumeAccountRateLimitResetCreditResponse = Schema.Struct({ + outcome: V2ConsumeAccountRateLimitResetCreditResponse__ConsumeAccountRateLimitResetCreditOutcome, +}).annotate({ title: "ConsumeAccountRateLimitResetCreditResponse" }); + export type V2ContextCompactedNotification = { readonly threadId: string; readonly turnId: string }; export const V2ContextCompactedNotification = Schema.Struct({ threadId: Schema.String, @@ -33231,6 +37233,15 @@ export const V2DeprecationNoticeNotification = Schema.Struct({ summary: Schema.String.annotate({ description: "Concise summary of what is deprecated." }), }).annotate({ title: "DeprecationNoticeNotification" }); +export type V2EnvironmentConnectionNotification = { + readonly environmentId: string; + readonly threadId: string; +}; +export const V2EnvironmentConnectionNotification = Schema.Struct({ + environmentId: Schema.String, + threadId: Schema.String, +}).annotate({ title: "EnvironmentConnectionNotification" }); + export type V2ErrorNotification = { readonly error: V2ErrorNotification__TurnError; readonly threadId: string; @@ -33333,6 +37344,8 @@ export const V2ExperimentalFeatureListResponse__ExperimentalFeatureStage = Schem export type V2ExternalAgentConfigDetectParams = { readonly cwds?: ReadonlyArray | null; readonly includeHome?: boolean; + readonly migrationSource?: string | null; + readonly source?: string | null; }; export const V2ExternalAgentConfigDetectParams = Schema.Struct({ cwds: Schema.optionalKey( @@ -33345,9 +37358,27 @@ export const V2ExternalAgentConfigDetectParams = Schema.Struct({ ), includeHome: Schema.optionalKey( Schema.Boolean.annotate({ - description: "If true, include detection under the user's home (~/.claude, ~/.codex, etc.).", + description: "If true, include detection under the user's home directory.", }), ), + migrationSource: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: + "Optional migration-source selector. Missing or unrecognized values use the default source.", + }), + Schema.Null, + ]), + ), + source: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: + "Deprecated field retained for compatibility. This field is ignored; use `migrationSource` to select the migration source.", + }), + Schema.Null, + ]), + ), }).annotate({ title: "ExternalAgentConfigDetectParams" }); export type V2ExternalAgentConfigDetectResponse = { @@ -33357,22 +37388,71 @@ export const V2ExternalAgentConfigDetectResponse = Schema.Struct({ items: Schema.Array(V2ExternalAgentConfigDetectResponse__ExternalAgentConfigMigrationItem), }).annotate({ title: "ExternalAgentConfigDetectResponse" }); -export type V2ExternalAgentConfigImportCompletedNotification = {}; -export const V2ExternalAgentConfigImportCompletedNotification = Schema.Struct({}).annotate({ - title: "ExternalAgentConfigImportCompletedNotification", -}); +export type V2ExternalAgentConfigImportCompletedNotification = { + readonly importId: string; + readonly itemTypeResults: ReadonlyArray; +}; +export const V2ExternalAgentConfigImportCompletedNotification = Schema.Struct({ + importId: Schema.String, + itemTypeResults: Schema.Array( + V2ExternalAgentConfigImportCompletedNotification__ExternalAgentConfigImportTypeResult, + ), +}).annotate({ title: "ExternalAgentConfigImportCompletedNotification" }); + +export type V2ExternalAgentConfigImportHistoriesReadResponse = { + readonly connectors: ReadonlyArray; + readonly data: ReadonlyArray; +}; +export const V2ExternalAgentConfigImportHistoriesReadResponse = Schema.Struct({ + connectors: Schema.Array( + V2ExternalAgentConfigImportHistoriesReadResponse__ExternalAgentImportedConnectorCandidate, + ), + data: Schema.Array( + V2ExternalAgentConfigImportHistoriesReadResponse__ExternalAgentConfigImportHistory, + ), +}).annotate({ title: "ExternalAgentConfigImportHistoriesReadResponse" }); export type V2ExternalAgentConfigImportParams = { readonly migrationItems: ReadonlyArray; + readonly migrationSource?: string | null; + readonly source?: string | null; }; export const V2ExternalAgentConfigImportParams = Schema.Struct({ migrationItems: Schema.Array(V2ExternalAgentConfigImportParams__ExternalAgentConfigMigrationItem), + migrationSource: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: + "Migration-source selector used to produce the migration items. Pass the same value to detection and import; missing or unrecognized values use the default source.", + }), + Schema.Null, + ]), + ), + source: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: "Optional identifier for the product that initiated the import.", + }), + Schema.Null, + ]), + ), }).annotate({ title: "ExternalAgentConfigImportParams" }); -export type V2ExternalAgentConfigImportResponse = {}; -export const V2ExternalAgentConfigImportResponse = Schema.Struct({}).annotate({ - title: "ExternalAgentConfigImportResponse", -}); +export type V2ExternalAgentConfigImportProgressNotification = { + readonly importId: string; + readonly itemTypeResults: ReadonlyArray; +}; +export const V2ExternalAgentConfigImportProgressNotification = Schema.Struct({ + importId: Schema.String, + itemTypeResults: Schema.Array( + V2ExternalAgentConfigImportProgressNotification__ExternalAgentConfigImportTypeResult, + ), +}).annotate({ title: "ExternalAgentConfigImportProgressNotification" }); + +export type V2ExternalAgentConfigImportResponse = { readonly importId: string }; +export const V2ExternalAgentConfigImportResponse = Schema.Struct({ + importId: Schema.String, +}).annotate({ title: "ExternalAgentConfigImportResponse" }); export type V2FeedbackUploadParams = { readonly classification: string; @@ -33735,6 +37815,7 @@ export const V2GetAccountParams = Schema.Struct({ }).annotate({ title: "GetAccountParams" }); export type V2GetAccountRateLimitsResponse = { + readonly rateLimitResetCredits?: V2GetAccountRateLimitsResponse__RateLimitResetCreditsSummary | null; readonly rateLimits: { readonly credits?: V2GetAccountRateLimitsResponse__CreditsSnapshot | null; readonly individualLimit?: V2GetAccountRateLimitsResponse__SpendControlLimitSnapshot | null; @@ -33744,12 +37825,16 @@ export type V2GetAccountRateLimitsResponse = { readonly primary?: V2GetAccountRateLimitsResponse__RateLimitWindow | null; readonly rateLimitReachedType?: V2GetAccountRateLimitsResponse__RateLimitReachedType | null; readonly secondary?: V2GetAccountRateLimitsResponse__RateLimitWindow | null; + readonly spendControlReached?: boolean | null; }; readonly rateLimitsByLimitId?: { readonly [x: string]: V2GetAccountRateLimitsResponse__RateLimitSnapshot; } | null; }; export const V2GetAccountRateLimitsResponse = Schema.Struct({ + rateLimitResetCredits: Schema.optionalKey( + Schema.Union([V2GetAccountRateLimitsResponse__RateLimitResetCreditsSummary, Schema.Null]), + ), rateLimits: Schema.Struct({ credits: Schema.optionalKey( Schema.Union([V2GetAccountRateLimitsResponse__CreditsSnapshot, Schema.Null]), @@ -33771,6 +37856,15 @@ export const V2GetAccountRateLimitsResponse = Schema.Struct({ secondary: Schema.optionalKey( Schema.Union([V2GetAccountRateLimitsResponse__RateLimitWindow, Schema.Null]), ), + spendControlReached: Schema.optionalKey( + Schema.Union([ + Schema.Boolean.annotate({ + description: + "Backend-reported spend-control state. `None` is unavailable, not a sparse-update recovery.", + }), + Schema.Null, + ]), + ), }).annotate({ description: "Backward-compatible single-bucket view; mirrors the historical payload.", }), @@ -33807,6 +37901,19 @@ export const V2GetAccountTokenUsageResponse = Schema.Struct({ summary: V2GetAccountTokenUsageResponse__AccountTokenUsageSummary, }).annotate({ title: "GetAccountTokenUsageResponse" }); +export type V2GetWorkspaceMessagesResponse = { + readonly featureEnabled: boolean; + readonly messages: ReadonlyArray; +}; +export const V2GetWorkspaceMessagesResponse = Schema.Struct({ + featureEnabled: Schema.Boolean.annotate({ + description: "Whether the workspace-message backend route is available for this client.", + }), + messages: Schema.Array(V2GetWorkspaceMessagesResponse__WorkspaceMessage).annotate({ + description: "Active workspace messages returned by the backend.", + }), +}).annotate({ title: "GetWorkspaceMessagesResponse" }); + export type V2GuardianWarningNotification = { readonly message: string; readonly threadId: string }; export const V2GuardianWarningNotification = Schema.Struct({ message: Schema.String.annotate({ @@ -34161,14 +38268,20 @@ export const V2ListMcpServerStatusResponse = Schema.Struct({ export type V2LoginAccountParams = | { readonly apiKey: string; readonly type: "apiKey" } - | { readonly codexStreamlinedLogin?: boolean; readonly type: "chatgpt" } + | { + readonly appBrand?: V2LoginAccountParams__LoginAppBrand | null; + readonly codexStreamlinedLogin?: boolean; + readonly type: "chatgpt"; + readonly useHostedLoginSuccessPage?: boolean; + } | { readonly type: "chatgptDeviceCode" } | { readonly accessToken: string; readonly chatgptAccountId: string; readonly chatgptPlanType?: string | null; readonly type: "chatgptAuthTokens"; - }; + } + | { readonly apiKey: string; readonly region: string; readonly type: "amazonBedrock" }; export const V2LoginAccountParams = Schema.Union( [ Schema.Struct({ @@ -34176,8 +38289,12 @@ export const V2LoginAccountParams = Schema.Union( type: Schema.Literal("apiKey").annotate({ title: "ApiKeyv2::LoginAccountParamsType" }), }).annotate({ title: "ApiKeyv2::LoginAccountParams" }), Schema.Struct({ + appBrand: Schema.optionalKey( + Schema.Union([V2LoginAccountParams__LoginAppBrand, Schema.Null]), + ), codexStreamlinedLogin: Schema.optionalKey(Schema.Boolean), type: Schema.Literal("chatgpt").annotate({ title: "Chatgptv2::LoginAccountParamsType" }), + useHostedLoginSuccessPage: Schema.optionalKey(Schema.Boolean), }).annotate({ title: "Chatgptv2::LoginAccountParams" }), Schema.Struct({ type: Schema.Literal("chatgptDeviceCode").annotate({ @@ -34209,6 +38326,16 @@ export const V2LoginAccountParams = Schema.Union( description: "[UNSTABLE] FOR OPENAI INTERNAL USE ONLY - DO NOT USE. The access token must contain the same scopes that Codex-managed ChatGPT auth tokens have.", }), + Schema.Struct({ + apiKey: Schema.String, + region: Schema.String, + type: Schema.Literal("amazonBedrock").annotate({ + title: "AmazonBedrockv2::LoginAccountParamsType", + }), + }).annotate({ + title: "AmazonBedrockv2::LoginAccountParams", + description: "[UNSTABLE] Managed Amazon Bedrock login is experimental.", + }), ], { mode: "oneOf" }, ).annotate({ title: "LoginAccountParams" }); @@ -34222,7 +38349,8 @@ export type V2LoginAccountResponse = readonly userCode: string; readonly verificationUrl: string; } - | { readonly type: "chatgptAuthTokens" }; + | { readonly type: "chatgptAuthTokens" } + | { readonly type: "amazonBedrock" }; export const V2LoginAccountResponse = Schema.Union( [ Schema.Struct({ @@ -34253,6 +38381,11 @@ export const V2LoginAccountResponse = Schema.Union( title: "ChatgptAuthTokensv2::LoginAccountResponseType", }), }).annotate({ title: "ChatgptAuthTokensv2::LoginAccountResponse" }), + Schema.Struct({ + type: Schema.Literal("amazonBedrock").annotate({ + title: "AmazonBedrockv2::LoginAccountResponseType", + }), + }).annotate({ title: "AmazonBedrockv2::LoginAccountResponse" }), ], { mode: "oneOf" }, ).annotate({ title: "LoginAccountResponse" }); @@ -34338,21 +38471,25 @@ export type V2McpServerOauthLoginCompletedNotification = { readonly error?: string | null; readonly name: string; readonly success: boolean; + readonly threadId?: string | null; }; export const V2McpServerOauthLoginCompletedNotification = Schema.Struct({ error: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), name: Schema.String, success: Schema.Boolean, + threadId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), }).annotate({ title: "McpServerOauthLoginCompletedNotification" }); export type V2McpServerOauthLoginParams = { readonly name: string; readonly scopes?: ReadonlyArray | null; + readonly threadId?: string | null; readonly timeoutSecs?: number | null; }; export const V2McpServerOauthLoginParams = Schema.Struct({ name: Schema.String, scopes: Schema.optionalKey(Schema.Union([Schema.Array(Schema.String), Schema.Null])), + threadId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), timeoutSecs: Schema.optionalKey( Schema.Union([Schema.Number.annotate({ format: "int64" }).check(Schema.isInt()), Schema.Null]), ), @@ -34370,12 +38507,19 @@ export const V2McpServerRefreshResponse = Schema.Struct({}).annotate({ export type V2McpServerStatusUpdatedNotification = { readonly error?: string | null; + readonly failureReason?: V2McpServerStatusUpdatedNotification__McpServerStartupFailureReason | null; readonly name: string; readonly status: V2McpServerStatusUpdatedNotification__McpServerStartupState; readonly threadId?: string | null; }; export const V2McpServerStatusUpdatedNotification = Schema.Struct({ error: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + failureReason: Schema.optionalKey( + Schema.Union([ + V2McpServerStatusUpdatedNotification__McpServerStartupFailureReason, + Schema.Null, + ]), + ), name: Schema.String, status: V2McpServerStatusUpdatedNotification__McpServerStartupState, threadId: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), @@ -34505,6 +38649,25 @@ export const V2ModelReroutedNotification = Schema.Struct({ turnId: Schema.String, }).annotate({ title: "ModelReroutedNotification" }); +export type V2ModelSafetyBufferingUpdatedNotification = { + readonly fasterModel?: string | null; + readonly model: string; + readonly reasons: ReadonlyArray; + readonly showBufferingUi: boolean; + readonly threadId: string; + readonly turnId: string; + readonly useCases: ReadonlyArray; +}; +export const V2ModelSafetyBufferingUpdatedNotification = Schema.Struct({ + fasterModel: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + model: Schema.String, + reasons: Schema.Array(Schema.String), + showBufferingUi: Schema.Boolean, + threadId: Schema.String, + turnId: Schema.String, + useCases: Schema.Array(Schema.String), +}).annotate({ title: "ModelSafetyBufferingUpdatedNotification" }); + export type V2ModelVerificationNotification = { readonly threadId: string; readonly turnId: string; @@ -34905,6 +39068,25 @@ export const V2ProcessOutputDeltaNotification__ProcessOutputStream = Schema.Lite "stderr", ]).annotate({ description: "Stream label for `process/outputDelta` notifications." }); +export type V2RawResponseCompletedNotification = { + readonly responseId: string; + readonly threadId: string; + readonly turnId: string; + readonly usage?: V2RawResponseCompletedNotification__TokenUsageBreakdown | null; +}; +export const V2RawResponseCompletedNotification = Schema.Struct({ + responseId: Schema.String, + threadId: Schema.String, + turnId: Schema.String, + usage: Schema.optionalKey( + Schema.Union([V2RawResponseCompletedNotification__TokenUsageBreakdown, Schema.Null]), + ), +}).annotate({ + title: "RawResponseCompletedNotification", + description: + "Internal-only notification containing the exact usage from one upstream Responses API completion.", +}); + export type V2RawResponseItemCompletedNotification = { readonly item: V2RawResponseItemCompletedNotification__ResponseItem; readonly threadId: string; @@ -35226,6 +39408,7 @@ export type V2ThreadForkParams = { readonly cwd?: string | null; readonly developerInstructions?: string | null; readonly ephemeral?: boolean; + readonly lastTurnId?: string | null; readonly model?: string | null; readonly modelProvider?: string | null; readonly sandbox?: V2ThreadForkParams__SandboxMode | null; @@ -35250,6 +39433,15 @@ export const V2ThreadForkParams = Schema.Struct({ cwd: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), developerInstructions: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), ephemeral: Schema.optionalKey(Schema.Boolean), + lastTurnId: Schema.optionalKey( + Schema.Union([ + Schema.String.annotate({ + description: + "Optional last turn id to fork through, inclusive.\n\nWhen specified, turns after `last_turn_id` are omitted from the fork. The referenced turn cannot be in progress.", + }), + Schema.Null, + ]), + ), model: Schema.optionalKey( Schema.Union([ Schema.String.annotate({ @@ -35284,7 +39476,7 @@ export type V2ThreadForkResponse = { readonly approvalPolicy: V2ThreadForkResponse__AskForApproval; readonly approvalsReviewer: "user" | "auto_review" | "guardian_subagent"; readonly cwd: V2ThreadForkResponse__AbsolutePathBuf; - readonly instructionSources?: ReadonlyArray; + readonly instructionSources?: ReadonlyArray; readonly model: string; readonly modelProvider: string; readonly reasoningEffort?: V2ThreadForkResponse__ReasoningEffort | null; @@ -35310,8 +39502,9 @@ export const V2ThreadForkResponse = Schema.Struct({ }), cwd: V2ThreadForkResponse__AbsolutePathBuf, instructionSources: Schema.optionalKey( - Schema.Array(V2ThreadForkResponse__AbsolutePathBuf).annotate({ - description: "Instruction source files currently loaded for this thread.", + Schema.Array(V2ThreadForkResponse__LegacyAppPathString).annotate({ + description: + "Environment-native paths to instruction source files currently loaded for this thread.", default: [], }), ), @@ -35433,6 +39626,21 @@ export const V2ThreadForkResponse__CommandExecutionSource = Schema.Literals([ "unifiedExecInteraction", ]); +export type V2ThreadForkResponse__MultiAgentMode = + | "explicitRequestOnly" + | "proactive" + | { readonly custom: string }; +export const V2ThreadForkResponse__MultiAgentMode = Schema.Union( + [ + Schema.Literals(["explicitRequestOnly", "proactive"]), + Schema.Struct({ custom: Schema.String }).annotate({ title: "CustomMultiAgentMode" }), + ], + { mode: "oneOf" }, +).annotate({ + description: + "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 V2ThreadForkResponse__NetworkAccess = "restricted" | "enabled"; export const V2ThreadForkResponse__NetworkAccess = Schema.Literals(["restricted", "enabled"]); @@ -35498,6 +39706,14 @@ export const V2ThreadForkResponse__SessionSource = Schema.Union( { mode: "oneOf" }, ); +export type V2ThreadForkResponse__ThreadExtra = {}; +export const V2ThreadForkResponse__ThreadExtra = Schema.Struct({}).annotate({ + description: "Extra app-server data for a thread.", +}); + +export type V2ThreadForkResponse__ThreadHistoryMode = "legacy" | "paginated"; +export const V2ThreadForkResponse__ThreadHistoryMode = Schema.Literals(["legacy", "paginated"]); + export type V2ThreadForkResponse__ThreadStatus = | { readonly type: "notLoaded" } | { readonly type: "idle" } @@ -35786,6 +40002,14 @@ export const V2ThreadListResponse__SessionSource = Schema.Union( { mode: "oneOf" }, ); +export type V2ThreadListResponse__ThreadExtra = {}; +export const V2ThreadListResponse__ThreadExtra = Schema.Struct({}).annotate({ + description: "Extra app-server data for a thread.", +}); + +export type V2ThreadListResponse__ThreadHistoryMode = "legacy" | "paginated"; +export const V2ThreadListResponse__ThreadHistoryMode = Schema.Literals(["legacy", "paginated"]); + export type V2ThreadListResponse__ThreadStatus = | { readonly type: "notLoaded" } | { readonly type: "idle" } @@ -35957,6 +40181,17 @@ export const V2ThreadMetadataUpdateResponse__SessionSource = Schema.Union( { mode: "oneOf" }, ); +export type V2ThreadMetadataUpdateResponse__ThreadExtra = {}; +export const V2ThreadMetadataUpdateResponse__ThreadExtra = Schema.Struct({}).annotate({ + description: "Extra app-server data for a thread.", +}); + +export type V2ThreadMetadataUpdateResponse__ThreadHistoryMode = "legacy" | "paginated"; +export const V2ThreadMetadataUpdateResponse__ThreadHistoryMode = Schema.Literals([ + "legacy", + "paginated", +]); + export type V2ThreadMetadataUpdateResponse__ThreadStatus = | { readonly type: "notLoaded" } | { readonly type: "idle" } @@ -36077,6 +40312,14 @@ export const V2ThreadReadResponse__SessionSource = Schema.Union( { mode: "oneOf" }, ); +export type V2ThreadReadResponse__ThreadExtra = {}; +export const V2ThreadReadResponse__ThreadExtra = Schema.Struct({}).annotate({ + description: "Extra app-server data for a thread.", +}); + +export type V2ThreadReadResponse__ThreadHistoryMode = "legacy" | "paginated"; +export const V2ThreadReadResponse__ThreadHistoryMode = Schema.Literals(["legacy", "paginated"]); + export type V2ThreadReadResponse__ThreadStatus = | { readonly type: "notLoaded" } | { readonly type: "idle" } @@ -36271,6 +40514,7 @@ export type V2ThreadResumeParams__ResponseItem = | { readonly content: ReadonlyArray; readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2ThreadResumeParams__InternalChatMessageMetadataPassthrough | null; readonly phase?: V2ThreadResumeParams__MessagePhase | null; readonly role: string; readonly type: "message"; @@ -36278,12 +40522,16 @@ export type V2ThreadResumeParams__ResponseItem = | { readonly author: string; readonly content: ReadonlyArray; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2ThreadResumeParams__InternalChatMessageMetadataPassthrough | null; readonly recipient: string; readonly type: "agent_message"; } | { readonly content?: ReadonlyArray | null; readonly encrypted_content?: string | null; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2ThreadResumeParams__InternalChatMessageMetadataPassthrough | null; readonly summary: ReadonlyArray; readonly type: "reasoning"; } @@ -36291,6 +40539,7 @@ export type V2ThreadResumeParams__ResponseItem = readonly action: V2ThreadResumeParams__LocalShellAction; readonly call_id?: string | null; readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2ThreadResumeParams__InternalChatMessageMetadataPassthrough | null; readonly status: V2ThreadResumeParams__LocalShellStatus; readonly type: "local_shell_call"; } @@ -36298,6 +40547,7 @@ export type V2ThreadResumeParams__ResponseItem = readonly arguments: string; readonly call_id: string; readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2ThreadResumeParams__InternalChatMessageMetadataPassthrough | null; readonly name: string; readonly namespace?: string | null; readonly type: "function_call"; @@ -36307,11 +40557,14 @@ export type V2ThreadResumeParams__ResponseItem = readonly call_id?: string | null; readonly execution: string; readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2ThreadResumeParams__InternalChatMessageMetadataPassthrough | null; readonly status?: string | null; readonly type: "tool_search_call"; } | { readonly call_id: string; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2ThreadResumeParams__InternalChatMessageMetadataPassthrough | null; readonly output: V2ThreadResumeParams__FunctionCallOutputBody; readonly type: "function_call_output"; } @@ -36319,12 +40572,16 @@ export type V2ThreadResumeParams__ResponseItem = readonly call_id: string; readonly id?: string | null; readonly input: string; + readonly internal_chat_message_metadata_passthrough?: V2ThreadResumeParams__InternalChatMessageMetadataPassthrough | null; readonly name: string; + readonly namespace?: string | null; readonly status?: string | null; readonly type: "custom_tool_call"; } | { readonly call_id: string; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2ThreadResumeParams__InternalChatMessageMetadataPassthrough | null; readonly name?: string | null; readonly output: V2ThreadResumeParams__FunctionCallOutputBody; readonly type: "custom_tool_call_output"; @@ -36332,6 +40589,8 @@ export type V2ThreadResumeParams__ResponseItem = | { readonly call_id?: string | null; readonly execution: string; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2ThreadResumeParams__InternalChatMessageMetadataPassthrough | null; readonly status: string; readonly tools: ReadonlyArray; readonly type: "tool_search_output"; @@ -36339,26 +40598,39 @@ export type V2ThreadResumeParams__ResponseItem = | { readonly action?: V2ThreadResumeParams__ResponsesApiWebSearchAction | null; readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2ThreadResumeParams__InternalChatMessageMetadataPassthrough | null; readonly status?: string | null; readonly type: "web_search_call"; } | { - readonly id: string; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2ThreadResumeParams__InternalChatMessageMetadataPassthrough | null; readonly result: string; readonly revised_prompt?: string | null; readonly status: string; readonly type: "image_generation_call"; } - | { readonly encrypted_content: string; readonly type: "compaction" } + | { + readonly encrypted_content: string; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2ThreadResumeParams__InternalChatMessageMetadataPassthrough | null; + readonly type: "compaction"; + } | { readonly type: "compaction_trigger" } - | { readonly encrypted_content?: string | null; readonly type: "context_compaction" } + | { + readonly encrypted_content?: string | null; + readonly id?: string | null; + readonly internal_chat_message_metadata_passthrough?: V2ThreadResumeParams__InternalChatMessageMetadataPassthrough | null; + readonly type: "context_compaction"; + } | { readonly type: "other" }; export const V2ThreadResumeParams__ResponseItem = Schema.Union( [ Schema.Struct({ content: Schema.Array(V2ThreadResumeParams__ContentItem), - id: Schema.optionalKey( - Schema.Union([Schema.String.annotate({ writeOnly: true }), Schema.Null]), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([V2ThreadResumeParams__InternalChatMessageMetadataPassthrough, Schema.Null]), ), phase: Schema.optionalKey(Schema.Union([V2ThreadResumeParams__MessagePhase, Schema.Null])), role: Schema.String, @@ -36367,6 +40639,10 @@ export const V2ThreadResumeParams__ResponseItem = Schema.Union( Schema.Struct({ author: Schema.String, content: Schema.Array(V2ThreadResumeParams__AgentMessageInputContent), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([V2ThreadResumeParams__InternalChatMessageMetadataPassthrough, Schema.Null]), + ), recipient: Schema.String, type: Schema.Literal("agent_message").annotate({ title: "AgentMessageResponseItemType" }), }).annotate({ title: "AgentMessageResponseItem" }), @@ -36375,6 +40651,10 @@ export const V2ThreadResumeParams__ResponseItem = Schema.Union( Schema.Union([Schema.Array(V2ThreadResumeParams__ReasoningItemContent), Schema.Null]), ), encrypted_content: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([V2ThreadResumeParams__InternalChatMessageMetadataPassthrough, Schema.Null]), + ), summary: Schema.Array(V2ThreadResumeParams__ReasoningItemReasoningSummary), type: Schema.Literal("reasoning").annotate({ title: "ReasoningResponseItemType" }), }).annotate({ title: "ReasoningResponseItem" }), @@ -36390,11 +40670,13 @@ export const V2ThreadResumeParams__ResponseItem = Schema.Union( Schema.Union([ Schema.String.annotate({ description: "Legacy id field retained for compatibility with older payloads.", - writeOnly: true, }), Schema.Null, ]), ), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([V2ThreadResumeParams__InternalChatMessageMetadataPassthrough, Schema.Null]), + ), status: V2ThreadResumeParams__LocalShellStatus, type: Schema.Literal("local_shell_call").annotate({ title: "LocalShellCallResponseItemType", @@ -36403,8 +40685,9 @@ export const V2ThreadResumeParams__ResponseItem = Schema.Union( Schema.Struct({ arguments: Schema.String, call_id: Schema.String, - id: Schema.optionalKey( - Schema.Union([Schema.String.annotate({ writeOnly: true }), Schema.Null]), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([V2ThreadResumeParams__InternalChatMessageMetadataPassthrough, Schema.Null]), ), name: Schema.String, namespace: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), @@ -36414,8 +40697,9 @@ export const V2ThreadResumeParams__ResponseItem = Schema.Union( arguments: Schema.Unknown, call_id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), execution: Schema.String, - id: Schema.optionalKey( - Schema.Union([Schema.String.annotate({ writeOnly: true }), Schema.Null]), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([V2ThreadResumeParams__InternalChatMessageMetadataPassthrough, Schema.Null]), ), status: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), type: Schema.Literal("tool_search_call").annotate({ @@ -36424,6 +40708,10 @@ export const V2ThreadResumeParams__ResponseItem = Schema.Union( }).annotate({ title: "ToolSearchCallResponseItem" }), Schema.Struct({ call_id: Schema.String, + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([V2ThreadResumeParams__InternalChatMessageMetadataPassthrough, Schema.Null]), + ), output: V2ThreadResumeParams__FunctionCallOutputBody, type: Schema.Literal("function_call_output").annotate({ title: "FunctionCallOutputResponseItemType", @@ -36431,11 +40719,13 @@ export const V2ThreadResumeParams__ResponseItem = Schema.Union( }).annotate({ title: "FunctionCallOutputResponseItem" }), Schema.Struct({ call_id: Schema.String, - id: Schema.optionalKey( - Schema.Union([Schema.String.annotate({ writeOnly: true }), Schema.Null]), - ), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), input: Schema.String, + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([V2ThreadResumeParams__InternalChatMessageMetadataPassthrough, Schema.Null]), + ), name: Schema.String, + namespace: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), status: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), type: Schema.Literal("custom_tool_call").annotate({ title: "CustomToolCallResponseItemType", @@ -36443,6 +40733,10 @@ export const V2ThreadResumeParams__ResponseItem = Schema.Union( }).annotate({ title: "CustomToolCallResponseItem" }), Schema.Struct({ call_id: Schema.String, + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([V2ThreadResumeParams__InternalChatMessageMetadataPassthrough, Schema.Null]), + ), name: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), output: V2ThreadResumeParams__FunctionCallOutputBody, type: Schema.Literal("custom_tool_call_output").annotate({ @@ -36452,6 +40746,10 @@ export const V2ThreadResumeParams__ResponseItem = Schema.Union( Schema.Struct({ call_id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), execution: Schema.String, + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([V2ThreadResumeParams__InternalChatMessageMetadataPassthrough, Schema.Null]), + ), status: Schema.String, tools: Schema.Array(Schema.Unknown), type: Schema.Literal("tool_search_output").annotate({ @@ -36462,14 +40760,18 @@ export const V2ThreadResumeParams__ResponseItem = Schema.Union( action: Schema.optionalKey( Schema.Union([V2ThreadResumeParams__ResponsesApiWebSearchAction, Schema.Null]), ), - id: Schema.optionalKey( - Schema.Union([Schema.String.annotate({ writeOnly: true }), Schema.Null]), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([V2ThreadResumeParams__InternalChatMessageMetadataPassthrough, Schema.Null]), ), status: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), type: Schema.Literal("web_search_call").annotate({ title: "WebSearchCallResponseItemType" }), }).annotate({ title: "WebSearchCallResponseItem" }), Schema.Struct({ - id: Schema.String, + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([V2ThreadResumeParams__InternalChatMessageMetadataPassthrough, Schema.Null]), + ), result: Schema.String, revised_prompt: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), status: Schema.String, @@ -36479,6 +40781,10 @@ export const V2ThreadResumeParams__ResponseItem = Schema.Union( }).annotate({ title: "ImageGenerationCallResponseItem" }), Schema.Struct({ encrypted_content: Schema.String, + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([V2ThreadResumeParams__InternalChatMessageMetadataPassthrough, Schema.Null]), + ), type: Schema.Literal("compaction").annotate({ title: "CompactionResponseItemType" }), }).annotate({ title: "CompactionResponseItem" }), Schema.Struct({ @@ -36488,6 +40794,10 @@ export const V2ThreadResumeParams__ResponseItem = Schema.Union( }).annotate({ title: "CompactionTriggerResponseItem" }), Schema.Struct({ encrypted_content: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + id: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), + internal_chat_message_metadata_passthrough: Schema.optionalKey( + Schema.Union([V2ThreadResumeParams__InternalChatMessageMetadataPassthrough, Schema.Null]), + ), type: Schema.Literal("context_compaction").annotate({ title: "ContextCompactionResponseItemType", }), @@ -36529,7 +40839,7 @@ export type V2ThreadResumeResponse = { readonly approvalPolicy: V2ThreadResumeResponse__AskForApproval; readonly approvalsReviewer: "user" | "auto_review" | "guardian_subagent"; readonly cwd: V2ThreadResumeResponse__AbsolutePathBuf; - readonly instructionSources?: ReadonlyArray; + readonly instructionSources?: ReadonlyArray; readonly model: string; readonly modelProvider: string; readonly reasoningEffort?: V2ThreadResumeResponse__ReasoningEffort | null; @@ -36555,8 +40865,9 @@ export const V2ThreadResumeResponse = Schema.Struct({ }), cwd: V2ThreadResumeResponse__AbsolutePathBuf, instructionSources: Schema.optionalKey( - Schema.Array(V2ThreadResumeResponse__AbsolutePathBuf).annotate({ - description: "Instruction source files currently loaded for this thread.", + Schema.Array(V2ThreadResumeResponse__LegacyAppPathString).annotate({ + description: + "Environment-native paths to instruction source files currently loaded for this thread.", default: [], }), ), @@ -36684,6 +40995,21 @@ export const V2ThreadResumeResponse__CommandExecutionSource = Schema.Literals([ "unifiedExecInteraction", ]); +export type V2ThreadResumeResponse__MultiAgentMode = + | "explicitRequestOnly" + | "proactive" + | { readonly custom: string }; +export const V2ThreadResumeResponse__MultiAgentMode = Schema.Union( + [ + Schema.Literals(["explicitRequestOnly", "proactive"]), + Schema.Struct({ custom: Schema.String }).annotate({ title: "CustomMultiAgentMode" }), + ], + { mode: "oneOf" }, +).annotate({ + description: + "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 V2ThreadResumeResponse__NetworkAccess = "restricted" | "enabled"; export const V2ThreadResumeResponse__NetworkAccess = Schema.Literals(["restricted", "enabled"]); @@ -36749,6 +41075,14 @@ export const V2ThreadResumeResponse__SessionSource = Schema.Union( { mode: "oneOf" }, ); +export type V2ThreadResumeResponse__ThreadExtra = {}; +export const V2ThreadResumeResponse__ThreadExtra = Schema.Struct({}).annotate({ + description: "Extra app-server data for a thread.", +}); + +export type V2ThreadResumeResponse__ThreadHistoryMode = "legacy" | "paginated"; +export const V2ThreadResumeResponse__ThreadHistoryMode = Schema.Literals(["legacy", "paginated"]); + export type V2ThreadResumeResponse__ThreadStatus = | { readonly type: "notLoaded" } | { readonly type: "idle" } @@ -36804,7 +41138,10 @@ export const V2ThreadRollbackParams = Schema.Struct({ .check(Schema.isInt()) .check(Schema.isGreaterThanOrEqualTo(0)), threadId: Schema.String, -}).annotate({ title: "ThreadRollbackParams" }); +}).annotate({ + title: "ThreadRollbackParams", + description: "DEPRECATED: `thread/rollback` will be removed soon.", +}); export type V2ThreadRollbackResponse = { readonly thread: { @@ -36822,6 +41159,7 @@ export type V2ThreadRollbackResponse = { readonly parentThreadId?: string | null; readonly path?: string | null; readonly preview: string; + readonly recencyAt?: number | null; readonly sessionId: string; readonly source: | "cli" @@ -36890,7 +41228,9 @@ export const V2ThreadRollbackResponse = Schema.Struct({ description: "Optional Git metadata captured when the thread was created.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this thread. Codex-generated thread IDs are UUIDv7.", + }), modelProvider: Schema.String.annotate({ description: "Model provider used for this thread (for example, 'openai').", }), @@ -36918,6 +41258,15 @@ export const V2ThreadRollbackResponse = Schema.Struct({ preview: Schema.String.annotate({ description: "Usually the first user message in the thread, if available.", }), + recencyAt: Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + description: "Unix timestamp (in seconds) used for thread recency ordering.", + format: "int64", + }).check(Schema.isInt()), + Schema.Null, + ]), + ), sessionId: Schema.String.annotate({ description: "Session id shared by threads that belong to the same session tree.", }), @@ -37050,6 +41399,7 @@ export type V2ThreadRollbackResponse__Thread = { readonly parentThreadId?: string | null; readonly path?: string | null; readonly preview: string; + readonly recencyAt?: number | null; readonly sessionId: string; readonly source: | "cli" @@ -37116,7 +41466,9 @@ export const V2ThreadRollbackResponse__Thread = Schema.Struct({ description: "Optional Git metadata captured when the thread was created.", }), ), - id: Schema.String, + id: Schema.String.annotate({ + description: "Identifier for this thread. Codex-generated thread IDs are UUIDv7.", + }), modelProvider: Schema.String.annotate({ description: "Model provider used for this thread (for example, 'openai').", }), @@ -37144,6 +41496,15 @@ export const V2ThreadRollbackResponse__Thread = Schema.Struct({ preview: Schema.String.annotate({ description: "Usually the first user message in the thread, if available.", }), + recencyAt: Schema.optionalKey( + Schema.Union([ + Schema.Number.annotate({ + description: "Unix timestamp (in seconds) used for thread recency ordering.", + format: "int64", + }).check(Schema.isInt()), + Schema.Null, + ]), + ), sessionId: Schema.String.annotate({ description: "Session id shared by threads that belong to the same session tree.", }), @@ -37192,6 +41553,14 @@ export const V2ThreadRollbackResponse__Thread = Schema.Struct({ }).check(Schema.isInt()), }); +export type V2ThreadRollbackResponse__ThreadExtra = {}; +export const V2ThreadRollbackResponse__ThreadExtra = Schema.Struct({}).annotate({ + description: "Extra app-server data for a thread.", +}); + +export type V2ThreadRollbackResponse__ThreadHistoryMode = "legacy" | "paginated"; +export const V2ThreadRollbackResponse__ThreadHistoryMode = Schema.Literals(["legacy", "paginated"]); + export type V2ThreadRollbackResponse__ThreadStatus = | { readonly type: "notLoaded" } | { readonly type: "idle" } @@ -37246,6 +41615,21 @@ export const V2ThreadSettingsUpdatedNotification = Schema.Struct({ threadSettings: V2ThreadSettingsUpdatedNotification__ThreadSettings, }).annotate({ title: "ThreadSettingsUpdatedNotification" }); +export type V2ThreadSettingsUpdatedNotification__MultiAgentMode = + | "explicitRequestOnly" + | "proactive" + | { readonly custom: string }; +export const V2ThreadSettingsUpdatedNotification__MultiAgentMode = Schema.Union( + [ + Schema.Literals(["explicitRequestOnly", "proactive"]), + Schema.Struct({ custom: Schema.String }).annotate({ title: "CustomMultiAgentMode" }), + ], + { mode: "oneOf" }, +).annotate({ + description: + "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 V2ThreadSettingsUpdatedNotification__NetworkAccess = "restricted" | "enabled"; export const V2ThreadSettingsUpdatedNotification__NetworkAccess = Schema.Literals([ "restricted", @@ -37339,6 +41723,17 @@ export const V2ThreadStartedNotification__SessionSource = Schema.Union( { mode: "oneOf" }, ); +export type V2ThreadStartedNotification__ThreadExtra = {}; +export const V2ThreadStartedNotification__ThreadExtra = Schema.Struct({}).annotate({ + description: "Extra app-server data for a thread.", +}); + +export type V2ThreadStartedNotification__ThreadHistoryMode = "legacy" | "paginated"; +export const V2ThreadStartedNotification__ThreadHistoryMode = Schema.Literals([ + "legacy", + "paginated", +]); + export type V2ThreadStartedNotification__ThreadStatus = | { readonly type: "notLoaded" } | { readonly type: "idle" } @@ -37423,6 +41818,12 @@ export const V2ThreadStartParams = Schema.Struct({ ), }).annotate({ title: "ThreadStartParams" }); +export type V2ThreadStartParams__AbsolutePathBuf = string; +export const V2ThreadStartParams__AbsolutePathBuf = Schema.String.annotate({ + description: + "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.", +}); + export type V2ThreadStartParams__CapabilityRootLocation = { readonly environmentId: string; readonly path: string; @@ -37432,7 +41833,9 @@ export const V2ThreadStartParams__CapabilityRootLocation = Schema.Union( [ Schema.Struct({ environmentId: Schema.String, - path: Schema.String, + path: Schema.String.annotate({ + description: "Absolute path for the root in the selected environment.", + }), type: Schema.Literal("environment").annotate({ title: "EnvironmentCapabilityRootLocationType", }), @@ -37444,19 +41847,52 @@ export const V2ThreadStartParams__CapabilityRootLocation = Schema.Union( { mode: "oneOf" }, ).annotate({ description: "Location used to resolve a selected capability root." }); -export type V2ThreadStartParams__DynamicToolSpec = { - readonly deferLoading?: boolean; - readonly description: string; - readonly inputSchema: unknown; - readonly name: string; - readonly namespace?: string | null; -}; -export const V2ThreadStartParams__DynamicToolSpec = Schema.Struct({ - deferLoading: Schema.optionalKey(Schema.Boolean), - description: Schema.String, - inputSchema: Schema.Unknown, - name: Schema.String, - namespace: Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), +export type V2ThreadStartParams__DynamicToolSpec = + | { + readonly deferLoading?: boolean; + readonly description: string; + readonly inputSchema: unknown; + readonly name: string; + readonly type: "function"; + } + | { + readonly description: string; + readonly name: string; + readonly tools: ReadonlyArray; + readonly type: "namespace"; + }; +export const V2ThreadStartParams__DynamicToolSpec = Schema.Union( + [ + Schema.Struct({ + deferLoading: Schema.optionalKey(Schema.Boolean), + description: Schema.String, + inputSchema: Schema.Unknown, + name: Schema.String, + type: Schema.Literal("function").annotate({ title: "FunctionDynamicToolSpecType" }), + }).annotate({ title: "FunctionDynamicToolSpec" }), + Schema.Struct({ + description: Schema.String, + name: Schema.String, + tools: Schema.Array(V2ThreadStartParams__DynamicToolNamespaceTool), + type: Schema.Literal("namespace").annotate({ title: "NamespaceDynamicToolSpecType" }), + }).annotate({ title: "NamespaceDynamicToolSpec" }), + ], + { mode: "oneOf" }, +); + +export type V2ThreadStartParams__MultiAgentMode = + | "explicitRequestOnly" + | "proactive" + | { readonly custom: string }; +export const V2ThreadStartParams__MultiAgentMode = Schema.Union( + [ + Schema.Literals(["explicitRequestOnly", "proactive"]), + Schema.Struct({ custom: Schema.String }).annotate({ title: "CustomMultiAgentMode" }), + ], + { mode: "oneOf" }, +).annotate({ + description: + "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 V2ThreadStartParams__SelectedCapabilityRoot = { @@ -37475,7 +41911,9 @@ export const V2ThreadStartParams__SelectedCapabilityRoot = Schema.Struct({ [ Schema.Struct({ environmentId: Schema.String, - path: Schema.String, + path: Schema.String.annotate({ + description: "Absolute path for the root in the selected environment.", + }), type: Schema.Literal("environment").annotate({ title: "EnvironmentCapabilityRootLocationType", }), @@ -37490,20 +41928,32 @@ export const V2ThreadStartParams__SelectedCapabilityRoot = Schema.Struct({ description: "A user-selected root that can expose one or more runtime capabilities.", }); +export type V2ThreadStartParams__ThreadHistoryMode = "legacy" | "paginated"; +export const V2ThreadStartParams__ThreadHistoryMode = Schema.Literals(["legacy", "paginated"]); + export type V2ThreadStartParams__TurnEnvironmentParams = { - readonly cwd: V2ThreadStartParams__AbsolutePathBuf; + readonly cwd: V2ThreadStartParams__LegacyAppPathString; readonly environmentId: string; + readonly runtimeWorkspaceRoots?: ReadonlyArray | null; }; export const V2ThreadStartParams__TurnEnvironmentParams = Schema.Struct({ - cwd: V2ThreadStartParams__AbsolutePathBuf, + cwd: V2ThreadStartParams__LegacyAppPathString, environmentId: Schema.String, + runtimeWorkspaceRoots: Schema.optionalKey( + Schema.Union([ + Schema.Array(V2ThreadStartParams__LegacyAppPathString).annotate({ + description: "Environment-native runtime workspace roots. Omitted defaults to `cwd`.", + }), + Schema.Null, + ]), + ), }); export type V2ThreadStartResponse = { readonly approvalPolicy: V2ThreadStartResponse__AskForApproval; readonly approvalsReviewer: "user" | "auto_review" | "guardian_subagent"; readonly cwd: V2ThreadStartResponse__AbsolutePathBuf; - readonly instructionSources?: ReadonlyArray; + readonly instructionSources?: ReadonlyArray; readonly model: string; readonly modelProvider: string; readonly reasoningEffort?: V2ThreadStartResponse__ReasoningEffort | null; @@ -37529,8 +41979,9 @@ export const V2ThreadStartResponse = Schema.Struct({ }), cwd: V2ThreadStartResponse__AbsolutePathBuf, instructionSources: Schema.optionalKey( - Schema.Array(V2ThreadStartResponse__AbsolutePathBuf).annotate({ - description: "Instruction source files currently loaded for this thread.", + Schema.Array(V2ThreadStartResponse__LegacyAppPathString).annotate({ + description: + "Environment-native paths to instruction source files currently loaded for this thread.", default: [], }), ), @@ -37655,6 +42106,21 @@ export const V2ThreadStartResponse__CommandExecutionSource = Schema.Literals([ "unifiedExecInteraction", ]); +export type V2ThreadStartResponse__MultiAgentMode = + | "explicitRequestOnly" + | "proactive" + | { readonly custom: string }; +export const V2ThreadStartResponse__MultiAgentMode = Schema.Union( + [ + Schema.Literals(["explicitRequestOnly", "proactive"]), + Schema.Struct({ custom: Schema.String }).annotate({ title: "CustomMultiAgentMode" }), + ], + { mode: "oneOf" }, +).annotate({ + description: + "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 V2ThreadStartResponse__NetworkAccess = "restricted" | "enabled"; export const V2ThreadStartResponse__NetworkAccess = Schema.Literals(["restricted", "enabled"]); @@ -37720,6 +42186,14 @@ export const V2ThreadStartResponse__SessionSource = Schema.Union( { mode: "oneOf" }, ); +export type V2ThreadStartResponse__ThreadExtra = {}; +export const V2ThreadStartResponse__ThreadExtra = Schema.Struct({}).annotate({ + description: "Extra app-server data for a thread.", +}); + +export type V2ThreadStartResponse__ThreadHistoryMode = "legacy" | "paginated"; +export const V2ThreadStartResponse__ThreadHistoryMode = Schema.Literals(["legacy", "paginated"]); + export type V2ThreadStartResponse__ThreadStatus = | { readonly type: "notLoaded" } | { readonly type: "idle" } @@ -37854,6 +42328,17 @@ export const V2ThreadUnarchiveResponse__SessionSource = Schema.Union( { mode: "oneOf" }, ); +export type V2ThreadUnarchiveResponse__ThreadExtra = {}; +export const V2ThreadUnarchiveResponse__ThreadExtra = Schema.Struct({}).annotate({ + description: "Extra app-server data for a thread.", +}); + +export type V2ThreadUnarchiveResponse__ThreadHistoryMode = "legacy" | "paginated"; +export const V2ThreadUnarchiveResponse__ThreadHistoryMode = Schema.Literals([ + "legacy", + "paginated", +]); + export type V2ThreadUnarchiveResponse__ThreadStatus = | { readonly type: "notLoaded" } | { readonly type: "idle" } @@ -38187,16 +42672,40 @@ export const V2TurnStartParams__CollaborationMode = Schema.Struct({ settings: V2TurnStartParams__Settings, }).annotate({ description: "Collaboration mode for a Codex session." }); +export type V2TurnStartParams__MultiAgentMode = + | "explicitRequestOnly" + | "proactive" + | { readonly custom: string }; +export const V2TurnStartParams__MultiAgentMode = Schema.Union( + [ + Schema.Literals(["explicitRequestOnly", "proactive"]), + Schema.Struct({ custom: Schema.String }).annotate({ title: "CustomMultiAgentMode" }), + ], + { mode: "oneOf" }, +).annotate({ + description: + "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 V2TurnStartParams__NetworkAccess = "restricted" | "enabled"; export const V2TurnStartParams__NetworkAccess = Schema.Literals(["restricted", "enabled"]); export type V2TurnStartParams__TurnEnvironmentParams = { - readonly cwd: V2TurnStartParams__AbsolutePathBuf; + readonly cwd: V2TurnStartParams__LegacyAppPathString; readonly environmentId: string; + readonly runtimeWorkspaceRoots?: ReadonlyArray | null; }; export const V2TurnStartParams__TurnEnvironmentParams = Schema.Struct({ - cwd: V2TurnStartParams__AbsolutePathBuf, + cwd: V2TurnStartParams__LegacyAppPathString, environmentId: Schema.String, + runtimeWorkspaceRoots: Schema.optionalKey( + Schema.Union([ + Schema.Array(V2TurnStartParams__LegacyAppPathString).annotate({ + description: "Environment-native runtime workspace roots. Omitted defaults to `cwd`.", + }), + Schema.Null, + ]), + ), }); export type V2TurnStartResponse = { readonly turn: V2TurnStartResponse__Turn }; diff --git a/packages/effect-codex-app-server/src/protocol.test.ts b/packages/effect-codex-app-server/src/protocol.test.ts index 0ed81b3b9e6b..a68abd537a88 100644 --- a/packages/effect-codex-app-server/src/protocol.test.ts +++ b/packages/effect-codex-app-server/src/protocol.test.ts @@ -23,6 +23,15 @@ const decodeJson = Schema.decodeEffect(Schema.UnknownFromJsonString); const decodeAccountTokenUsageResponse = Schema.decodeUnknownEffect( CodexRpc.CLIENT_REQUEST_RESPONSES["account/usage/read"], ); +const decodeAccountRateLimitsResponse = Schema.decodeUnknownEffect( + CodexRpc.CLIENT_REQUEST_RESPONSES["account/rateLimits/read"], +); +const decodeConsumeRateLimitResetCreditParams = Schema.decodeUnknownEffect( + CodexRpc.CLIENT_REQUEST_PARAMS["account/rateLimitResetCredit/consume"], +); +const decodeConsumeRateLimitResetCreditResponse = Schema.decodeUnknownEffect( + CodexRpc.CLIENT_REQUEST_RESPONSES["account/rateLimitResetCredit/consume"], +); it.layer(NodeServices.layer)("effect-codex-app-server protocol", (it) => { it.effect("maps account usage responses to the upstream token usage schema", () => @@ -42,6 +51,83 @@ it.layer(NodeServices.layer)("effect-codex-app-server protocol", (it) => { }), ); + it.effect("maps earned rate-limit reset credits from account rate-limit snapshots", () => + Effect.gen(function* () { + assert.strictEqual( + CodexRpc.CLIENT_REQUEST_RESPONSES["account/rateLimits/read"], + CodexSchema.V2GetAccountRateLimitsResponse, + ); + + const response = { + rateLimits: {}, + rateLimitResetCredits: { + availableCount: 2, + credits: [ + { + id: "RateLimitResetCredit_1", + resetType: "codexRateLimits", + status: "available", + grantedAt: 1_781_654_400, + expiresAt: 1_784_246_400, + title: "Full reset", + description: "Ready to redeem", + }, + { + id: "RateLimitResetCredit_2", + resetType: "unknown", + status: "unknown", + grantedAt: 1_781_654_401, + expiresAt: null, + }, + ], + }, + } as const; + + assert.deepEqual(yield* decodeAccountRateLimitsResponse(response), response); + assert.deepEqual( + yield* decodeAccountRateLimitsResponse({ + rateLimits: {}, + rateLimitResetCredits: { availableCount: 2, credits: null }, + }), + { + rateLimits: {}, + rateLimitResetCredits: { availableCount: 2, credits: null }, + }, + ); + }), + ); + + it.effect("maps the earned rate-limit reset consume request and response", () => + Effect.gen(function* () { + assert.equal( + CodexRpc.CLIENT_REQUEST_METHODS["account/rateLimitResetCredit/consume"], + "account/rateLimitResetCredit/consume", + ); + assert.strictEqual( + CodexRpc.CLIENT_REQUEST_PARAMS["account/rateLimitResetCredit/consume"], + CodexSchema.V2ConsumeAccountRateLimitResetCreditParams, + ); + assert.strictEqual( + CodexRpc.CLIENT_REQUEST_RESPONSES["account/rateLimitResetCredit/consume"], + CodexSchema.V2ConsumeAccountRateLimitResetCreditResponse, + ); + + assert.deepEqual( + yield* decodeConsumeRateLimitResetCreditParams({ + idempotencyKey: "8ae96ff3-3425-4f4c-8772-b6fd61502868", + creditId: "RateLimitResetCredit_1", + }), + { + idempotencyKey: "8ae96ff3-3425-4f4c-8772-b6fd61502868", + creditId: "RateLimitResetCredit_1", + }, + ); + assert.deepEqual(yield* decodeConsumeRateLimitResetCreditResponse({ outcome: "reset" }), { + outcome: "reset", + }); + }), + ); + it.effect( "encodes requests without a jsonrpc field and routes inbound requests and notifications", () => diff --git a/packages/shared/src/cliArgs.test.ts b/packages/shared/src/cliArgs.test.ts index adf2a3f03c05..1fc6ab0215e4 100644 --- a/packages/shared/src/cliArgs.test.ts +++ b/packages/shared/src/cliArgs.test.ts @@ -1,6 +1,27 @@ import { describe, expect, it } from "vite-plus/test"; -import { parseCliArgs } from "./cliArgs.ts"; +import { parseCliArgs, tokenizeCliArgs } from "./cliArgs.ts"; + +describe("tokenizeCliArgs", () => { + it("preserves quoted values and escaped spaces", () => { + expect( + tokenizeCliArgs( + String.raw`--config model="gpt 5" --enable foo\ bar --config=profile='work profile'`, + ), + ).toEqual(["--config", "model=gpt 5", "--enable", "foo bar", "--config=profile=work profile"]); + }); + + it("preserves literal backslashes in path values", () => { + expect( + tokenizeCliArgs(String.raw`--config cacheDir=C:\Users\me --config "quoted=C:\Users\me"`), + ).toEqual([ + "--config", + String.raw`cacheDir=C:\Users\me`, + "--config", + String.raw`quoted=C:\Users\me`, + ]); + }); +}); describe("parseCliArgs", () => { it("returns empty result for empty string", () => { @@ -57,6 +78,13 @@ describe("parseCliArgs", () => { }); }); + it("parses quoted --append-system-prompt with value and --chrome", () => { + expect(parseCliArgs(`--append-system-prompt "always think step by step" --chrome`)).toEqual({ + flags: { "append-system-prompt": "always think step by step", chrome: null }, + positionals: [], + }); + }); + it("parses --max-budget-usd with numeric value", () => { expect(parseCliArgs("--chrome --max-budget-usd 5.00")).toEqual({ flags: { chrome: null, "max-budget-usd": "5.00" }, diff --git a/packages/shared/src/cliArgs.ts b/packages/shared/src/cliArgs.ts index 20920093302b..69851f2f3fb3 100644 --- a/packages/shared/src/cliArgs.ts +++ b/packages/shared/src/cliArgs.ts @@ -7,10 +7,67 @@ export interface ParseCliArgsOptions { readonly booleanFlags?: readonly string[]; } +export function tokenizeCliArgs(args?: string): ReadonlyArray { + const input = args?.trim(); + if (!input) return []; + + const tokens: string[] = []; + let current = ""; + let quote: "'" | '"' | undefined; + let quoted = false; + + for (let index = 0; index < input.length; index++) { + const char = input[index]; + if (char === undefined) continue; + + if (quote) { + if (char === quote) { + quote = undefined; + quoted = true; + } else if (char === "\\" && quote === '"') { + const next = input[index + 1]; + if (next !== undefined && ['"', "\\", "$", "`"].includes(next)) { + current += next; + index++; + } else { + current += char; + } + } else { + current += char; + } + continue; + } + + if (char === "'" || char === '"') { + quote = char; + quoted = true; + } else if (/\s/.test(char)) { + if (current || quoted) { + tokens.push(current); + current = ""; + quoted = false; + } + } else if (char === "\\") { + const next = input[index + 1]; + if (next !== undefined && /\s/.test(next)) { + current += next; + index++; + } else { + current += char; + } + } else { + current += char; + } + } + + if (current || quoted) tokens.push(current); + return tokens; +} + /** * Parse CLI-style arguments into flags and positionals. * - * Accepts a string (split by whitespace) or a pre-split argv array. + * Accepts a string (quote-aware tokenized) or a pre-split argv array. * Supports `--key value`, `--key=value`, and `--flag` (boolean) syntax. * * parseCliArgs("") @@ -32,8 +89,7 @@ export function parseCliArgs( args: string | readonly string[], options?: ParseCliArgsOptions, ): ParsedCliArgs { - const tokens = - typeof args === "string" ? args.trim().split(/\s+/).filter(Boolean) : Array.from(args); + const tokens = typeof args === "string" ? tokenizeCliArgs(args) : Array.from(args); const booleanSet = options?.booleanFlags ? new Set(options.booleanFlags) : undefined; const flags: Record = {}; diff --git a/packages/shared/src/model.test.ts b/packages/shared/src/model.test.ts index 2e1276672f88..b055c255bd7a 100644 --- a/packages/shared/src/model.test.ts +++ b/packages/shared/src/model.test.ts @@ -1,13 +1,7 @@ import { describe, expect, it } from "vite-plus/test"; -import { - DEFAULT_MODEL, - ProviderDriverKind, - ProviderInstanceId, - type ModelCapabilities, -} from "@t3tools/contracts"; +import { ProviderDriverKind, ProviderInstanceId, type ModelCapabilities } from "@t3tools/contracts"; import { - applyClaudePromptEffortPrefix, buildProviderOptionSelectionsFromDescriptors, createModelCapabilities, createModelSelection, @@ -16,11 +10,8 @@ import { getProviderOptionDescriptors, getProviderOptionBooleanSelectionValue, getProviderOptionStringSelectionValue, - isClaudeUltrathinkPrompt, + normalizeCustomModelSlug, normalizeModelSlug, - resolveModelSlugForProvider, - resolveSelectableModel, - trimOrNull, } from "./model.ts"; const codexCaps: ModelCapabilities = createModelCapabilities({ @@ -70,91 +61,6 @@ const claudeCaps: ModelCapabilities = createModelCapabilities({ ], }); -describe("normalizeModelSlug", () => { - it("maps known aliases to canonical slugs", () => { - const claude = ProviderDriverKind.make("claudeAgent"); - expect(normalizeModelSlug("gpt-5-codex")).toBe("gpt-5.4"); - expect(normalizeModelSlug("5.3")).toBe("gpt-5.3-codex"); - expect(normalizeModelSlug("sonnet", claude)).toBe("sonnet"); - expect(normalizeModelSlug("sonnet-5", claude)).toBe("claude-sonnet-5"); - expect(normalizeModelSlug("sonnet-4.6", claude)).toBe("claude-sonnet-4-6"); - }); - - it("returns null for empty or missing values", () => { - expect(normalizeModelSlug("")).toBeNull(); - expect(normalizeModelSlug(" ")).toBeNull(); - expect(normalizeModelSlug(null)).toBeNull(); - expect(normalizeModelSlug(undefined)).toBeNull(); - }); -}); - -describe("resolveModelSlugForProvider", () => { - it("returns defaults when the model is missing", () => { - expect(resolveModelSlugForProvider(ProviderDriverKind.make("codex"), undefined)).toBe( - DEFAULT_MODEL, - ); - expect(resolveModelSlugForProvider(ProviderDriverKind.make("ollama"), undefined)).toBe( - DEFAULT_MODEL, - ); - expect(resolveModelSlugForProvider(ProviderDriverKind.make("grok"), undefined)).toBe( - "grok-build", - ); - }); - - it("preserves normalized unknown models", () => { - expect( - resolveModelSlugForProvider(ProviderDriverKind.make("codex"), "custom/internal-model"), - ).toBe("custom/internal-model"); - }); -}); - -describe("resolveSelectableModel", () => { - it("resolves exact slugs, labels, and aliases", () => { - const options = [ - { slug: "gpt-5.3-codex", name: "GPT-5.3 Codex" }, - { slug: "claude-sonnet-5", name: "Claude Sonnet 5" }, - { slug: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" }, - ]; - expect(resolveSelectableModel(ProviderDriverKind.make("codex"), "gpt-5.3-codex", options)).toBe( - "gpt-5.3-codex", - ); - expect(resolveSelectableModel(ProviderDriverKind.make("codex"), "gpt-5.3 codex", options)).toBe( - "gpt-5.3-codex", - ); - expect(resolveSelectableModel(ProviderDriverKind.make("claudeAgent"), "sonnet", options)).toBe( - null, - ); - expect( - resolveSelectableModel(ProviderDriverKind.make("claudeAgent"), "sonnet-5", options), - ).toBe("claude-sonnet-5"); - expect( - resolveSelectableModel(ProviderDriverKind.make("claudeAgent"), "sonnet-4.6", options), - ).toBe("claude-sonnet-4-6"); - }); -}); - -describe("misc helpers", () => { - it("detects ultrathink prompts", () => { - expect(isClaudeUltrathinkPrompt("Please ultrathink about this")).toBe(true); - expect(isClaudeUltrathinkPrompt("Ultrathink:\nInvestigate")).toBe(true); - expect(isClaudeUltrathinkPrompt("Investigate")).toBe(false); - }); - - it("prefixes ultrathink prompts once", () => { - expect(applyClaudePromptEffortPrefix("Investigate", "ultrathink")).toBe( - "Ultrathink:\nInvestigate", - ); - expect(applyClaudePromptEffortPrefix("Ultrathink:\nInvestigate", "ultrathink")).toBe( - "Ultrathink:\nInvestigate", - ); - }); - - it("trims strings to null", () => { - expect(trimOrNull(" hi ")).toBe("hi"); - expect(trimOrNull(" ")).toBeNull(); - }); -}); - describe("descriptor helpers", () => { it("applies selection values to capability descriptors", () => { expect( @@ -240,3 +146,12 @@ describe("descriptor helpers", () => { expect(getModelSelectionBooleanOptionValue(selection, "fastMode")).toBe(true); }); }); + +describe("model slug normalization", () => { + it("preserves exact custom slugs instead of expanding provider aliases", () => { + const claude = ProviderDriverKind.make("claudeAgent"); + + expect(normalizeModelSlug("opus", claude)).toBe("claude-opus-4-8"); + expect(normalizeCustomModelSlug(" opus ")).toBe("opus"); + }); +}); diff --git a/packages/shared/src/model.ts b/packages/shared/src/model.ts index 9fdbd6c04470..bdc0c0cc8efb 100644 --- a/packages/shared/src/model.ts +++ b/packages/shared/src/model.ts @@ -236,11 +236,7 @@ export function normalizeModelSlug( model: string | null | undefined, provider: ProviderDriverKind = DEFAULT_PROVIDER_DRIVER_KIND, ): string | null { - if (typeof model !== "string") { - return null; - } - - const trimmed = model.trim(); + const trimmed = normalizeCustomModelSlug(model); if (!trimmed) { return null; } @@ -252,6 +248,15 @@ export function normalizeModelSlug( return typeof aliased === "string" ? aliased : trimmed; } +/** Custom model identifiers are provider-owned, so only trim them; never expand aliases. */ +export function normalizeCustomModelSlug(model: string | null | undefined): string | null { + if (typeof model !== "string") { + return null; + } + + return model.trim() || null; +} + export function resolveSelectableModel( provider: ProviderDriverKind, value: string | null | undefined,