Group app-server connection, protocol, and turn projections

This commit is contained in:
murashit 2026-06-12 15:28:21 +09:00
parent 998182a182
commit 31e30b637a
136 changed files with 704 additions and 426 deletions

View file

@ -1,51 +1,51 @@
import type { InitializeResponse } from "../generated/app-server/InitializeResponse";
import type { CollaborationMode } from "../generated/app-server/CollaborationMode";
import type { RequestId } from "../generated/app-server/RequestId";
import type { ReasoningEffort } from "../generated/app-server/ReasoningEffort";
import type { ApprovalsReviewer } from "../generated/app-server/v2/ApprovalsReviewer";
import type { ConfigReadResponse } from "../generated/app-server/v2/ConfigReadResponse";
import type { ConfigWriteResponse } from "../generated/app-server/v2/ConfigWriteResponse";
import type { FsReadFileResponse } from "../generated/app-server/v2/FsReadFileResponse";
import type { GetAccountRateLimitsResponse } from "../generated/app-server/v2/GetAccountRateLimitsResponse";
import type { HookTrustStatus } from "../generated/app-server/v2/HookTrustStatus";
import type { HooksListResponse } from "../generated/app-server/v2/HooksListResponse";
import type { CollaborationModeListResponse } from "../generated/app-server/v2/CollaborationModeListResponse";
import type { ListMcpServerStatusParams } from "../generated/app-server/v2/ListMcpServerStatusParams";
import type { ListMcpServerStatusResponse } from "../generated/app-server/v2/ListMcpServerStatusResponse";
import type { ModelListResponse } from "../generated/app-server/v2/ModelListResponse";
import type { ModelProviderCapabilitiesReadResponse } from "../generated/app-server/v2/ModelProviderCapabilitiesReadResponse";
import type { SkillsListResponse } from "../generated/app-server/v2/SkillsListResponse";
import type { ThreadArchiveResponse } from "../generated/app-server/v2/ThreadArchiveResponse";
import type { ThreadForkResponse } from "../generated/app-server/v2/ThreadForkResponse";
import type { ThreadGoalClearResponse } from "../generated/app-server/v2/ThreadGoalClearResponse";
import type { ThreadGoalGetResponse } from "../generated/app-server/v2/ThreadGoalGetResponse";
import type { ThreadGoalSetResponse } from "../generated/app-server/v2/ThreadGoalSetResponse";
import type { ThreadInjectItemsResponse } from "../generated/app-server/v2/ThreadInjectItemsResponse";
import type { ThreadListResponse } from "../generated/app-server/v2/ThreadListResponse";
import type { ThreadReadResponse } from "../generated/app-server/v2/ThreadReadResponse";
import type { ThreadResumeResponse } from "../generated/app-server/v2/ThreadResumeResponse";
import type { ThreadRollbackResponse } from "../generated/app-server/v2/ThreadRollbackResponse";
import type { ThreadSetNameResponse } from "../generated/app-server/v2/ThreadSetNameResponse";
import type { ThreadSettingsUpdateResponse } from "../generated/app-server/v2/ThreadSettingsUpdateResponse";
import type { ThreadCompactStartResponse } from "../generated/app-server/v2/ThreadCompactStartResponse";
import type { SortDirection } from "../generated/app-server/v2/SortDirection";
import type { ThreadStartResponse } from "../generated/app-server/v2/ThreadStartResponse";
import type { ThreadTurnsListResponse } from "../generated/app-server/v2/ThreadTurnsListResponse";
import type { ThreadUnarchiveResponse } from "../generated/app-server/v2/ThreadUnarchiveResponse";
import type { TurnItemsView } from "../generated/app-server/v2/TurnItemsView";
import type { TurnInterruptResponse } from "../generated/app-server/v2/TurnInterruptResponse";
import type { TurnStartResponse } from "../generated/app-server/v2/TurnStartResponse";
import type { TurnSteerResponse } from "../generated/app-server/v2/TurnSteerResponse";
import type { UserInput } from "../generated/app-server/v2/UserInput";
import { CLIENT_VERSION } from "../constants";
import type { InitializeResponse } from "../../generated/app-server/InitializeResponse";
import type { CollaborationMode } from "../../generated/app-server/CollaborationMode";
import type { RequestId } from "../../generated/app-server/RequestId";
import type { ReasoningEffort } from "../../generated/app-server/ReasoningEffort";
import type { ApprovalsReviewer } from "../../generated/app-server/v2/ApprovalsReviewer";
import type { ConfigReadResponse } from "../../generated/app-server/v2/ConfigReadResponse";
import type { ConfigWriteResponse } from "../../generated/app-server/v2/ConfigWriteResponse";
import type { FsReadFileResponse } from "../../generated/app-server/v2/FsReadFileResponse";
import type { GetAccountRateLimitsResponse } from "../../generated/app-server/v2/GetAccountRateLimitsResponse";
import type { HookTrustStatus } from "../../generated/app-server/v2/HookTrustStatus";
import type { HooksListResponse } from "../../generated/app-server/v2/HooksListResponse";
import type { CollaborationModeListResponse } from "../../generated/app-server/v2/CollaborationModeListResponse";
import type { ListMcpServerStatusParams } from "../../generated/app-server/v2/ListMcpServerStatusParams";
import type { ListMcpServerStatusResponse } from "../../generated/app-server/v2/ListMcpServerStatusResponse";
import type { ModelListResponse } from "../../generated/app-server/v2/ModelListResponse";
import type { ModelProviderCapabilitiesReadResponse } from "../../generated/app-server/v2/ModelProviderCapabilitiesReadResponse";
import type { SkillsListResponse } from "../../generated/app-server/v2/SkillsListResponse";
import type { ThreadArchiveResponse } from "../../generated/app-server/v2/ThreadArchiveResponse";
import type { ThreadForkResponse } from "../../generated/app-server/v2/ThreadForkResponse";
import type { ThreadGoalClearResponse } from "../../generated/app-server/v2/ThreadGoalClearResponse";
import type { ThreadGoalGetResponse } from "../../generated/app-server/v2/ThreadGoalGetResponse";
import type { ThreadGoalSetResponse } from "../../generated/app-server/v2/ThreadGoalSetResponse";
import type { ThreadInjectItemsResponse } from "../../generated/app-server/v2/ThreadInjectItemsResponse";
import type { ThreadListResponse } from "../../generated/app-server/v2/ThreadListResponse";
import type { ThreadReadResponse } from "../../generated/app-server/v2/ThreadReadResponse";
import type { ThreadResumeResponse } from "../../generated/app-server/v2/ThreadResumeResponse";
import type { ThreadRollbackResponse } from "../../generated/app-server/v2/ThreadRollbackResponse";
import type { ThreadSetNameResponse } from "../../generated/app-server/v2/ThreadSetNameResponse";
import type { ThreadSettingsUpdateResponse } from "../../generated/app-server/v2/ThreadSettingsUpdateResponse";
import type { ThreadCompactStartResponse } from "../../generated/app-server/v2/ThreadCompactStartResponse";
import type { SortDirection } from "../../generated/app-server/v2/SortDirection";
import type { ThreadStartResponse } from "../../generated/app-server/v2/ThreadStartResponse";
import type { ThreadTurnsListResponse } from "../../generated/app-server/v2/ThreadTurnsListResponse";
import type { ThreadUnarchiveResponse } from "../../generated/app-server/v2/ThreadUnarchiveResponse";
import type { TurnItemsView } from "../../generated/app-server/v2/TurnItemsView";
import type { TurnInterruptResponse } from "../../generated/app-server/v2/TurnInterruptResponse";
import type { TurnStartResponse } from "../../generated/app-server/v2/TurnStartResponse";
import type { TurnSteerResponse } from "../../generated/app-server/v2/TurnSteerResponse";
import type { UserInput } from "../../generated/app-server/v2/UserInput";
import { CLIENT_VERSION } from "../../constants";
import { StdioAppServerTransport, type AppServerTransport, type AppServerTransportHandlers } from "./transport";
import type { ClientRequestMethod, ClientRequestParams, PendingRequest, RpcError, RpcInboundMessage, RpcOutboundMessage } from "./types";
import type { ServerNotification } from "../generated/app-server/ServerNotification";
import type { ServerRequest } from "../generated/app-server/ServerRequest";
import type { JsonValue } from "../generated/app-server/serde_json/JsonValue";
import { toAppServerUserInput, type CodexInput } from "./request-input";
import { appServerThreadGoalUpdate, type ThreadGoalUpdate } from "./thread-goal";
import type { ServiceTierRequest, ThreadSettingsUpdate } from "./thread-settings";
import type { ClientRequestMethod, ClientRequestParams, PendingRequest, RpcError, RpcInboundMessage, RpcOutboundMessage } from "./rpc-messages";
import type { ServerNotification } from "../../generated/app-server/ServerNotification";
import type { ServerRequest } from "../../generated/app-server/ServerRequest";
import type { JsonValue } from "../../generated/app-server/serde_json/JsonValue";
import { toAppServerUserInput, type CodexInput } from "../protocol/request-input";
import { appServerThreadGoalUpdate, type ThreadGoalUpdate } from "../protocol/thread-goal";
import type { ServiceTierRequest, ThreadSettingsUpdate } from "../protocol/thread-settings";
const DEFAULT_REQUEST_TIMEOUT_MS = 120_000;
const MAX_SUPPRESSED_ORPHAN_RESPONSES = 256;

View file

