Skip to content

Commit a109178

Browse files
committed
refactor(session): 回滚 session.ts 文件
1 parent 5fd54b9 commit a109178

1 file changed

Lines changed: 154 additions & 138 deletions

File tree

src/session.ts

Lines changed: 154 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,156 @@
1+
import * as fs from "fs";
2+
import * as path from "path";
3+
import * as os from "os";
4+
import * as crypto from "crypto";
5+
import { fileURLToPath } from "url";
6+
import matter from "gray-matter";
7+
import ejs from "ejs";
8+
import type { ChatCompletionMessageParam, ChatCompletionContentPart } from "openai/resources/chat/completions";
9+
import { launchNotifyScript } from "./common/notify";
10+
import { buildThinkingRequestOptions } from "./common/openai-thinking";
11+
import { DEEPSEEK_V4_MODELS, supportsMultimodal } from "./common/model-capabilities";
12+
import {
13+
getCompactPrompt,
14+
getDefaultSkillPrompt,
15+
getRuntimeContext,
16+
getSystemPrompt,
17+
getTools,
18+
type ToolDefinition,
19+
} from "./prompt";
20+
import {
21+
ToolExecutor,
22+
type CreateOpenAIClient,
23+
type ProcessTimeoutControl,
24+
type ProcessTimeoutInfo,
25+
type ToolCallExecution,
26+
type ToolExecutionHooks,
27+
} from "./tools/executor";
28+
import { McpManager } from "./mcp/mcp-manager";
129
import type { McpServerConfig, PermissionScope, PermissionSettings } from "./settings";
2-
import type { AskPermissionRequest, MessageToolPermission, UserToolPermission } from "./common/permissions";
3-
import type { CreateOpenAIClient } from "./tools/executor";
30+
import { logApiError } from "./common/error-logger";
31+
import { logOpenAIChatCompletionDebug, normalizeDebugError } from "./common/debug-logger";
32+
import { killProcessTree } from "./common/process-tree";
33+
import { GitFileHistory } from "./common/file-history";
34+
import { getSnippet } from "./common/state";
35+
import {
36+
appendProjectPermissionAllows,
37+
buildPermissionToolExecution,
38+
computeToolCallPermissions,
39+
hasUserPermissionReplies,
40+
normalizeAskPermissions,
41+
parseToolCallForPermissions,
42+
type AskPermissionRequest,
43+
type MessageToolPermission,
44+
type PermissionToolCall,
45+
type UserToolPermission,
46+
} from "./common/permissions";
47+
48+
export type { PermissionScope } from "./settings";
49+
export type {
50+
AskPermissionRequest,
51+
AskPermissionScope,
52+
BashPermissionScope,
53+
MessageToolPermission,
54+
PermissionDecision,
55+
UserToolPermission,
56+
} from "./common/permissions";
57+
58+
const MAX_SESSION_ENTRIES = 50;
59+
const DEFAULT_NEW_PROMPT_API_URL = "https://deepcode.vegamo.cn/api/plugin/new";
60+
const NEW_PROMPT_REPORT_TIMEOUT_MS = 3000;
61+
const DEFAULT_COMPACT_PROMPT_TOKEN_THRESHOLD = 128 * 1024;
62+
const DEEPSEEK_V4_COMPACT_PROMPT_TOKEN_THRESHOLD = 512 * 1024;
63+
64+
type ChatCompletionDebugOptions = {
65+
enabled?: boolean;
66+
location: string;
67+
baseURL?: string;
68+
params?: Record<string, unknown>;
69+
};
70+
71+
export function getCompactPromptTokenThreshold(model: string): number {
72+
return DEEPSEEK_V4_MODELS.has(model)
73+
? DEEPSEEK_V4_COMPACT_PROMPT_TOKEN_THRESHOLD
74+
: DEFAULT_COMPACT_PROMPT_TOKEN_THRESHOLD;
75+
}
76+
77+
function isUsageRecord(value: unknown): value is Record<string, unknown> {
78+
return value !== null && typeof value === "object" && !Array.isArray(value);
79+
}
80+
81+
function summarizeCompletionOptions(options?: Record<string, unknown>): Record<string, unknown> | undefined {
82+
if (!options) {
83+
return undefined;
84+
}
85+
return {
86+
...options,
87+
signal: options.signal instanceof AbortSignal ? { aborted: options.signal.aborted } : options.signal,
88+
};
89+
}
90+
91+
function addUsageValue(current: unknown, next: unknown): unknown {
92+
if (typeof next === "number") {
93+
return (typeof current === "number" ? current : 0) + next;
94+
}
95+
96+
if (isUsageRecord(next)) {
97+
const currentRecord = isUsageRecord(current) ? current : {};
98+
const result: Record<string, unknown> = { ...currentRecord };
99+
for (const [key, value] of Object.entries(next)) {
100+
result[key] = addUsageValue(currentRecord[key], value);
101+
}
102+
return result;
103+
}
104+
105+
return next;
106+
}
107+
108+
function accumulateUsage(current: ModelUsage | null, next: unknown | null | undefined): ModelUsage | null {
109+
if (next == null) {
110+
return current ?? null;
111+
}
112+
return addUsageValue(current, next) as ModelUsage;
113+
}
114+
115+
function usageWithRequestCount(usage: ModelUsage): ModelUsage {
116+
const totalReqs = typeof usage.total_reqs === "number" ? usage.total_reqs + 1 : 1;
117+
return {
118+
...usage,
119+
total_reqs: totalReqs,
120+
};
121+
}
122+
123+
function accumulateUsagePerModel(
124+
current: Record<string, ModelUsage> | null | undefined,
125+
model: string,
126+
next: ModelUsage | null | undefined
127+
): Record<string, ModelUsage> | null {
128+
if (next == null) {
129+
return current ?? null;
130+
}
131+
132+
const usagePerModel = { ...(current ?? {}) };
133+
const modelName = model.trim() || "unknown";
134+
usagePerModel[modelName] = accumulateUsage(usagePerModel[modelName] ?? null, usageWithRequestCount(next))!;
135+
return usagePerModel;
136+
}
137+
138+
function getExtensionRoot(): string {
139+
if (typeof __dirname !== "undefined") {
140+
return path.resolve(__dirname, "..");
141+
}
142+
143+
const currentFilePath = fileURLToPath(import.meta.url);
144+
return path.resolve(path.dirname(currentFilePath), "..");
145+
}
146+
147+
function getTotalTokens(usage: ModelUsage | null | undefined): number {
148+
if (!isUsageRecord(usage)) {
149+
return 0;
150+
}
151+
const totalTokens = usage.total_tokens;
152+
return typeof totalTokens === "number" ? totalTokens : 0;
153+
}
4154

5155
export type SessionStatus =
6156
| "failed"
@@ -52,7 +202,7 @@ export type SessionEntry = {
52202
activeTokens: number;
53203
createTime: string;
54204
updateTime: string;
55-
processes: Map<string, SessionProcessEntry> | null;
205+
processes: Map<string, SessionProcessEntry> | null; // {pid: process info}
56206
askPermissions?: AskPermissionRequest[];
57207
};
58208

@@ -113,7 +263,7 @@ export type SkillInfo = {
113263
isLoaded?: boolean;
114264
};
115265

116-
export type SessionManagerOptions = {
266+
type SessionManagerOptions = {
117267
projectRoot: string;
118268
createOpenAIClient: CreateOpenAIClient;
119269
getResolvedSettings: () => {
@@ -138,140 +288,6 @@ export type LlmStreamProgress = {
138288
formattedTokens: string;
139289
phase: "start" | "update" | "end";
140290
};
141-
import { DEEPSEEK_V4_MODELS } from "./common/model-capabilities";
142-
143-
const DEFAULT_COMPACT_PROMPT_TOKEN_THRESHOLD = 128 * 1024;
144-
const DEEPSEEK_V4_COMPACT_PROMPT_TOKEN_THRESHOLD = 512 * 1024;
145-
146-
export function getCompactPromptTokenThreshold(model: string): number {
147-
return DEEPSEEK_V4_MODELS.has(model)
148-
? DEEPSEEK_V4_COMPACT_PROMPT_TOKEN_THRESHOLD
149-
: DEFAULT_COMPACT_PROMPT_TOKEN_THRESHOLD;
150-
}
151-
152-
export function isUsageRecord(value: unknown): value is Record<string, unknown> {
153-
return value !== null && typeof value === "object" && !Array.isArray(value);
154-
}
155-
156-
export function getTotalTokens(usage: ModelUsage | null | undefined): number {
157-
if (!isUsageRecord(usage)) {
158-
return 0;
159-
}
160-
const totalTokens = (usage as Record<string, unknown>).total_tokens;
161-
return typeof totalTokens === "number" ? totalTokens : 0;
162-
}
163-
164-
export function summarizeCompletionOptions(options?: Record<string, unknown>): Record<string, unknown> | undefined {
165-
if (!options) {
166-
return undefined;
167-
}
168-
return {
169-
...options,
170-
signal: options.signal instanceof AbortSignal ? { aborted: options.signal.aborted } : options.signal,
171-
};
172-
}
173-
174-
export function addUsageValue(current: unknown, next: unknown): unknown {
175-
if (typeof next === "number") {
176-
return (typeof current === "number" ? current : 0) + next;
177-
}
178-
179-
if (isUsageRecord(next)) {
180-
const currentRecord = isUsageRecord(current) ? current : {};
181-
const result: Record<string, unknown> = { ...currentRecord };
182-
for (const [key, value] of Object.entries(next)) {
183-
result[key] = addUsageValue(currentRecord[key], value);
184-
}
185-
return result;
186-
}
187-
188-
return next;
189-
}
190-
191-
export function accumulateUsage(current: ModelUsage | null, next: unknown | null | undefined): ModelUsage | null {
192-
if (next == null) {
193-
return current ?? null;
194-
}
195-
return addUsageValue(current, next) as ModelUsage;
196-
}
197-
198-
export function usageWithRequestCount(usage: ModelUsage): ModelUsage {
199-
const totalReqs = typeof usage.total_reqs === "number" ? usage.total_reqs + 1 : 1;
200-
return {
201-
...usage,
202-
total_reqs: totalReqs,
203-
};
204-
}
205-
206-
export function accumulateUsagePerModel(
207-
current: Record<string, ModelUsage> | null | undefined,
208-
model: string,
209-
next: ModelUsage | null | undefined
210-
): Record<string, ModelUsage> | null {
211-
if (next == null) {
212-
return current ?? null;
213-
}
214-
215-
const usagePerModel = { ...(current ?? {}) };
216-
const modelName = model.trim() || "unknown";
217-
usagePerModel[modelName] = accumulateUsage(usagePerModel[modelName] ?? null, usageWithRequestCount(next))!;
218-
return usagePerModel;
219-
}
220-
221-
export { getExtensionRoot } from "./prompt";
222-
import * as fs from "fs";
223-
import * as path from "path";
224-
import * as os from "os";
225-
import * as crypto from "crypto";
226-
import matter from "gray-matter";
227-
import ejs from "ejs";
228-
import type { ChatCompletionContentPart, ChatCompletionMessageParam } from "openai/resources/chat/completions";
229-
import { launchNotifyScript } from "./common/notify";
230-
import { buildThinkingRequestOptions } from "./common/openai-thinking";
231-
import { supportsMultimodal } from "./common/model-capabilities";
232-
import {
233-
getCompactPrompt,
234-
getDefaultSkillPrompt,
235-
getExtensionRoot,
236-
getRuntimeContext,
237-
getSystemPrompt,
238-
getTools,
239-
type ToolDefinition,
240-
} from "./prompt";
241-
import {
242-
type ProcessTimeoutControl,
243-
type ProcessTimeoutInfo,
244-
type ToolCallExecution,
245-
type ToolExecutionHooks,
246-
ToolExecutor,
247-
} from "./tools/executor";
248-
import { McpManager } from "./mcp/mcp-manager";
249-
250-
import { logApiError } from "./common/error-logger";
251-
import { logOpenAIChatCompletionDebug, normalizeDebugError } from "./common/debug-logger";
252-
import { killProcessTree } from "./common/process-tree";
253-
import { GitFileHistory } from "./common/file-history";
254-
import { getSnippet } from "./common/state";
255-
import {
256-
appendProjectPermissionAllows,
257-
buildPermissionToolExecution,
258-
computeToolCallPermissions,
259-
hasUserPermissionReplies,
260-
normalizeAskPermissions,
261-
parseToolCallForPermissions,
262-
type PermissionToolCall,
263-
} from "./common/permissions";
264-
265-
const MAX_SESSION_ENTRIES = 50;
266-
const DEFAULT_NEW_PROMPT_API_URL = "https://deepcode.vegamo.cn/api/plugin/new";
267-
const NEW_PROMPT_REPORT_TIMEOUT_MS = 3000;
268-
269-
type ChatCompletionDebugOptions = {
270-
enabled?: boolean;
271-
location: string;
272-
baseURL?: string;
273-
params?: Record<string, unknown>;
274-
};
275291

276292
export class SessionManager {
277293
private readonly projectRoot: string;

0 commit comments

Comments
 (0)