@ -1,7 +1,7 @@
import type { ServerNotification } from "../generated/app-server/ServerNotification";
import type { ServerRequest } from "../generated/app-server/ServerRequest";
import type { ServerNotification } from "../../generated/app-server/ServerNotification";
import type { ServerRequest } from "../../generated/app-server/ServerRequest";
import { AppServerClient, type AppServerClientHandlers } from "./client";
import { appServerInitializationFromResponse, type AppServerInitialization } from "./initialization";
import { appServerInitializationFromResponse, type AppServerInitialization } from "../protocol/initialization";
export interface ConnectionManagerHandlers {
onNotification: (notification: ServerNotification) => void;

View file

@ -1,8 +1,8 @@
import type { ClientNotification } from "../generated/app-server/ClientNotification";
import type { ClientRequest } from "../generated/app-server/ClientRequest";
import type { RequestId } from "../generated/app-server/RequestId";
import type { ServerNotification } from "../generated/app-server/ServerNotification";
import type { ServerRequest } from "../generated/app-server/ServerRequest";
import type { ClientNotification } from "../../generated/app-server/ClientNotification";
import type { ClientRequest } from "../../generated/app-server/ClientRequest";
import type { RequestId } from "../../generated/app-server/RequestId";
import type { ServerNotification } from "../../generated/app-server/ServerNotification";
import type { ServerRequest } from "../../generated/app-server/ServerRequest";
export type { RequestId, ServerNotification, ServerRequest };

View file

@ -1,7 +1,7 @@
import { spawn, type ChildProcessWithoutNullStreams } from "child_process";
import * as readline from "readline";
import type { RpcOutboundMessage } from "./types";
import type { RpcOutboundMessage } from "./rpc-messages";
export interface AppServerTransport {
start(): void;

View file

@ -1,5 +1,5 @@
import type { AppServerHookOperation } from "./client";
import type { HookItem, ModelMetadata, SkillMetadata } from "../domain/catalog/metadata";
import type { AppServerHookOperation } from "../connection/client";
import type { HookItem, ModelMetadata, SkillMetadata } from "../../domain/catalog/metadata";
export interface CatalogModel {
id: string;

View file

@ -1,4 +1,4 @@
import type { InitializeResponse as AppServerInitializeResponse } from "../generated/app-server/InitializeResponse";
import type { InitializeResponse as AppServerInitializeResponse } from "../../generated/app-server/InitializeResponse";
export interface AppServerInitialization {
userAgent: string;

View file

@ -1,4 +1,4 @@
import type { UserInput } from "../generated/app-server/v2/UserInput";
import type { UserInput } from "../../generated/app-server/v2/UserInput";
export interface RequestMention {
name: string;

View file

@ -7,7 +7,7 @@ import {
type ApprovalsReviewer,
type ServiceTier,
} from "./runtime-policy";
import { normalizeReasoningEffort, type ReasoningEffort } from "../domain/catalog/metadata";
import { normalizeReasoningEffort, type ReasoningEffort } from "../../domain/catalog/metadata";
type ReasoningSummary = "auto" | "concise" | "detailed" | "none";
type Verbosity = "low" | "medium" | "high";

View file

@ -1,8 +1,9 @@
import type { RateLimitSnapshot as AppServerRateLimitSnapshot } from "../generated/app-server/v2/RateLimitSnapshot";
import type { RateLimitWindow as AppServerRateLimitWindow } from "../generated/app-server/v2/RateLimitWindow";
import type { SpendControlLimitSnapshot as AppServerSpendControlLimitSnapshot } from "../generated/app-server/v2/SpendControlLimitSnapshot";
import type { ThreadTokenUsage as AppServerThreadTokenUsage } from "../generated/app-server/v2/ThreadTokenUsage";
import type { TokenUsageBreakdown as AppServerTokenUsageBreakdown } from "../generated/app-server/v2/TokenUsageBreakdown";
import type { GetAccountRateLimitsResponse as AppServerAccountRateLimitsResponse } from "../../generated/app-server/v2/GetAccountRateLimitsResponse";
import type { RateLimitSnapshot as AppServerRateLimitSnapshot } from "../../generated/app-server/v2/RateLimitSnapshot";
import type { RateLimitWindow as AppServerRateLimitWindow } from "../../generated/app-server/v2/RateLimitWindow";
import type { SpendControlLimitSnapshot as AppServerSpendControlLimitSnapshot } from "../../generated/app-server/v2/SpendControlLimitSnapshot";
import type { ThreadTokenUsage as AppServerThreadTokenUsage } from "../../generated/app-server/v2/ThreadTokenUsage";
import type { TokenUsageBreakdown as AppServerTokenUsageBreakdown } from "../../generated/app-server/v2/TokenUsageBreakdown";
export interface RateLimitSnapshot {
limitId: string | null;
@ -51,6 +52,14 @@ export function rateLimitSnapshotFromAppServerSnapshot(snapshot: AppServerRateLi
};
}
export function rateLimitSnapshotFromAccountRateLimitsResponse(response: AppServerAccountRateLimitsResponse): RateLimitSnapshot {
return rateLimitSnapshotFromAppServerSnapshot(accountRateLimitSnapshotFromResponse(response));
}
export function accountRateLimitsSummaryFromResponse(response: AppServerAccountRateLimitsResponse): string {
return response.rateLimitsByLimitId ? `${String(Object.keys(response.rateLimitsByLimitId).length)} limits` : "available";
}
export function threadTokenUsageFromAppServerUsage(usage: AppServerThreadTokenUsage): ThreadTokenUsage {
return {
total: tokenUsageBreakdownFromAppServerBreakdown(usage.total),
@ -59,6 +68,12 @@ export function threadTokenUsageFromAppServerUsage(usage: AppServerThreadTokenUs
};
}
function accountRateLimitSnapshotFromResponse(response: AppServerAccountRateLimitsResponse): AppServerRateLimitSnapshot {
const snapshots = response.rateLimitsByLimitId;
const codexRateLimit = snapshots && Object.hasOwn(snapshots, "codex") ? snapshots["codex"] : undefined;
return codexRateLimit ?? response.rateLimits;
}
function rateLimitWindowFromAppServerWindow(window: AppServerRateLimitWindow): RateLimitWindow {
return {
usedPercent: window.usedPercent,

View file

@ -1,6 +1,6 @@
import type { ThreadGoal as AppServerThreadGoal } from "../generated/app-server/v2/ThreadGoal";
import type { ThreadGoalStatus as AppServerThreadGoalStatus } from "../generated/app-server/v2/ThreadGoalStatus";
import type { JsonValue } from "../generated/app-server/serde_json/JsonValue";
import type { ThreadGoal as AppServerThreadGoal } from "../../generated/app-server/v2/ThreadGoal";
import type { ThreadGoalStatus as AppServerThreadGoalStatus } from "../../generated/app-server/v2/ThreadGoalStatus";
import type { JsonValue } from "../../generated/app-server/serde_json/JsonValue";
export type ThreadGoalStatus = "active" | "paused" | "blocked" | "usageLimited" | "budgetLimited" | "complete";

View file

@ -1,9 +1,9 @@
import type { CollaborationMode } from "../generated/app-server/CollaborationMode";
import type { ModeKind } from "../generated/app-server/ModeKind";
import type { Personality } from "../generated/app-server/Personality";
import type { ReasoningEffort } from "../generated/app-server/ReasoningEffort";
import type { ReasoningSummary } from "../generated/app-server/ReasoningSummary";
import type { SandboxPolicy } from "../generated/app-server/v2/SandboxPolicy";
import type { CollaborationMode } from "../../generated/app-server/CollaborationMode";
import type { ModeKind } from "../../generated/app-server/ModeKind";
import type { Personality } from "../../generated/app-server/Personality";
import type { ReasoningEffort } from "../../generated/app-server/ReasoningEffort";
import type { ReasoningSummary } from "../../generated/app-server/ReasoningSummary";
import type { SandboxPolicy } from "../../generated/app-server/v2/SandboxPolicy";
import type { ApprovalPolicy, ApprovalsReviewer } from "./runtime-policy";
export type ServiceTierRequest = string | null | undefined;

View file

@ -1,4 +1,4 @@
import type { Thread } from "../domain/threads/model";
import type { Thread } from "../../domain/threads/model";
export interface ThreadRecord {
id: string;

View file

@ -1,13 +1,13 @@
import type { FileUpdateChange as GeneratedFileUpdateChange } from "../generated/app-server/v2/FileUpdateChange";
import type { ThreadItem as GeneratedTurnItem } from "../generated/app-server/v2/ThreadItem";
import type { Turn as GeneratedTurnRecord } from "../generated/app-server/v2/Turn";
import type { UserInput } from "../generated/app-server/v2/UserInput";
import type { FileUpdateChange as GeneratedFileUpdateChange } from "../../generated/app-server/v2/FileUpdateChange";
import type { ThreadItem as GeneratedTurnItem } from "../../generated/app-server/v2/ThreadItem";
import type { Turn as GeneratedTurnRecord } from "../../generated/app-server/v2/Turn";
import type { UserInput } from "../../generated/app-server/v2/UserInput";
import {
conversationSummaryFromTranscriptEntries,
nonEmptyConversationSummaries,
type ThreadConversationSummary,
type ThreadTranscriptEntry,
} from "../domain/threads/transcript";
} from "../../domain/threads/transcript";
export type FileUpdateChange = GeneratedFileUpdateChange;
export type TurnItem = GeneratedTurnItem;
@ -17,18 +17,37 @@ export function transcriptEntriesFromTurnRecord(turn: TurnRecord): ThreadTranscr
return turn.items.flatMap((item) => transcriptEntriesFromTurnItem(item, turn));
}
export function transcriptEntriesFromTurnRecords(turns: readonly TurnRecord[]): ThreadTranscriptEntry[] {
return turns.flatMap(transcriptEntriesFromTurnRecord);
}
export function conversationSummaryFromTurnRecord(turn: TurnRecord): ThreadConversationSummary {
return conversationSummaryFromTranscriptEntries(transcriptEntriesFromTurnRecord(turn));
}
export function conversationAssistantTextFromTurnRecord(turn: TurnRecord): string | null {
return conversationSummaryFromTurnRecord(turn).assistantText;
}
export function completedConversationSummaryFromTurnRecord(turn: TurnRecord): ThreadConversationSummary | null {
if (turn.status !== "completed") return null;
const summary = conversationSummaryFromTurnRecord(turn);
return summary.userText && summary.assistantText ? summary : null;
}
export function completedConversationSummariesFromTurnRecords(turns: readonly TurnRecord[]): ThreadConversationSummary[] {
return turns.flatMap((turn) => {
const summary = completedConversationSummaryFromTurnRecord(turn);
return summary ? [summary] : [];
});
}
export function conversationSummariesFromTurnRecords(turns: readonly TurnRecord[]): ThreadConversationSummary[] {
return nonEmptyConversationSummaries(turns.map(conversationSummaryFromTurnRecord));
}
export function chronologicalConversationSummariesFromTurnRecords(turns: readonly TurnRecord[]): ThreadConversationSummary[] {
return nonEmptyConversationSummaries(chronologicalTurnRecords(turns).map(conversationSummaryFromTurnRecord));
return conversationSummariesFromTurnRecords(chronologicalTurnRecords(turns));
}
export function turnUserItemText(item: Extract<TurnItem, { type: "userMessage" }>): string {

View file

@ -3,16 +3,16 @@ import {
type AppServerClientHandlers,
type AppServerStartEphemeralThreadOptions,
type AppServerStartStructuredTurnOptions,
} from "./client";
import { abortablePromise, throwIfAbortSignalAborted } from "../shared/lifecycle/abortable";
import type { InitializeResponse } from "../generated/app-server/InitializeResponse";
import type { RequestId } from "../generated/app-server/RequestId";
import type { ServerNotification } from "../generated/app-server/ServerNotification";
import type { JsonValue } from "../generated/app-server/serde_json/JsonValue";
import type { ModelListResponse } from "../generated/app-server/v2/ModelListResponse";
import type { ThreadStartResponse } from "../generated/app-server/v2/ThreadStartResponse";
import type { TurnStartResponse } from "../generated/app-server/v2/TurnStartResponse";
import type { TurnItem, TurnRecord } from "./turn";
} from "../connection/client";
import { abortablePromise, throwIfAbortSignalAborted } from "../../shared/lifecycle/abortable";
import type { InitializeResponse } from "../../generated/app-server/InitializeResponse";
import type { RequestId } from "../../generated/app-server/RequestId";
import type { ServerNotification } from "../../generated/app-server/ServerNotification";
import type { JsonValue } from "../../generated/app-server/serde_json/JsonValue";
import type { ModelListResponse } from "../../generated/app-server/v2/ModelListResponse";
import type { ThreadStartResponse } from "../../generated/app-server/v2/ThreadStartResponse";
import type { TurnStartResponse } from "../../generated/app-server/v2/TurnStartResponse";
import type { TurnItem, TurnRecord } from "../protocol/turn";
export type StructuredTurnOutputSchema = JsonValue;

View file

@ -1,13 +1,13 @@
import type { AppServerClient } from "./client";
import type { AppServerClient } from "../connection/client";
import {
appServerHookOperationFromHookItem,
hookItemsFromCatalogHooks,
modelMetadataFromCatalogModels,
skillMetadataFromCatalogSkills,
} from "./catalog";
import { threadFromThreadRecord, threadsFromThreadRecords } from "./thread";
import type { HookItem, ModelMetadata, SkillMetadata } from "../domain/catalog/metadata";
import type { Thread } from "../domain/threads/model";
} from "../protocol/catalog";
import { threadFromThreadRecord, threadsFromThreadRecords } from "../protocol/thread";
import type { HookItem, ModelMetadata, SkillMetadata } from "../../domain/catalog/metadata";
import type { Thread } from "../../domain/threads/model";
export interface HookData {
hooks: HookItem[];

View file

@ -1,4 +1,4 @@
import type { ThreadTokenUsage, TokenUsageBreakdown } from "./runtime-metrics";
import type { ThreadTokenUsage, TokenUsageBreakdown } from "../protocol/runtime-metrics";
export const ROLLOUT_TOKEN_USAGE_READ_TIMEOUT_MS = 2_000;
export const ROLLOUT_TOKEN_USAGE_MAX_BASE64_BYTES = 12 * 1024 * 1024;

View file

@ -1,8 +1,8 @@
import type { Diagnostics } from "./diagnostics";
import type { RateLimitSnapshot } from "./runtime-metrics";
import { cloneRuntimeConfigSnapshot, type RuntimeConfigSnapshot } from "./runtime-config";
import type { Thread } from "../domain/threads/model";
import type { ModelMetadata, SkillMetadata } from "../domain/catalog/metadata";
import type { Diagnostics } from "../protocol/diagnostics";
import type { RateLimitSnapshot } from "../protocol/runtime-metrics";
import { cloneRuntimeConfigSnapshot, type RuntimeConfigSnapshot } from "../protocol/runtime-config";
import type { Thread } from "../../domain/threads/model";
import type { ModelMetadata, SkillMetadata } from "../../domain/catalog/metadata";
export interface SharedAppServerMetadata {
runtimeConfig: RuntimeConfigSnapshot | null;

View file

@ -1,5 +1,5 @@
import type { Thread } from "../domain/threads/model";
import type { ModelMetadata } from "../domain/catalog/metadata";
import type { Thread } from "../../domain/threads/model";
import type { ModelMetadata } from "../../domain/catalog/metadata";
import {
applySharedAppServerMetadata,
applySharedModels,

View file

@ -1,6 +1,6 @@
import type { Thread } from "../domain/threads/model";
import type { ActivePermissionProfile, ApprovalPolicy, ApprovalsReviewer, ServiceTier } from "./runtime-policy";
import { threadFromThreadRecord, type ThreadRecord } from "./thread";
import type { Thread } from "../../domain/threads/model";
import type { ActivePermissionProfile, ApprovalPolicy, ApprovalsReviewer, ServiceTier } from "../protocol/runtime-policy";
import { threadFromThreadRecord, type ThreadRecord } from "../protocol/thread";
export interface ThreadActivationSnapshot {
thread: Thread;

View file

@ -1,5 +1,5 @@
import type { Thread } from "../../domain/threads/model";
import type { SharedAppServerMetadata } from "../../app-server/shared-cache-state";
import type { SharedAppServerMetadata } from "../../app-server/services/shared-cache-state";
import type { CodexPanelSettings } from "../../settings/model";
import type { ChatTurnDiffViewState } from "./turn-diff/model";

View file

@ -1,4 +1,4 @@
import type { AppServerClient } from "../../app-server/client";
import type { AppServerClient } from "../../app-server/connection/client";
import type { DisplayDetailSection, DisplayItem } from "./display/types";
import type { ChatStateStore } from "./state/reducer";
import type { ChatViewRenderController } from "./panel/view-render-controller";

View file

@ -1,8 +1,8 @@
import type { App, Component, EventRef } from "obsidian";
import type { ComponentChild as UiNode } from "preact";
import type { AppServerClient } from "../../app-server/client";
import type { SharedAppServerMetadata } from "../../app-server/shared-cache-state";
import type { AppServerClient } from "../../app-server/connection/client";
import type { SharedAppServerMetadata } from "../../app-server/services/shared-cache-state";
import type { ArchiveExportAdapter } from "../thread-export/archive-markdown";
import type { Thread } from "../../domain/threads/model";
import type { CodexPanelSettings } from "../../settings/model";

View file

@ -1,4 +1,4 @@
import { ConnectionManager } from "../../app-server/connection-manager";
import { ConnectionManager } from "../../app-server/connection/connection-manager";
import type { ChatServerDiagnosticsActions } from "./connection/server-actions/diagnostics";
import type { ChatServerMetadataActions } from "./connection/server-actions/metadata";
import type { ChatServerThreadActions } from "./connection/server-actions/threads";

View file

@ -1,9 +1,9 @@
import { Notice } from "obsidian";
import type { ConnectionManager } from "../../../app-server/connection-manager";
import type { ConnectionManager } from "../../../app-server/connection/connection-manager";
import type { RuntimeSnapshot } from "../runtime/snapshot";
import type { ChatState, ChatStateStore } from "../state/reducer";
import type { SharedAppServerMetadata } from "../../../app-server/shared-cache-state";
import type { SharedAppServerMetadata } from "../../../app-server/services/shared-cache-state";
import type { Thread } from "../../../domain/threads/model";
import type { CodexPanelSettings } from "../../../settings/model";
import { createChatServerDiagnosticsActions, type ChatServerDiagnosticsActions } from "./server-actions/diagnostics";

View file

@ -1,6 +1,6 @@
import { StaleConnectionError } from "../../../app-server/connection-manager";
import type { AppServerClient } from "../../../app-server/client";
import type { AppServerInitialization } from "../../../app-server/initialization";
import { StaleConnectionError } from "../../../app-server/connection/connection-manager";
import type { AppServerClient } from "../../../app-server/connection/client";
import type { AppServerInitialization } from "../../../app-server/protocol/initialization";
import type { ChatStateStore } from "../state/reducer";
import type { ChatConnectionWorkTracker, ActiveChatConnection } from "../lifecycle";

View file

@ -1,4 +1,4 @@
import type { AppServerClient } from "../../../../app-server/client";
import type { AppServerClient } from "../../../../app-server/connection/client";
import {
diagnosticProbeError,
diagnosticProbeOk,
@ -9,8 +9,9 @@ import {
type DiagnosticProbeMethod,
type McpServerStartupStatus,
type McpServerStatusSummary,
} from "../../../../app-server/diagnostics";
import type { SharedAppServerMetadata } from "../../../../app-server/shared-cache-state";
} from "../../../../app-server/protocol/diagnostics";
import { accountRateLimitsSummaryFromResponse } from "../../../../app-server/protocol/runtime-metrics";
import type { SharedAppServerMetadata } from "../../../../app-server/services/shared-cache-state";
import { mcpStatusLines as buildMcpStatusLines } from "../../display/status/diagnostics";
import { cloneAppServerDiagnostics, type ChatServerActionHost } from "./host";
@ -75,7 +76,7 @@ async function refreshDiagnosticProbes(
probeDiagnostic(
"account/rateLimits/read",
() => client.readAccountRateLimits(),
(response) => (response.rateLimitsByLimitId ? `${String(Object.keys(response.rateLimitsByLimitId).length)} limits` : "available"),
accountRateLimitsSummaryFromResponse,
),
);
}

View file

@ -1,5 +1,5 @@
import type { AppServerClient } from "../../../../app-server/client";
import type { Diagnostics } from "../../../../app-server/diagnostics";
import type { AppServerClient } from "../../../../app-server/connection/client";
import type { Diagnostics } from "../../../../app-server/protocol/diagnostics";
import type { ChatStateStore } from "../../state/reducer";
export interface ChatServerActionHost {

View file

@ -1,8 +1,11 @@
import { type Diagnostics, diagnosticProbeError, diagnosticProbeOk } from "../../../../app-server/diagnostics";
import { listModelMetadata, listSkillCatalog } from "../../../../app-server/resource-operations";
import { runtimeConfigSnapshotFromAppServerConfig } from "../../../../app-server/runtime-config";
import { rateLimitSnapshotFromAppServerSnapshot } from "../../../../app-server/runtime-metrics";
import type { SharedAppServerMetadata } from "../../../../app-server/shared-cache-state";
import { type Diagnostics, diagnosticProbeError, diagnosticProbeOk } from "../../../../app-server/protocol/diagnostics";
import { listModelMetadata, listSkillCatalog } from "../../../../app-server/services/resource-operations";
import { runtimeConfigSnapshotFromAppServerConfig } from "../../../../app-server/protocol/runtime-config";
import {
accountRateLimitsSummaryFromResponse,
rateLimitSnapshotFromAccountRateLimitsResponse,
} from "../../../../app-server/protocol/runtime-metrics";
import type { SharedAppServerMetadata } from "../../../../app-server/services/shared-cache-state";
import type { ModelMetadata, SkillMetadata } from "../../../../domain/catalog/metadata";
import { cloneAppServerDiagnostics, type ChatServerActionHost } from "./host";
@ -263,15 +266,9 @@ async function loadRateLimitFromClient(
): Promise<RateLimitMetadataResult> {
try {
const response = await client.readAccountRateLimits();
const rateLimitsByLimitId = response.rateLimitsByLimitId;
const codexRateLimit = rateLimitsByLimitId && Object.hasOwn(rateLimitsByLimitId, "codex") ? rateLimitsByLimitId["codex"] : undefined;
const rateLimit = codexRateLimit ?? response.rateLimits;
return {
data: rateLimitSnapshotFromAppServerSnapshot(rateLimit),
probe: diagnosticProbeOk(
"account/rateLimits/read",
response.rateLimitsByLimitId ? `${String(Object.keys(response.rateLimitsByLimitId).length)} limits` : "available",
),
data: rateLimitSnapshotFromAccountRateLimitsResponse(response),
probe: diagnosticProbeOk("account/rateLimits/read", accountRateLimitsSummaryFromResponse(response)),
};
} catch (error) {
return { data: null, probe: diagnosticProbeError("account/rateLimits/read", error) };

View file

@ -1,4 +1,4 @@
import { listThreads } from "../../../../app-server/resource-operations";
import { listThreads } from "../../../../app-server/services/resource-operations";
import type { Thread } from "../../../../domain/threads/model";
import type { RuntimeSnapshot } from "../../runtime/snapshot";
import { runtimeConfigOrDefault } from "../../runtime/effective";

View file

@ -1,7 +1,7 @@
import type { App, EventRef } from "obsidian";
import type { ComponentChild as UiNode } from "preact";
import type { CodexInput } from "../../../../app-server/request-input";
import type { CodexInput } from "../../../../app-server/protocol/request-input";
import { isComposerSendKey, type SendShortcut } from "../../../../shared/ui/keyboard";
import { textareaCursorAtVisualBoundary } from "../../../../shared/ui/textarea-caret";
import { chatTurnBusy, type ChatAction, type ChatState, type ChatStateStore } from "../../state/reducer";

View file

@ -1,4 +1,4 @@
import { codexTextInputWithMentions, type RequestMention } from "../../../../app-server/request-input";
import { codexTextInputWithMentions, type RequestMention } from "../../../../app-server/protocol/request-input";
import type { SkillMetadata } from "../../../../domain/catalog/metadata";
import { parseObsidianWikiLink } from "../../../../shared/obsidian/wikilinks";

View file

@ -1,6 +1,6 @@
import type { App, Component } from "obsidian";
import type { AppServerClient } from "../../../app-server/client";
import type { AppServerClient } from "../../../app-server/connection/client";
import type { ChatServerThreadActions } from "../connection/server-actions/threads";
import { ChatComposerController } from "./composer/controller";
import { activeTurnId, type ChatState, type ChatStateStore } from "../state/reducer";

View file

@ -1,5 +1,5 @@
import type { PendingApproval } from "../../protocol/server-requests/approval";
import type { RequestId } from "../../../../app-server/types";
import type { RequestId } from "../../../../app-server/connection/rpc-messages";
import { userInputDraftKey, userInputOtherDraftKey, type PendingUserInput } from "../../protocol/server-requests/user-input";
export interface ChatRequestState {

View file

@ -1,5 +1,5 @@
import type { AppServerClient } from "../../../../app-server/client";
import type { CodexInput } from "../../../../app-server/request-input";
import type { AppServerClient } from "../../../../app-server/connection/client";
import type { CodexInput } from "../../../../app-server/protocol/request-input";
import { submissionStateSnapshot } from "../../state/selectors";
import type { ChatStateStore } from "../../state/reducer";
import { parseSlashCommand } from "../composer/suggestions";

View file

@ -2,7 +2,7 @@ import type { PendingTurnStart } from "../../state/reducer";
import type { DisplayFileMention, DisplayItem, MessageDisplayItem } from "../../display/types";
import { fileMentionsFromInput, userMessageDisplayText } from "../../display/items/user-message";
import { attachHookRunsToTurn } from "../../state/message-stream-updates";
import type { CodexInput } from "../../../../app-server/request-input";
import type { CodexInput } from "../../../../app-server/protocol/request-input";
export interface LocalUserMessageParams {
id: string;

View file

@ -1,4 +1,4 @@
import type { AppServerClient } from "../../../../app-server/client";
import type { AppServerClient } from "../../../../app-server/connection/client";
import { activeThreadId, canImplementPlan } from "../../state/selectors";
import type { ChatStateStore } from "../../state/reducer";
import type { DisplayItem } from "../../display/types";

View file

@ -1,5 +1,5 @@
import type { CodexInput } from "../../../../app-server/request-input";
import type { ThreadGoal, ThreadGoalStatus } from "../../../../app-server/thread-goal";
import type { CodexInput } from "../../../../app-server/protocol/request-input";
import type { ThreadGoal, ThreadGoalStatus } from "../../../../app-server/protocol/thread-goal";
import type { ReasoningEffort } from "../../../../domain/catalog/metadata";
import type { Thread } from "../../../../domain/threads/model";
import { getThreadTitle } from "../../../../domain/threads/model";

View file

@ -1,6 +1,6 @@
import type { AppServerClient } from "../../../../app-server/client";
import { codexTextInputWithAttachments, type CodexInput } from "../../../../app-server/request-input";
import { chronologicalConversationSummariesFromTurnRecords } from "../../../../app-server/turn";
import type { AppServerClient } from "../../../../app-server/connection/client";
import { codexTextInputWithAttachments, type CodexInput } from "../../../../app-server/protocol/request-input";
import { chronologicalConversationSummariesFromTurnRecords } from "../../../../app-server/protocol/turn";
import { referencedThreadPromptBundle, referencedThreadTurns, REFERENCED_THREAD_TURN_LIMIT } from "../../../../domain/threads/reference";
import type { Thread } from "../../../../domain/threads/model";
import {
@ -12,7 +12,7 @@ import type { SlashCommandName } from "../composer/slash-commands";
import type { DisplayDetailSection } from "../../display/types";
import type { ReasoningEffort } from "../../../../domain/catalog/metadata";
import { findModelMetadataByIdOrName, supportedEffortsForModelMetadata } from "../../../../domain/catalog/metadata";
import type { ThreadGoal, ThreadGoalStatus } from "../../../../app-server/thread-goal";
import type { ThreadGoal, ThreadGoalStatus } from "../../../../app-server/protocol/thread-goal";
import { submissionStateSnapshot } from "../../state/selectors";
import type { ChatStateStore } from "../../state/reducer";
import { currentModel, runtimeConfigOrDefault } from "../../runtime/effective";

View file

@ -1,5 +1,5 @@
import type { AppServerClient } from "../../../../app-server/client";
import type { CodexInput } from "../../../../app-server/request-input";
import type { AppServerClient } from "../../../../app-server/connection/client";
import type { CodexInput } from "../../../../app-server/protocol/request-input";
import type { ReferencedThreadDisplay } from "../../../../domain/threads/reference";
import { submissionStateSnapshot } from "../../state/selectors";
import type { ChatStateStore } from "../../state/reducer";

View file

@ -1,4 +1,4 @@
import type { ThreadGoal, ThreadGoalStatus } from "../../../../app-server/thread-goal";
import type { ThreadGoal, ThreadGoalStatus } from "../../../../app-server/protocol/thread-goal";
import { truncate } from "../../../../utils";
import type { GoalDisplayItem } from "../types";

View file

@ -1,4 +1,4 @@
import type { CodexInput, CodexInputItem } from "../../../../app-server/request-input";
import type { CodexInput, CodexInputItem } from "../../../../app-server/protocol/request-input";
import type { DisplayFileMention } from "../types";
type TextRange = [number, number];

View file

@ -1,4 +1,4 @@
import { DIAGNOSTIC_PROBE_METHODS, appServerIdentity, appServerPlatform } from "../../../../app-server/diagnostics";
import { DIAGNOSTIC_PROBE_METHODS, appServerIdentity, appServerPlatform } from "../../../../app-server/protocol/diagnostics";
import { CLIENT_VERSION } from "../../../../constants";
import type {
Diagnostics,
@ -6,7 +6,7 @@ import type {
DiagnosticProbeResult,
McpServerDiagnostic,
McpServerStatusSummary,
} from "../../../../app-server/diagnostics";
} from "../../../../app-server/protocol/diagnostics";
interface DiagnosticRow {
label: string;

View file

@ -1,5 +1,5 @@
import type { RateLimitWindow, SpendControlLimitSnapshot, ThreadTokenUsage } from "../../../../app-server/runtime-metrics";
import type { RuntimeConfigSnapshot } from "../../../../app-server/runtime-config";
import type { RateLimitWindow, SpendControlLimitSnapshot, ThreadTokenUsage } from "../../../../app-server/protocol/runtime-metrics";
import type { RuntimeConfigSnapshot } from "../../../../app-server/protocol/runtime-config";
import { jsonPreview } from "../../../../utils";
import { sortedModelMetadata } from "../../../../domain/catalog/metadata";
import { defaultEffortForModelMetadata } from "../../../../domain/catalog/metadata";

View file

@ -1,9 +1,9 @@
import type { DisplayDetailSection, DisplayFileChange, DisplayItem, ExecutionState } from "./types";
import type { HistoricalTurn } from "../../../app-server/turn-history";
import type { FileUpdateChange, TurnItem } from "../../../app-server/turn";
import type { DisplayDetailSection, DisplayFileChange, DisplayFileMention, DisplayItem, ExecutionState } from "./types";
import type { HistoricalTurn } from "../../../app-server/protocol/turn-history";
import type { FileUpdateChange, TurnItem } from "../../../app-server/protocol/turn";
import { definedProp, truncate } from "../../../utils";
import { referencedThreadDisplayFromPrompt } from "../../../domain/threads/reference";
import { turnUserItemText } from "../../../app-server/turn";
import { referencedThreadDisplayFromPrompt, type ReferencedThreadDisplay } from "../../../domain/threads/reference";
import { turnUserItemText } from "../../../app-server/protocol/turn";
import { agentDisplayItem } from "./items/agent";
import { pathRelativeToRoot } from "./details/path-labels";
import { normalizeProposedPlanMarkdown } from "./items/proposed-plan";
@ -37,6 +37,54 @@ type ReviewModeItem =
type ContextCompactionItem = Extract<TurnItem, { type: "contextCompaction" }>;
type DisplayExecutionState = Exclude<ExecutionState, null>;
type ExecutionStateByStatus = Readonly<Record<string, DisplayExecutionState>>;
interface BaseDisplayData {
id: string;
}
interface UserMessageDisplayData extends BaseDisplayData {
text: string;
displayText: string;
clientId: string | null;
mentionedFiles: DisplayFileMention[];
referencedThread: {
text: string;
displayText: string;
reference: ReferencedThreadDisplay;
} | null;
}
interface MessageDisplayData extends BaseDisplayData {
text: string;
}
interface ToolDisplayData extends BaseDisplayData {
text: string;
toolLabel?: string;
status?: string;
output?: string;
details?: DisplayDetailSection[];
executionState?: ExecutionState;
summaryPath?: boolean;
}
interface CommandDisplayData extends BaseDisplayData {
actionLabel: string;
text: string;
command: string;
cwd: string;
status: string;
exitCode?: number;
durationMs?: number;
output: string;
executionState: ExecutionState;
}
interface FileChangeDisplayData extends BaseDisplayData {
text: string;
status: string;
changes: DisplayFileChange[];
executionState: ExecutionState;
}
const COMMAND_STATES = {
inProgress: "running",
@ -109,102 +157,153 @@ export function displayItemFromTurnItem(item: TurnItem, turnId?: string): Displa
}
function userMessageDisplayItem(item: UserMessageItem, turnId?: string): DisplayItem {
return userMessageDisplayItemFromData(userMessageDisplayDataFromItem(item), turnId);
}
function userMessageDisplayDataFromItem(item: UserMessageItem): UserMessageDisplayData {
const text = turnUserItemText(item);
const displayText = userMessageDisplayText(text, item.content);
const mentionedFiles = fileMentionsFromInput(item.content);
const referencedThread = referencedThreadDisplayFromPrompt(text);
if (referencedThread) {
return {
id: item.id,
text,
displayText: userMessageDisplayText(text, item.content),
clientId: item.clientId,
mentionedFiles: fileMentionsFromInput(item.content),
referencedThread: referencedThread
? {
text: referencedThread.text,
displayText: userMessageDisplayText(referencedThread.text, item.content),
reference: referencedThread.reference,
}
: null,
};
}
function userMessageDisplayItemFromData(data: UserMessageDisplayData, turnId?: string): DisplayItem {
if (data.referencedThread) {
return {
id: item.id,
id: data.id,
kind: "message",
messageKind: "user",
role: "user",
text: userMessageDisplayText(referencedThread.text, item.content),
copyText: referencedThread.text,
referencedThread: referencedThread.reference,
text: data.referencedThread.displayText,
copyText: data.referencedThread.text,
referencedThread: data.referencedThread.reference,
...definedProp("turnId", turnId),
...definedProp("clientId", item.clientId),
sourceItemId: item.id,
...(mentionedFiles.length > 0 ? { mentionedFiles } : {}),
...definedProp("clientId", data.clientId),
sourceItemId: data.id,
...(data.mentionedFiles.length > 0 ? { mentionedFiles: data.mentionedFiles } : {}),
};
}
return {
id: item.id,
id: data.id,
kind: "message",
messageKind: "user",
role: "user",
text: displayText,
copyText: text,
text: data.displayText,
copyText: data.text,
...definedProp("turnId", turnId),
...definedProp("clientId", item.clientId),
sourceItemId: item.id,
...(mentionedFiles.length > 0 ? { mentionedFiles } : {}),
...definedProp("clientId", data.clientId),
sourceItemId: data.id,
...(data.mentionedFiles.length > 0 ? { mentionedFiles: data.mentionedFiles } : {}),
};
}
function agentMessageDisplayItem(item: AgentMessageItem, turnId?: string): DisplayItem {
return assistantResponseDisplayItemFromData(agentMessageDisplayDataFromItem(item), turnId);
}
function agentMessageDisplayDataFromItem(item: AgentMessageItem): MessageDisplayData {
return { id: item.id, text: item.text };
}
function assistantResponseDisplayItemFromData(data: MessageDisplayData, turnId?: string): DisplayItem {
return {
id: item.id,
id: data.id,
kind: "message",
messageKind: "assistantResponse",
role: "assistant",
text: item.text,
copyText: item.text,
text: data.text,
copyText: data.text,
...definedProp("turnId", turnId),
sourceItemId: item.id,
sourceItemId: data.id,
messageState: "completed",
};
}
function planDisplayItem(item: PlanItem, turnId?: string): DisplayItem {
return proposedPlanDisplayItemFromData(planDisplayDataFromItem(item), turnId);
}
function planDisplayDataFromItem(item: PlanItem): MessageDisplayData {
const text = normalizeProposedPlanMarkdown(item.text);
return { id: item.id, text };
}
function proposedPlanDisplayItemFromData(data: MessageDisplayData, turnId?: string): DisplayItem {
return {
id: item.id,
id: data.id,
kind: "message",
messageKind: "proposedPlan",
role: "assistant",
text,
copyText: text,
text: data.text,
copyText: data.text,
...definedProp("turnId", turnId),
sourceItemId: item.id,
sourceItemId: data.id,
messageState: "completed",
};
}
function hookPromptDisplayItem(item: HookPromptItem, turnId?: string): DisplayItem {
return hookPromptDisplayItemFromData(hookPromptDisplayDataFromItem(item), turnId);
}
function hookPromptDisplayDataFromItem(item: HookPromptItem): MessageDisplayData {
return { id: item.id, text: item.fragments.map((fragment) => fragment.text).join("\n\n") || "Hook prompt" };
}
function hookPromptDisplayItemFromData(data: MessageDisplayData, turnId?: string): DisplayItem {
return {
id: item.id,
id: data.id,
kind: "hook",
role: "tool",
text: item.fragments.map((fragment) => fragment.text).join("\n\n") || "Hook prompt",
text: data.text,
...definedProp("turnId", turnId),
sourceItemId: item.id,
sourceItemId: data.id,
};
}
function reasoningDisplayItem(item: ReasoningItem, turnId?: string): DisplayItem {
return reasoningDisplayItemFromData(reasoningDisplayDataFromItem(item), turnId);
}
function reasoningDisplayDataFromItem(item: ReasoningItem): MessageDisplayData {
return { id: item.id, text: reasoningText(item) };
}
function reasoningDisplayItemFromData(data: MessageDisplayData, turnId?: string): DisplayItem {
return {
id: item.id,
id: data.id,
kind: "reasoning",
role: "tool",
text: reasoningText(item),
text: data.text,
...definedProp("turnId", turnId),
sourceItemId: item.id,
sourceItemId: data.id,
};
}
function mcpToolCallDisplayItem(item: McpToolCallItem, turnId?: string): DisplayItem {
return toolDisplayItemFromData(mcpToolCallDisplayDataFromItem(item), turnId);
}
function mcpToolCallDisplayDataFromItem(item: McpToolCallItem): ToolDisplayData {
const name = `${item.server}.${item.tool}`;
const target = jsonTargetLabel(item.arguments);
const failure = item.error?.message ? truncate(item.error.message, 96) : failedStatusLabel(item.status);
return {
id: item.id,
kind: "tool",
role: "tool",
text: compactToolSummary(null, target, statusQualifier(item.status, failure)),
toolLabel: name,
...definedProp("turnId", turnId),
sourceItemId: item.id,
status: item.status,
details: jsonDetails([
["Arguments JSON", item.arguments],
@ -216,18 +315,35 @@ function mcpToolCallDisplayItem(item: McpToolCallItem, turnId?: string): Display
};
}
function toolDisplayItemFromData(data: ToolDisplayData, turnId?: string): DisplayItem {
return {
id: data.id,
kind: "tool",
role: "tool",
text: data.text,
...definedProp("toolLabel", data.toolLabel),
...definedProp("summaryPath", data.summaryPath),
...definedProp("turnId", turnId),
sourceItemId: data.id,
...definedProp("status", data.status),
...definedProp("details", data.details),
...definedProp("output", data.output),
...("executionState" in data ? { executionState: data.executionState } : {}),
};
}
function dynamicToolCallDisplayItem(item: DynamicToolCallItem, turnId?: string): DisplayItem {
return toolDisplayItemFromData(dynamicToolCallDisplayDataFromItem(item), turnId);
}
function dynamicToolCallDisplayDataFromItem(item: DynamicToolCallItem): ToolDisplayData {
const name = `${item.namespace ? `${item.namespace}.` : ""}${item.tool}`;
const target = jsonTargetLabel(item.arguments);
const failure = item.success === false ? "failed" : failedStatusLabel(item.status);
return {
id: item.id,
kind: "tool",
role: "tool",
text: compactToolSummary(null, target, statusQualifier(item.status, failure)),
toolLabel: name,
...definedProp("turnId", turnId),
sourceItemId: item.id,
status: item.status,
details: jsonDetails([
["Arguments JSON", item.arguments],
@ -239,43 +355,43 @@ function dynamicToolCallDisplayItem(item: DynamicToolCallItem, turnId?: string):
}
function webSearchDisplayItem(item: WebSearchItem, turnId?: string): DisplayItem {
return toolDisplayItemFromData(webSearchDisplayDataFromItem(item), turnId);
}
function webSearchDisplayDataFromItem(item: WebSearchItem): ToolDisplayData {
return {
id: item.id,
kind: "tool",
role: "tool",
text: webSearchSummary(item),
toolLabel: "web search",
...definedProp("turnId", turnId),
sourceItemId: item.id,
details: webSearchDetails(item),
output: "",
};
}
function imageViewDisplayItem(item: ImageViewItem, turnId?: string): DisplayItem {
return toolDisplayItemFromData(imageViewDisplayDataFromItem(item), turnId);
}
function imageViewDisplayDataFromItem(item: ImageViewItem): ToolDisplayData {
return {
id: item.id,
kind: "tool",
role: "tool",
text: compactToolSummary(null, item.path),
toolLabel: "imageView",
summaryPath: true,
...definedProp("turnId", turnId),
sourceItemId: item.id,
};
}
function imageGenerationDisplayItem(item: ImageGenerationItem, turnId?: string): DisplayItem {
return toolDisplayItemFromData(imageGenerationDisplayDataFromItem(item), turnId);
}
function imageGenerationDisplayDataFromItem(item: ImageGenerationItem): ToolDisplayData {
const target = item.savedPath ?? item.result;
return {
id: item.id,
kind: "tool",
role: "tool",
text: compactToolSummary(null, target, statusQualifier(item.status, failedStatusLabel(item.status))),
toolLabel: "imageGeneration",
summaryPath: Boolean(item.savedPath),
...definedProp("turnId", turnId),
sourceItemId: item.id,
status: item.status,
details: [
...bodyDetail("Saved path", item.savedPath),
@ -288,26 +404,34 @@ function imageGenerationDisplayItem(item: ImageGenerationItem, turnId?: string):
}
function reviewModeDisplayItem(item: ReviewModeItem, turnId?: string): DisplayItem {
return toolDisplayItemFromData(reviewModeDisplayDataFromItem(item), turnId);
}
function reviewModeDisplayDataFromItem(item: ReviewModeItem): ToolDisplayData {
return {
id: item.id,
kind: "tool",
role: "tool",
text: item.type === "enteredReviewMode" ? "Entered review mode" : "Exited review mode",
toolLabel: item.type,
...definedProp("turnId", turnId),
sourceItemId: item.id,
output: item.review,
};
}
function contextCompactionDisplayItem(item: ContextCompactionItem, turnId?: string): DisplayItem {
return contextCompactionDisplayItemFromData(contextCompactionDisplayDataFromItem(item), turnId);
}
function contextCompactionDisplayDataFromItem(item: ContextCompactionItem): MessageDisplayData {
return { id: item.id, text: "Context compaction" };
}
function contextCompactionDisplayItemFromData(data: MessageDisplayData, turnId?: string): DisplayItem {
return {
id: item.id,
id: data.id,
kind: "contextCompaction",
role: "tool",
text: "Context compaction",
text: data.text,
...definedProp("turnId", turnId),
sourceItemId: item.id,
sourceItemId: data.id,
};
}
@ -452,6 +576,10 @@ function webSearchDetails(item: WebSearchItem): DisplayDetailSection[] {
}
function commandDisplayItem(item: CommandExecutionItem, turnId?: string): DisplayItem {
return commandDisplayItemFromData(commandDisplayDataFromItem(item), turnId);
}
function commandDisplayDataFromItem(item: CommandExecutionItem): CommandDisplayData {
const exitCode = typeof item.exitCode === "number" ? item.exitCode : undefined;
const durationMs = typeof item.durationMs === "number" ? item.durationMs : undefined;
const target = commandTargetLabel(item);
@ -461,12 +589,8 @@ function commandDisplayItem(item: CommandExecutionItem, turnId?: string): Displa
: statusQualifier(item.status, failedStatusLabel(item.status));
return {
id: item.id,
kind: "command",
role: "tool",
actionLabel: commandActionLabel(item),
text: compactToolSummary(null, target, qualifier),
...definedProp("turnId", turnId),
sourceItemId: item.id,
command: item.command,
cwd: item.cwd,
status: item.status,
@ -477,22 +601,55 @@ function commandDisplayItem(item: CommandExecutionItem, turnId?: string): Displa
};
}
function commandDisplayItemFromData(data: CommandDisplayData, turnId?: string): DisplayItem {
return {
id: data.id,
kind: "command",
role: "tool",
actionLabel: data.actionLabel,
text: data.text,
...definedProp("turnId", turnId),
sourceItemId: data.id,
command: data.command,
cwd: data.cwd,
status: data.status,
...definedProp("exitCode", data.exitCode),
...definedProp("durationMs", data.durationMs),
output: data.output,
executionState: data.executionState,
};
}
function fileChangeDisplayItem(item: FileChangeItem, turnId?: string): DisplayItem {
return fileChangeDisplayItemFromData(fileChangeDisplayDataFromItem(item), turnId);
}
function fileChangeDisplayDataFromItem(item: FileChangeItem): FileChangeDisplayData {
const changes = normalizeFileChanges(item.changes);
const qualifier = statusQualifier(item.status, failedStatusLabel(item.status));
return {
id: item.id,
kind: "fileChange",
role: "tool",
text: compactToolSummary(null, fileChangeTargetLabel(changes), qualifier),
...definedProp("turnId", turnId),
sourceItemId: item.id,
status: item.status,
changes,
executionState: patchApplyExecutionState(item.status),
};
}
function fileChangeDisplayItemFromData(data: FileChangeDisplayData, turnId?: string): DisplayItem {
return {
id: data.id,
kind: "fileChange",
role: "tool",
text: data.text,
...definedProp("turnId", turnId),
sourceItemId: data.id,
status: data.status,
changes: data.changes,
executionState: data.executionState,
};
}
export function normalizeFileChanges(changes: FileUpdateChange[]): DisplayFileChange[] {
return changes.map((change) => ({
kind: change.kind.type,

View file

@ -1,4 +1,4 @@
import type { SharedAppServerMetadata } from "../../../app-server/shared-cache-state";
import type { SharedAppServerMetadata } from "../../../app-server/services/shared-cache-state";
import type { Thread } from "../../../domain/threads/model";
import type { ChatServerMetadataActions } from "../connection/server-actions/metadata";
import type { ChatServerThreadActions } from "../connection/server-actions/threads";

View file

@ -1,4 +1,4 @@
import type { ConnectionManager } from "../../../app-server/connection-manager";
import type { ConnectionManager } from "../../../app-server/connection/connection-manager";
import type { ComponentChild as UiNode } from "preact";
import type { ChatStateStore } from "../state/reducer";
import type { CodexPanelSettings } from "../../../settings/model";

View file

@ -1,5 +1,5 @@
import type { RequestId, ServerNotification, ServerRequest } from "../../../../app-server/types";
import type { McpServerStartupStatus } from "../../../../app-server/diagnostics";
import type { RequestId, ServerNotification, ServerRequest } from "../../../../app-server/connection/rpc-messages";
import type { McpServerStartupStatus } from "../../../../app-server/protocol/diagnostics";
import type { ThreadConversationSummary } from "../../../../domain/threads/transcript";
import { classifyAppServerLog } from "./app-server-logs";
import { activeTurnId, type ChatAction, type ChatState, type ChatStateStore } from "../../state/reducer";

View file

@ -1,13 +1,13 @@
import { activeThreadSettingsAppliedAction } from "../../state/actions";
import type { McpServerStartupStatus } from "../../../../app-server/diagnostics";
import { threadTokenUsageFromAppServerUsage } from "../../../../app-server/runtime-metrics";
import type { McpServerStartupStatus } from "../../../../app-server/protocol/diagnostics";
import { threadTokenUsageFromAppServerUsage } from "../../../../app-server/protocol/runtime-metrics";
import {
completedConversationSummaryFromTurnRecord,
type FileUpdateChange,
type TurnItem,
type TurnRecord,
} from "../../../../app-server/turn";
import type { ServerNotification } from "../../../../app-server/types";
} from "../../../../app-server/protocol/turn";
import type { ServerNotification } from "../../../../app-server/connection/rpc-messages";
import type { ThreadConversationSummary } from "../../../../domain/threads/transcript";
import { jsonPreview } from "../../../../utils";
import { activeTurnId, pendingTurnStart as pendingTurnStartForState, type ChatAction, type ChatState } from "../../state/reducer";

View file

@ -1,4 +1,4 @@
import type { ServerNotification, ServerRequest } from "../../../../app-server/types";
import type { ServerNotification, ServerRequest } from "../../../../app-server/connection/rpc-messages";
import { toPendingApproval, type PendingApproval } from "../server-requests/approval";
import { toPendingUserInput, type PendingUserInput } from "../server-requests/user-input";

View file

@ -1,6 +1,6 @@
import { jsonPreview } from "../../../../utils";
import { permissionRows } from "../../display/details/permission-rows";
import type { RequestId } from "../../../../app-server/types";
import type { RequestId } from "../../../../app-server/connection/rpc-messages";
type SimpleApprovalDecision = "accept" | "acceptForSession" | "decline" | "cancel";
export type CommandApprovalDecision =

View file

@ -1,4 +1,4 @@
import type { AppServerClient } from "../../../../app-server/client";
import type { AppServerClient } from "../../../../app-server/connection/client";
type RespondRequestId = Parameters<AppServerClient["respondToServerRequest"]>[0];
type RejectRequestId = Parameters<AppServerClient["rejectServerRequest"]>[0];

View file

@ -1,6 +1,6 @@
import type { RequestId } from "../../../../app-server/types";
import type { RequestId } from "../../../../app-server/connection/rpc-messages";
export type { RequestId } from "../../../../app-server/types";
export type { RequestId } from "../../../../app-server/connection/rpc-messages";
interface UserInputRequestLike {
id: RequestId;

View file

@ -1,6 +1,6 @@
import { cloneRuntimeConfigSnapshot, emptyRuntimeConfigSnapshot, type RuntimeConfigSnapshot } from "../../../app-server/runtime-config";
import { cloneRuntimeConfigSnapshot, emptyRuntimeConfigSnapshot, type RuntimeConfigSnapshot } from "../../../app-server/protocol/runtime-config";
import { findModelMetadataByIdOrName, type ModelMetadata } from "../../../domain/catalog/metadata";
import type { ApprovalPolicy, ApprovalsReviewer } from "../../../app-server/runtime-policy";
import type { ApprovalPolicy, ApprovalsReviewer } from "../../../app-server/protocol/runtime-policy";
import { supportedEffortsForModelMetadata, type ReasoningEffort } from "../../../domain/catalog/metadata";
import type { RuntimeSnapshot } from "./snapshot";

View file

@ -1,7 +1,7 @@
import type { AppServerClient } from "../../../app-server/client";
import type { RuntimeConfigSnapshot } from "../../../app-server/runtime-config";
import type { ApprovalsReviewer } from "../../../app-server/runtime-policy";
import type { ThreadSettingsUpdate } from "../../../app-server/thread-settings";
import type { AppServerClient } from "../../../app-server/connection/client";
import type { RuntimeConfigSnapshot } from "../../../app-server/protocol/runtime-config";
import type { ApprovalsReviewer } from "../../../app-server/protocol/runtime-policy";
import type { ThreadSettingsUpdate } from "../../../app-server/protocol/thread-settings";
import type { ReasoningEffort } from "../../../domain/catalog/metadata";
import { autoReviewActive, fastModeActive, runtimeConfigOrDefault } from "./effective";
import {

View file

@ -1,7 +1,7 @@
import type { ChatState } from "../state/reducer";
import type { ActivePermissionProfile, RuntimeConfigSnapshot } from "../../../app-server/runtime-config";
import type { RateLimitSnapshot, ThreadTokenUsage } from "../../../app-server/runtime-metrics";
import type { ApprovalPolicy, ApprovalsReviewer, ServiceTier } from "../../../app-server/runtime-policy";
import type { ActivePermissionProfile, RuntimeConfigSnapshot } from "../../../app-server/protocol/runtime-config";
import type { RateLimitSnapshot, ThreadTokenUsage } from "../../../app-server/protocol/runtime-metrics";
import type { ApprovalPolicy, ApprovalsReviewer, ServiceTier } from "../../../app-server/protocol/runtime-policy";
import type { ModelMetadata, ReasoningEffort } from "../../../domain/catalog/metadata";
import type { CollaborationMode, PendingRuntimeSetting, RequestedServiceTier } from "./pending-settings";

View file

@ -4,8 +4,8 @@ import {
type ApprovalPolicy,
type ApprovalsReviewer,
type ServiceTier,
} from "../../../app-server/runtime-policy";
import type { ThreadSettingsUpdate } from "../../../app-server/thread-settings";
} from "../../../app-server/protocol/runtime-policy";
import type { ThreadSettingsUpdate } from "../../../app-server/protocol/thread-settings";
import { normalizeReasoningEffort, type ReasoningEffort } from "../../../domain/catalog/metadata";
import {
resetRuntimeSettingToConfig,

View file

@ -1,7 +1,7 @@
import { applyThreadSettingsValue, appServerCollaborationMode, type ThreadSettingsUpdate } from "../../../app-server/thread-settings";
import type { ServiceTierRequest } from "../../../app-server/thread-settings";
import { applyThreadSettingsValue, appServerCollaborationMode, type ThreadSettingsUpdate } from "../../../app-server/protocol/thread-settings";
import type { ServiceTierRequest } from "../../../app-server/protocol/thread-settings";
import { currentModel, currentReasoningEffort, fastServiceTierRequestValue } from "./effective";
import type { RuntimeConfigSnapshot } from "../../../app-server/runtime-config";
import type { RuntimeConfigSnapshot } from "../../../app-server/protocol/runtime-config";
import type { RuntimeSnapshot } from "./snapshot";
import type { PendingRuntimeSetting } from "./pending-settings";

View file

@ -1,6 +1,6 @@
import type { AppServerInitialization } from "../../../app-server/initialization";
import type { AppServerInitialization } from "../../../app-server/protocol/initialization";
import type { Thread } from "../../../domain/threads/model";
import { parseServiceTier, type ServiceTier } from "../../../app-server/runtime-policy";
import { parseServiceTier, type ServiceTier } from "../../../app-server/protocol/runtime-policy";
import { normalizeReasoningEffort, type ReasoningEffort } from "../../../domain/catalog/metadata";
import type { ChatRuntimeState } from "../runtime/state";
import type { CollaborationMode } from "../runtime/pending-settings";

View file

@ -1,14 +1,14 @@
import type { AppServerInitialization } from "../../../app-server/initialization";
import type { AppServerInitialization } from "../../../app-server/protocol/initialization";
import type { ReasoningEffort } from "../../../domain/catalog/metadata";
import type { Thread } from "../../../domain/threads/model";
import type { ModelMetadata, SkillMetadata } from "../../../domain/catalog/metadata";
import type { ThreadGoal } from "../../../app-server/thread-goal";
import type { ThreadSettingsUpdate } from "../../../app-server/thread-settings";
import type { ApprovalsReviewer } from "../../../app-server/runtime-policy";
import type { Diagnostics } from "../../../app-server/diagnostics";
import { createAppServerDiagnostics } from "../../../app-server/diagnostics";
import type { RuntimeConfigSnapshot } from "../../../app-server/runtime-config";
import type { RateLimitSnapshot, ThreadTokenUsage } from "../../../app-server/runtime-metrics";
import type { ThreadGoal } from "../../../app-server/protocol/thread-goal";
import type { ThreadSettingsUpdate } from "../../../app-server/protocol/thread-settings";
import type { ApprovalsReviewer } from "../../../app-server/protocol/runtime-policy";
import type { Diagnostics } from "../../../app-server/protocol/diagnostics";
import { createAppServerDiagnostics } from "../../../app-server/protocol/diagnostics";
import type { RuntimeConfigSnapshot } from "../../../app-server/protocol/runtime-config";
import type { RateLimitSnapshot, ThreadTokenUsage } from "../../../app-server/protocol/runtime-metrics";
import type { CollaborationMode } from "../runtime/pending-settings";
import {
commitPendingThreadSettingsRuntimeState,
@ -26,7 +26,7 @@ import {
type ChatRuntimeState,
} from "../runtime/state";
import type { RequestedServiceTier } from "../runtime/pending-settings";
import type { RequestId } from "../../../app-server/types";
import type { RequestId } from "../../../app-server/connection/rpc-messages";
import type { ComposerSuggestion } from "../conversation/composer/suggestions";
import { upsertDisplayItem } from "./message-stream-updates";
import type { DisplayItem } from "../display/types";

View file

@ -1,4 +1,4 @@
import type { AppServerClient } from "../../../app-server/client";
import type { AppServerClient } from "../../../app-server/connection/client";
import type { ArchiveExportAdapter } from "../../thread-export/archive-markdown";
import type { CodexPanelSettings } from "../../../settings/model";
import type { ChatAction, ChatState, ChatStateStore } from "../state/reducer";

View file

@ -1,7 +1,7 @@
import { Notice } from "obsidian";
import { threadFromThreadRecord } from "../../../app-server/thread";
import { transcriptEntriesFromTurnRecord } from "../../../app-server/turn";
import { threadFromThreadRecord } from "../../../app-server/protocol/thread";
import { transcriptEntriesFromTurnRecords } from "../../../app-server/protocol/turn";
import { exportArchivedThreadMarkdown } from "../../thread-export/archive-markdown";
import { chatTurnBusy } from "../state/reducer";
import type { ChatThreadActionsHost } from "./action-context";
@ -36,7 +36,7 @@ export async function archiveThreadOnServer(
const result = await exportArchivedThreadMarkdown(
{
...threadFromThreadRecord(response.thread, { archived: true }),
transcriptEntries: response.thread.turns.flatMap(transcriptEntriesFromTurnRecord),
transcriptEntries: transcriptEntriesFromTurnRecords(response.thread.turns),
},
{ ...settings, vaultPath: host.vaultPath },
host.archiveAdapter(),

View file

@ -1,4 +1,4 @@
import type { AppServerClient } from "../../../app-server/client";
import type { AppServerClient } from "../../../app-server/connection/client";
import type { Thread } from "../../../domain/threads/model";
import type { ThreadConversationSummary } from "../../../domain/threads/transcript";
import type { CodexPanelSettings } from "../../../settings/model";

View file

@ -1,6 +1,6 @@
import type { ConnectionManager } from "../../../app-server/connection-manager";
import type { AppServerClient } from "../../../app-server/client";
import { recoverRolloutTokenUsage } from "../../../app-server/rollout-token-usage";
import type { ConnectionManager } from "../../../app-server/connection/connection-manager";
import type { AppServerClient } from "../../../app-server/connection/client";
import { recoverRolloutTokenUsage } from "../../../app-server/services/rollout-token-usage";
import type { ArchiveExportAdapter } from "../../thread-export/archive-markdown";
import { createChatThreadActions } from "./actions";
import { AutoTitleController } from "./auto-title-controller";

View file

@ -1,11 +1,11 @@
import type { AppServerClient } from "../../../app-server/client";
import type { AppServerClient } from "../../../app-server/connection/client";
import {
appServerThreadGoalUserHistoryItem,
threadGoalFromAppServerGoal,
type ThreadGoal,
type ThreadGoalStatus,
type ThreadGoalUpdate,
} from "../../../app-server/thread-goal";
} from "../../../app-server/protocol/thread-goal";
import type { ChatStateStore } from "../state/reducer";
import type { GoalDisplayItem } from "../display/types";
import { goalChangeItem } from "../display/items/goal";

View file

@ -1,5 +1,5 @@
import type { AppServerClient } from "../../../app-server/client";
import type { ThreadTurnsPage } from "../../../app-server/turn-history";
import type { AppServerClient } from "../../../app-server/connection/client";
import type { ThreadTurnsPage } from "../../../app-server/protocol/turn-history";
import type { ChatAction, ChatState, ChatStateStore } from "../state/reducer";
import { displayItemsFromTurns } from "../display/turn-items";

View file

@ -1,4 +1,4 @@
import type { AppServerClient } from "../../../app-server/client";
import type { AppServerClient } from "../../../app-server/connection/client";
import type { ChatStateStore } from "../state/reducer";
export interface ThreadRenameActionsHost {

View file

@ -1,5 +1,5 @@
import type { AppServerClient } from "../../../app-server/client";
import { completedConversationSummaryFromTurnRecord } from "../../../app-server/turn";
import type { AppServerClient } from "../../../app-server/connection/client";
import { completedConversationSummariesFromTurnRecords } from "../../../app-server/protocol/turn";
import { getThreadTitle } from "../../../domain/threads/model";
import type { Thread } from "../../../domain/threads/model";
import type { CodexPanelSettings } from "../../../settings/model";
@ -158,10 +158,7 @@ export class RenameController {
readTurns: async (id, cursor, limit, sortDirection) => {
const response = await client.threadTurnsList(id, cursor, limit, sortDirection);
return {
data: response.data.flatMap((turn) => {
const summary = completedConversationSummaryFromTurnRecord(turn);
return summary ? [summary] : [];
}),
data: completedConversationSummariesFromTurnRecords(response.data),
nextCursor: response.nextCursor,
};
},

View file

@ -1,5 +1,5 @@
import type { AppServerClient } from "../../../app-server/client";
import type { ThreadTokenUsage } from "../../../app-server/runtime-metrics";
import type { AppServerClient } from "../../../app-server/connection/client";
import type { ThreadTokenUsage } from "../../../app-server/protocol/runtime-metrics";
import { activeThreadId, canSwitchToThread, displayItemsEmpty, listedThreads } from "../state/selectors";
import type { ChatStateStore } from "../state/reducer";
import type { RestorationController } from "./restoration-controller";

View file

@ -1,8 +1,8 @@
import { parseServiceTier } from "../../../app-server/runtime-policy";
import { parseServiceTier } from "../../../app-server/protocol/runtime-policy";
import { upsertThread } from "../../../domain/threads/model";
import { normalizeReasoningEffort } from "../../../domain/catalog/metadata";
import type { Thread } from "../../../domain/threads/model";
import { threadActivationSnapshotFromAppServerResponse, type ThreadActivationSnapshot } from "../../../app-server/thread-activation";
import { threadActivationSnapshotFromAppServerResponse, type ThreadActivationSnapshot } from "../../../app-server/services/thread-activation";
import type { ChatRuntimeState } from "../runtime/state";
import type { DisplayItem } from "../display/types";
import type { ActiveThreadResumedAction } from "../state/actions";

View file

@ -1,4 +1,4 @@
import { threadFromThreadRecord } from "../../../app-server/thread";
import { threadFromThreadRecord } from "../../../app-server/protocol/thread";
import { rollbackCandidateFromItems } from "../display/item-actions";
import { displayItemsFromTurns } from "../display/turn-items";
import { chatTurnBusy } from "../state/reducer";

View file

@ -1,7 +1,7 @@
import type { ComponentChild as UiNode } from "preact";
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "preact/hooks";
import type { ThreadGoal, ThreadGoalStatus } from "../../../app-server/thread-goal";
import type { ThreadGoal, ThreadGoalStatus } from "../../../app-server/protocol/thread-goal";
import { isComposerSendKey, type SendShortcut } from "../../../shared/ui/keyboard";
import { IconButton } from "../../../shared/ui/components";
import { syncTextareaHeight } from "../../../shared/ui/textarea-autogrow";

View file

@ -1,6 +1,6 @@
import { ItemView, type ViewStateResult, type WorkspaceLeaf } from "obsidian";
import type { AppServerClient } from "../../app-server/client";
import type { AppServerClient } from "../../app-server/connection/client";
import { VIEW_TYPE_CODEX_PANEL } from "../../constants";
import type { DisplayDetailSection, DisplayItem } from "./display/types";
import type { ReasoningEffort } from "../../domain/catalog/metadata";
@ -10,7 +10,7 @@ import type { RuntimeSnapshot } from "./runtime/snapshot";
import { collaborationModeLabel as formatCollaborationModeLabel } from "./runtime/pending-settings";
import { chatTurnBusy, createChatStateStore, type ChatState, type ChatAction } from "./state/reducer";
import type { OpenCodexPanelSnapshot } from "../../workspace/open-panel-snapshot";
import type { SharedAppServerMetadata } from "../../app-server/shared-cache-state";
import type { SharedAppServerMetadata } from "../../app-server/services/shared-cache-state";
import type { CodexChatHost } from "./chat-host";
import { createStructuredSystemItem, createSystemItem } from "./display/items/system";
import {

View file

@ -4,10 +4,10 @@ import {
type EphemeralStructuredTurnClientFactory,
type EphemeralStructuredTurnRuntimeClient,
type StructuredTurnOutputSchema,
} from "../../app-server/ephemeral-structured-turn";
import { lastAgentMessageTextFromTurnRecord } from "../../app-server/turn";
} from "../../app-server/services/ephemeral-structured-turn";
import { lastAgentMessageTextFromTurnRecord } from "../../app-server/protocol/turn";
import type { ReasoningEffort } from "../../domain/catalog/metadata";
import { modelMetadataFromCatalogModels } from "../../app-server/catalog";
import { modelMetadataFromCatalogModels } from "../../app-server/protocol/catalog";
import type { ModelMetadata } from "../../domain/catalog/metadata";
import { runtimeOverride, validatedRuntimeOverrideForModelMetadata } from "../../domain/catalog/runtime-overrides";
import type { SelectionRewriteRuntimeSettings } from "./model";

View file

@ -1,7 +1,7 @@
import { Notice, Platform, SuggestModal, type App } from "obsidian";
import { listThreads } from "../../app-server/resource-operations";
import { withShortLivedAppServerClient } from "../../app-server/short-lived-client";
import { listThreads } from "../../app-server/services/resource-operations";
import { withShortLivedAppServerClient } from "../../app-server/connection/short-lived-client";
import { getThreadTitle } from "../../domain/threads/model";
import type { Thread } from "../../domain/threads/model";
import type { CodexPanelSettings } from "../../settings/model";

View file

@ -1,12 +1,12 @@
import { modelMetadataFromCatalogModels } from "../../app-server/catalog";
import { modelMetadataFromCatalogModels } from "../../app-server/protocol/catalog";
import {
runEphemeralStructuredTurn,
type EphemeralStructuredTurnClient,
type EphemeralStructuredTurnClientFactory,
type EphemeralStructuredTurnRuntimeClient,
type StructuredTurnOutputSchema,
} from "../../app-server/ephemeral-structured-turn";
import { conversationSummaryFromTurnRecord, type TurnRecord } from "../../app-server/turn";
} from "../../app-server/services/ephemeral-structured-turn";
import { conversationAssistantTextFromTurnRecord, type TurnRecord } from "../../app-server/protocol/turn";
import type { ModelMetadata, ReasoningEffort } from "../../domain/catalog/metadata";
import { runtimeOverride, validatedRuntimeOverrideForModelMetadata } from "../../domain/catalog/runtime-overrides";
import { threadTitleFromGeneratedText, threadTitlePrompt, type ThreadTitleContext } from "./model";
@ -73,7 +73,7 @@ export interface ThreadTitleRuntimeOverride {
}
export function threadTitleFromGenerationTurn(turn: TurnRecord): string | null {
const response = conversationSummaryFromTurnRecord(turn).assistantText;
const response = conversationAssistantTextFromTurnRecord(turn);
return response ? threadTitleFromGeneratedText(response) : null;
}

View file

@ -1,15 +1,15 @@
import { ItemView, Notice, type WorkspaceLeaf } from "obsidian";
import type { AppServerClient } from "../../app-server/client";
import { ConnectionManager, StaleConnectionError } from "../../app-server/connection-manager";
import { listThreads } from "../../app-server/resource-operations";
import { threadFromThreadRecord } from "../../app-server/thread";
import type { AppServerClient } from "../../app-server/connection/client";
import { ConnectionManager, StaleConnectionError } from "../../app-server/connection/connection-manager";
import { listThreads } from "../../app-server/services/resource-operations";
import { threadFromThreadRecord } from "../../app-server/protocol/thread";
import { VIEW_TYPE_CODEX_THREADS } from "../../constants";
import type { Thread } from "../../domain/threads/model";
import type { CodexPanelSettings } from "../../settings/model";
import { exportArchivedThreadMarkdown } from "../thread-export/archive-markdown";
import type { OpenCodexPanelSnapshot } from "../../workspace/open-panel-snapshot";
import { completedConversationSummaryFromTurnRecord, transcriptEntriesFromTurnRecord } from "../../app-server/turn";
import { completedConversationSummariesFromTurnRecords, transcriptEntriesFromTurnRecords } from "../../app-server/protocol/turn";
import { generateThreadTitleWithCodex } from "../thread-title/generation";
import { findThreadTitleContext, THREAD_TITLE_CONTEXT_UNAVAILABLE_MESSAGE } from "../thread-title/model";
import { renderThreadsView, unmountThreadsView } from "./renderer";
@ -332,10 +332,7 @@ export class CodexThreadsView extends ItemView {
readTurns: async (id, cursor, limit, sortDirection) => {
const response = await client.threadTurnsList(id, cursor, limit, sortDirection);
return {
data: response.data.flatMap((turn) => {
const summary = completedConversationSummaryFromTurnRecord(turn);
return summary ? [summary] : [];
}),
data: completedConversationSummariesFromTurnRecords(response.data),
nextCursor: response.nextCursor,
};
},
@ -383,7 +380,7 @@ export class CodexThreadsView extends ItemView {
const result = await exportArchivedThreadMarkdown(
{
...threadFromThreadRecord(response.thread, { archived: true }),
transcriptEntries: response.thread.turns.flatMap(transcriptEntriesFromTurnRecord),
transcriptEntries: transcriptEntriesFromTurnRecords(response.thread.turns),
},
{ ...this.plugin.settings, vaultPath: this.plugin.vaultPath },
this.app.vault.adapter,

View file

@ -7,8 +7,8 @@ import type { CodexChatHost } from "./features/chat/chat-host";
import { CodexChatTurnDiffView } from "./features/chat/turn-diff/view";
import { openThreadPicker, type ThreadPickerHost } from "./features/thread-picker/modal";
import { CodexThreadsView, type CodexThreadsHost } from "./features/threads-view/view";
import { SharedAppServerCache } from "./app-server/shared-cache";
import type { SharedAppServerCacheContext } from "./app-server/shared-cache-state";
import { SharedAppServerCache } from "./app-server/services/shared-cache";
import type { SharedAppServerCacheContext } from "./app-server/services/shared-cache-state";
import { DEFAULT_SETTINGS, getVaultPath, normalizeSettings, settingsMatchNormalizedData, type CodexPanelSettings } from "./settings/model";
import { CodexPanelSettingTab, type CodexPanelSettingTabHost } from "./settings/tab";
import { persistedChatTurnDiffViewState, type ChatTurnDiffViewState } from "./features/chat/turn-diff/model";

View file

@ -1,5 +1,5 @@
import type { AppServerClient } from "../app-server/client";
import { listHookData, listModelMetadata, listThreads, type HookData } from "../app-server/resource-operations";
import type { AppServerClient } from "../app-server/connection/client";
import { listHookData, listModelMetadata, listThreads, type HookData } from "../app-server/services/resource-operations";
import type { ModelMetadata } from "../domain/catalog/metadata";
import type { Thread } from "../domain/threads/model";
import { errorMessage } from "../utils";

View file

@ -1,8 +1,8 @@
import { type App, Notice, type Plugin, PluginSettingTab, Setting, setIcon } from "obsidian";
import type { AppServerClient } from "../app-server/client";
import { restoreArchivedThread, setHookItemEnabled, trustHookItem } from "../app-server/resource-operations";
import { withShortLivedAppServerClient } from "../app-server/short-lived-client";
import type { AppServerClient } from "../app-server/connection/client";
import { restoreArchivedThread, setHookItemEnabled, trustHookItem } from "../app-server/services/resource-operations";
import { withShortLivedAppServerClient } from "../app-server/connection/short-lived-client";
import { DEFAULT_CODEX_PATH } from "../constants";
import type { ReasoningEffort } from "../domain/catalog/metadata";
import type { HookItem, ModelMetadata } from "../domain/catalog/metadata";

View file

@ -4,7 +4,7 @@ import { VIEW_TYPE_CODEX_THREADS } from "../constants";
import { CodexThreadsView } from "../features/threads-view/view";
import type { ModelMetadata } from "../domain/catalog/metadata";
import type { Thread } from "../domain/threads/model";
import type { SharedAppServerMetadata } from "../app-server/shared-cache-state";
import type { SharedAppServerMetadata } from "../app-server/services/shared-cache-state";
import type { WorkspacePanelCoordinator } from "./panel-coordinator";
export interface ThreadSurfaceCoordinatorOptions {

View file

@ -1,9 +1,9 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { AppServerClient } from "../../src/app-server/client";
import type { AppServerRpcError, AppServerStartStructuredTurnOptions, AppServerStartTurnOptions } from "../../src/app-server/client";
import type { AppServerTransport, AppServerTransportHandlers } from "../../src/app-server/transport";
import type { RpcOutboundMessage } from "../../src/app-server/types";
import { AppServerClient } from "../../src/app-server/connection/client";
import type { AppServerRpcError, AppServerStartStructuredTurnOptions, AppServerStartTurnOptions } from "../../src/app-server/connection/client";
import type { AppServerTransport, AppServerTransportHandlers } from "../../src/app-server/connection/transport";
import type { RpcOutboundMessage } from "../../src/app-server/connection/rpc-messages";
import type { InitializeResponse } from "../../src/generated/app-server/InitializeResponse";
import type { ServerRequest } from "../../src/generated/app-server/ServerRequest";
import manifest from "../../manifest.json";

View file

@ -9,8 +9,8 @@ import {
createAppServerDiagnostics,
shortErrorMessage,
upsertMcpServerDiagnostic,
} from "../../src/app-server/diagnostics";
import type { InitializeDiagnostics } from "../../src/app-server/diagnostics";
} from "../../src/app-server/protocol/diagnostics";
import type { InitializeDiagnostics } from "../../src/app-server/protocol/diagnostics";
describe("app-server diagnostics", () => {
it("formats initialize metadata", () => {

View file

@ -5,7 +5,7 @@ import {
hookItemsFromCatalogHooks,
modelMetadataFromCatalogModels,
skillMetadataFromCatalogSkills,
} from "../../src/app-server/catalog";
} from "../../src/app-server/protocol/catalog";
import type { HookMetadata } from "../../src/generated/app-server/v2/HookMetadata";
import type { Model } from "../../src/generated/app-server/v2/Model";
import type { SkillMetadata } from "../../src/generated/app-server/v2/SkillMetadata";

View file

@ -1,9 +1,9 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { AppServerClient } from "../../src/app-server/client";
import { ConnectionManager, StaleConnectionError } from "../../src/app-server/connection-manager";
import type { AppServerTransport, AppServerTransportHandlers } from "../../src/app-server/transport";
import type { RpcOutboundMessage } from "../../src/app-server/types";
import { AppServerClient } from "../../src/app-server/connection/client";
import { ConnectionManager, StaleConnectionError } from "../../src/app-server/connection/connection-manager";
import type { AppServerTransport, AppServerTransportHandlers } from "../../src/app-server/connection/transport";
import type { RpcOutboundMessage } from "../../src/app-server/connection/rpc-messages";
class SilentTransport implements AppServerTransport {
readonly sent: RpcOutboundMessage[] = [];

View file

@ -6,12 +6,12 @@ import {
runEphemeralStructuredTurn,
type EphemeralStructuredTurnClient,
type EphemeralStructuredTurnClientFactory,
} from "../../src/app-server/ephemeral-structured-turn";
} from "../../src/app-server/services/ephemeral-structured-turn";
import type {
AppServerClientHandlers,
AppServerStartEphemeralThreadOptions,
AppServerStartStructuredTurnOptions,
} from "../../src/app-server/client";
} from "../../src/app-server/connection/client";
import type { InitializeResponse } from "../../src/generated/app-server/InitializeResponse";
import type { RequestId } from "../../src/generated/app-server/RequestId";
import type { ServerNotification } from "../../src/generated/app-server/ServerNotification";
@ -20,7 +20,7 @@ import type { ModelListResponse } from "../../src/generated/app-server/v2/ModelL
import type { Thread as ThreadRecord } from "../../src/generated/app-server/v2/Thread";
import type { ThreadStartResponse } from "../../src/generated/app-server/v2/ThreadStartResponse";
import type { TurnStartResponse } from "../../src/generated/app-server/v2/TurnStartResponse";
import type { TurnItem, TurnRecord } from "../../src/app-server/turn";
import type { TurnItem, TurnRecord } from "../../src/app-server/protocol/turn";
describe("runEphemeralStructuredTurn", () => {
it("fills completed turn items from item completion notifications", async () => {

View file

@ -5,7 +5,7 @@ import {
codexTextInputWithMentions,
toAppServerUserInput,
type CodexInput,
} from "../../src/app-server/request-input";
} from "../../src/app-server/protocol/request-input";
describe("app-server request input", () => {
it("builds text input with mentions and skills", () => {

View file

@ -1,7 +1,7 @@
import { describe, expect, it, vi } from "vitest";
import type { AppServerClient } from "../../src/app-server/client";
import { listHookData, listSkillCatalog, listThreads } from "../../src/app-server/resource-operations";
import type { AppServerClient } from "../../src/app-server/connection/client";
import { listHookData, listSkillCatalog, listThreads } from "../../src/app-server/services/resource-operations";
describe("app-server resource operations", () => {
it("maps listed threads to domain threads with archive state", async () => {

View file

@ -5,7 +5,7 @@ import {
recoverRolloutTokenUsage,
ROLLOUT_TOKEN_USAGE_MAX_BASE64_BYTES,
ROLLOUT_TOKEN_USAGE_READ_TIMEOUT_MS,
} from "../../src/app-server/rollout-token-usage";
} from "../../src/app-server/services/rollout-token-usage";
describe("rollout token usage recovery", () => {
it("parses the last valid token_count event", () => {

View file

@ -0,0 +1,66 @@
import { describe, expect, it } from "vitest";
import {
accountRateLimitsSummaryFromResponse,
rateLimitSnapshotFromAccountRateLimitsResponse,
} from "../../src/app-server/protocol/runtime-metrics";
type AccountRateLimitsResponse = Parameters<typeof rateLimitSnapshotFromAccountRateLimitsResponse>[0];
type AppServerRateLimitSnapshot = AccountRateLimitsResponse["rateLimits"];
describe("app-server runtime metrics", () => {
it("projects the codex rate limit bucket when multi-bucket limits are available", () => {
expect(
rateLimitSnapshotFromAccountRateLimitsResponse({
rateLimits: appServerRateLimitFixture("legacy", 12),
rateLimitsByLimitId: {
other: appServerRateLimitFixture("other", 34),
codex: appServerRateLimitFixture("codex", 56),
},
}),
).toMatchObject({ limitId: "codex", primary: { usedPercent: 56 } });
});
it("falls back to the legacy rate limit snapshot when no codex bucket is available", () => {
expect(
rateLimitSnapshotFromAccountRateLimitsResponse({
rateLimits: appServerRateLimitFixture("legacy", 12),
rateLimitsByLimitId: {
other: appServerRateLimitFixture("other", 34),
},
}),
).toMatchObject({ limitId: "legacy", primary: { usedPercent: 12 } });
});
it("summarizes account rate limit response availability", () => {
expect(
accountRateLimitsSummaryFromResponse({
rateLimits: appServerRateLimitFixture("legacy", 12),
rateLimitsByLimitId: {
codex: appServerRateLimitFixture("codex", 56),
other: appServerRateLimitFixture("other", 34),
},
}),
).toBe("2 limits");
expect(
accountRateLimitsSummaryFromResponse({
rateLimits: appServerRateLimitFixture("legacy", 12),
rateLimitsByLimitId: null,
}),
).toBe("available");
});
});
function appServerRateLimitFixture(limitId: string, usedPercent: number): AppServerRateLimitSnapshot {
return {
limitId,
limitName: limitId,
primary: { usedPercent, windowDurationMins: 300, resetsAt: null },
secondary: null,
credits: null,
individualLimit: null,
planType: null,
rateLimitReachedType: null,
};
}

View file

@ -1,8 +1,8 @@
import { describe, expect, it } from "vitest";
import { createAppServerDiagnostics } from "../../src/app-server/diagnostics";
import type { RateLimitSnapshot } from "../../src/app-server/runtime-metrics";
import { emptyRuntimeConfigSnapshot } from "../../src/app-server/runtime-config";
import { createAppServerDiagnostics } from "../../src/app-server/protocol/diagnostics";
import type { RateLimitSnapshot } from "../../src/app-server/protocol/runtime-metrics";
import { emptyRuntimeConfigSnapshot } from "../../src/app-server/protocol/runtime-config";
import {
applySharedAppServerMetadata,
applySharedModels,
@ -13,7 +13,7 @@ import {
createSharedAppServerState,
sharedAppServerCacheContextIsComplete,
type SharedAppServerCacheContext,
} from "../../src/app-server/shared-cache-state";
} from "../../src/app-server/services/shared-cache-state";
import type { ModelMetadata } from "../../src/domain/catalog/metadata";
import type { Thread } from "../../src/domain/threads/model";

View file

@ -1,9 +1,9 @@
import { describe, expect, it, vi } from "vitest";
import { createAppServerDiagnostics, diagnosticProbeError, diagnosticProbeOk } from "../../src/app-server/diagnostics";
import { SharedAppServerCache } from "../../src/app-server/shared-cache";
import { emptyRuntimeConfigSnapshot, type RuntimeConfigSnapshot } from "../../src/app-server/runtime-config";
import type { SharedAppServerCacheContext, SharedAppServerMetadata } from "../../src/app-server/shared-cache-state";
import { createAppServerDiagnostics, diagnosticProbeError, diagnosticProbeOk } from "../../src/app-server/protocol/diagnostics";
import { SharedAppServerCache } from "../../src/app-server/services/shared-cache";
import { emptyRuntimeConfigSnapshot, type RuntimeConfigSnapshot } from "../../src/app-server/protocol/runtime-config";
import type { SharedAppServerCacheContext, SharedAppServerMetadata } from "../../src/app-server/services/shared-cache-state";
import type { ModelMetadata } from "../../src/domain/catalog/metadata";
describe("SharedAppServerCache", () => {

View file

@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { threadActivationSnapshotFromAppServerResponse } from "../../src/app-server/thread-activation";
import { threadActivationSnapshotFromAppServerResponse } from "../../src/app-server/services/thread-activation";
import type { ThreadResumeResponse } from "../../src/generated/app-server/v2/ThreadResumeResponse";
import type { Thread as ThreadRecord } from "../../src/generated/app-server/v2/Thread";

View file

@ -4,7 +4,7 @@ import {
appServerThreadGoalUpdate,
appServerThreadGoalUserHistoryItem,
threadGoalFromAppServerGoal,
} from "../../src/app-server/thread-goal";
} from "../../src/app-server/protocol/thread-goal";
describe("app-server thread goal model", () => {
it("maps app-server goals into panel-owned goal snapshots", () => {

View file

@ -1,7 +1,7 @@
import { describe, expect, it } from "vitest";
import { appServerCollaborationMode, applyThreadSettingsValue, type ThreadSettingsUpdate } from "../../src/app-server/thread-settings";
import { appServerApprovalsReviewerOrNull, parseServiceTier } from "../../src/app-server/runtime-policy";
import { appServerCollaborationMode, applyThreadSettingsValue, type ThreadSettingsUpdate } from "../../src/app-server/protocol/thread-settings";
import { appServerApprovalsReviewerOrNull, parseServiceTier } from "../../src/app-server/protocol/runtime-policy";
describe("app-server thread settings", () => {
it("applies defined thread setting values and omits undefined values", () => {

View file

@ -2,12 +2,15 @@ import { describe, expect, it } from "vitest";
import {
chronologicalConversationSummariesFromTurnRecords,
completedConversationSummariesFromTurnRecords,
completedConversationSummaryFromTurnRecord,
conversationAssistantTextFromTurnRecord,
lastAgentMessageTextFromTurnRecord,
transcriptEntriesFromTurnRecords,
transcriptEntriesFromTurnRecord,
type TurnItem,
type TurnRecord,
} from "../../src/app-server/turn";
} from "../../src/app-server/protocol/turn";
describe("app-server turn records", () => {
it("projects readable transcript entries without command log items", () => {
@ -44,6 +47,16 @@ describe("app-server turn records", () => {
).toBeNull();
});
it("projects completed summaries from turn lists without exposing filtering logic to callers", () => {
expect(
completedConversationSummariesFromTurnRecords([
turn([userMessage("u1", "依頼"), agentMessage("a1", "回答")], { id: "completed" }),
turn([userMessage("u2", "失敗した依頼"), agentMessage("a2", "失敗した回答")], { id: "failed", status: "failed" }),
turn([commandItem("cmd")], { id: "empty" }),
]),
).toEqual([{ userText: "依頼", assistantText: "回答" }]);
});
it("returns chronological summaries and drops turns without conversation text", () => {
expect(
chronologicalConversationSummariesFromTurnRecords([
@ -57,6 +70,22 @@ describe("app-server turn records", () => {
]);
});
it("projects transcript entries from turn lists", () => {
expect(
transcriptEntriesFromTurnRecords([
turn([userMessage("u1", "先の依頼")], { id: "turn-1", startedAt: 10 }),
turn([agentMessage("a1", "後の回答")], { id: "turn-2", startedAt: 20, completedAt: 25 }),
]),
).toEqual([
{ kind: "user", text: "先の依頼", timestamp: 10 },
{ kind: "assistant", text: "後の回答", timestamp: 25 },
]);
});
it("extracts assistant-like conversation text for generated turn consumers", () => {
expect(conversationAssistantTextFromTurnRecord(turn([userMessage("u1", "依頼"), planItem("p1", "計画")]))).toBe("計画");
});
it("extracts the final non-empty agent message text from a turn", () => {
expect(
lastAgentMessageTextFromTurnRecord(

View file

@ -1,7 +1,7 @@
import { describe, expect, it, vi } from "vitest";
import type { AppServerClient } from "../../../../src/app-server/client";
import { emptyRuntimeConfigSnapshot } from "../../../../src/app-server/runtime-config";
import type { AppServerClient } from "../../../../src/app-server/connection/client";
import { emptyRuntimeConfigSnapshot } from "../../../../src/app-server/protocol/runtime-config";
import { createChatState, createChatStateStore } from "../../../../src/features/chat/state/reducer";
import {
ChatConnectionController,

Some files were not shown because too many files have changed in this diff Show more