@jingyi0605/codingns 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/codingns.mjs +47 -8
- package/dist/public/assets/{TerminalPage-Nq5sPc5c.js → TerminalPage-4p6EBqrR.js} +19 -19
- package/dist/public/assets/gemini-D4G1NbrE.png +0 -0
- package/dist/public/assets/index-CxeghocY.css +1 -0
- package/dist/public/assets/index-DXusStl0.js +108 -0
- package/dist/public/assets/kimi-BWNNSh7e.png +0 -0
- package/dist/public/index.html +2 -2
- package/dist/server/config/env.d.ts +7 -0
- package/dist/server/config/env.js +147 -1
- package/dist/server/config/env.js.map +1 -1
- package/dist/server/config/opencode-system-probe-helper-process.d.ts +24 -0
- package/dist/server/config/opencode-system-probe-helper-process.js +70 -5
- package/dist/server/config/opencode-system-probe-helper-process.js.map +1 -1
- package/dist/server/modules/auth/auth-service.d.ts +7 -1
- package/dist/server/modules/auth/auth-service.js +23 -3
- package/dist/server/modules/auth/auth-service.js.map +1 -1
- package/dist/server/modules/bootstrap/bootstrap-service.d.ts +3 -1
- package/dist/server/modules/bootstrap/bootstrap-service.js +7 -2
- package/dist/server/modules/bootstrap/bootstrap-service.js.map +1 -1
- package/dist/server/modules/butler/butler-action-context-service.d.ts +30 -0
- package/dist/server/modules/butler/butler-action-context-service.js +108 -0
- package/dist/server/modules/butler/butler-action-context-service.js.map +1 -0
- package/dist/server/modules/butler/butler-auth-service.d.ts +17 -0
- package/dist/server/modules/butler/butler-auth-service.js +91 -0
- package/dist/server/modules/butler/butler-auth-service.js.map +1 -0
- package/dist/server/modules/butler/butler-control-action-service.d.ts +65 -0
- package/dist/server/modules/butler/butler-control-action-service.js +296 -0
- package/dist/server/modules/butler/butler-control-action-service.js.map +1 -0
- package/dist/server/modules/butler/butler-control-session-service.d.ts +55 -0
- package/dist/server/modules/butler/butler-control-session-service.js +367 -0
- package/dist/server/modules/butler/butler-control-session-service.js.map +1 -0
- package/dist/server/modules/butler/butler-controller.d.ts +367 -0
- package/dist/server/modules/butler/butler-controller.js +475 -0
- package/dist/server/modules/butler/butler-controller.js.map +1 -0
- package/dist/server/modules/butler/butler-follow-up-evaluation-instruction-adapter.d.ts +34 -0
- package/dist/server/modules/butler/butler-follow-up-evaluation-instruction-adapter.js +77 -0
- package/dist/server/modules/butler/butler-follow-up-evaluation-instruction-adapter.js.map +1 -0
- package/dist/server/modules/butler/butler-follow-up-scheduler.d.ts +23 -0
- package/dist/server/modules/butler/butler-follow-up-scheduler.js +57 -0
- package/dist/server/modules/butler/butler-follow-up-scheduler.js.map +1 -0
- package/dist/server/modules/butler/butler-follow-up-service.d.ts +86 -0
- package/dist/server/modules/butler/butler-follow-up-service.js +948 -0
- package/dist/server/modules/butler/butler-follow-up-service.js.map +1 -0
- package/dist/server/modules/butler/butler-inbox-service.d.ts +35 -0
- package/dist/server/modules/butler/butler-inbox-service.js +136 -0
- package/dist/server/modules/butler/butler-inbox-service.js.map +1 -0
- package/dist/server/modules/butler/butler-notification-service.d.ts +12 -0
- package/dist/server/modules/butler/butler-notification-service.js +45 -0
- package/dist/server/modules/butler/butler-notification-service.js.map +1 -0
- package/dist/server/modules/butler/butler-profile-service.d.ts +26 -0
- package/dist/server/modules/butler/butler-profile-service.js +529 -0
- package/dist/server/modules/butler/butler-profile-service.js.map +1 -0
- package/dist/server/modules/butler/butler-project-service.d.ts +48 -0
- package/dist/server/modules/butler/butler-project-service.js +253 -0
- package/dist/server/modules/butler/butler-project-service.js.map +1 -0
- package/dist/server/modules/butler/butler-session-service.d.ts +79 -0
- package/dist/server/modules/butler/butler-session-service.js +503 -0
- package/dist/server/modules/butler/butler-session-service.js.map +1 -0
- package/dist/server/modules/butler/butler-session-summary-service.d.ts +55 -0
- package/dist/server/modules/butler/butler-session-summary-service.js +382 -0
- package/dist/server/modules/butler/butler-session-summary-service.js.map +1 -0
- package/dist/server/modules/butler/context-aggregator.d.ts +187 -0
- package/dist/server/modules/butler/context-aggregator.js +807 -0
- package/dist/server/modules/butler/context-aggregator.js.map +1 -0
- package/dist/server/modules/butler/instruction-adapter.d.ts +28 -0
- package/dist/server/modules/butler/instruction-adapter.js +101 -0
- package/dist/server/modules/butler/instruction-adapter.js.map +1 -0
- package/dist/server/modules/butler/patrol-execution-service.d.ts +47 -0
- package/dist/server/modules/butler/patrol-execution-service.js +347 -0
- package/dist/server/modules/butler/patrol-execution-service.js.map +1 -0
- package/dist/server/modules/butler/patrol-plan-service.d.ts +54 -0
- package/dist/server/modules/butler/patrol-plan-service.js +272 -0
- package/dist/server/modules/butler/patrol-plan-service.js.map +1 -0
- package/dist/server/modules/butler/patrol-run-service.d.ts +60 -0
- package/dist/server/modules/butler/patrol-run-service.js +185 -0
- package/dist/server/modules/butler/patrol-run-service.js.map +1 -0
- package/dist/server/modules/butler/patrol-scheduler.d.ts +36 -0
- package/dist/server/modules/butler/patrol-scheduler.js +99 -0
- package/dist/server/modules/butler/patrol-scheduler.js.map +1 -0
- package/dist/server/modules/butler/project-memory-service.d.ts +30 -0
- package/dist/server/modules/butler/project-memory-service.js +103 -0
- package/dist/server/modules/butler/project-memory-service.js.map +1 -0
- package/dist/server/modules/butler/provider-adapter-registry.d.ts +61 -0
- package/dist/server/modules/butler/provider-adapter-registry.js +430 -0
- package/dist/server/modules/butler/provider-adapter-registry.js.map +1 -0
- package/dist/server/modules/butler/session-summary-instruction-adapter.d.ts +28 -0
- package/dist/server/modules/butler/session-summary-instruction-adapter.js +79 -0
- package/dist/server/modules/butler/session-summary-instruction-adapter.js.map +1 -0
- package/dist/server/modules/butler/session-summary-scheduler.d.ts +23 -0
- package/dist/server/modules/butler/session-summary-scheduler.js +57 -0
- package/dist/server/modules/butler/session-summary-scheduler.js.map +1 -0
- package/dist/server/modules/butler/verification-run-service.d.ts +73 -0
- package/dist/server/modules/butler/verification-run-service.js +633 -0
- package/dist/server/modules/butler/verification-run-service.js.map +1 -0
- package/dist/server/modules/demo/demo-cleanup-service.d.ts +41 -0
- package/dist/server/modules/demo/demo-cleanup-service.js +111 -0
- package/dist/server/modules/demo/demo-cleanup-service.js.map +1 -0
- package/dist/server/modules/preferences/profile-service.js +8 -2
- package/dist/server/modules/preferences/profile-service.js.map +1 -1
- package/dist/server/modules/sessions/claude-runtime-helper-process.js +1 -1
- package/dist/server/modules/sessions/claude-runtime-helper-process.js.map +1 -1
- package/dist/server/modules/sessions/codex-app-server-helper-client.d.ts +5 -1
- package/dist/server/modules/sessions/codex-app-server-helper-client.js +10 -2
- package/dist/server/modules/sessions/codex-app-server-helper-client.js.map +1 -1
- package/dist/server/modules/sessions/session-controller.d.ts +3 -1
- package/dist/server/modules/sessions/session-controller.js +11 -2
- package/dist/server/modules/sessions/session-controller.js.map +1 -1
- package/dist/server/modules/sessions/session-history-service.d.ts +14 -1
- package/dist/server/modules/sessions/session-history-service.js +291 -30
- package/dist/server/modules/sessions/session-history-service.js.map +1 -1
- package/dist/server/modules/sessions/session-live-runtime-service.d.ts +25 -2
- package/dist/server/modules/sessions/session-live-runtime-service.js +526 -158
- package/dist/server/modules/sessions/session-live-runtime-service.js.map +1 -1
- package/dist/server/modules/sessions/session-provider-error-mapper.js +28 -0
- package/dist/server/modules/sessions/session-provider-error-mapper.js.map +1 -1
- package/dist/server/modules/terminal/terminal-service.js +2 -2
- package/dist/server/modules/terminal/terminal-service.js.map +1 -1
- package/dist/server/modules/workbench/workbench-service.d.ts +7 -1
- package/dist/server/modules/workbench/workbench-service.js +31 -7
- package/dist/server/modules/workbench/workbench-service.js.map +1 -1
- package/dist/server/routes/butler.d.ts +3 -0
- package/dist/server/routes/butler.js +54 -0
- package/dist/server/routes/butler.js.map +1 -0
- package/dist/server/routes/sessions.d.ts +1 -0
- package/dist/server/routes/sessions.js +12 -3
- package/dist/server/routes/sessions.js.map +1 -1
- package/dist/server/server/create-server.d.ts +61 -0
- package/dist/server/server/create-server.js +180 -10
- package/dist/server/server/create-server.js.map +1 -1
- package/dist/server/storage/repositories/butler-control-event-repository.d.ts +8 -0
- package/dist/server/storage/repositories/butler-control-event-repository.js +78 -0
- package/dist/server/storage/repositories/butler-control-event-repository.js.map +1 -0
- package/dist/server/storage/repositories/butler-control-session-repository.d.ts +11 -0
- package/dist/server/storage/repositories/butler-control-session-repository.js +86 -0
- package/dist/server/storage/repositories/butler-control-session-repository.js.map +1 -0
- package/dist/server/storage/repositories/butler-follow-up-task-repository.d.ts +16 -0
- package/dist/server/storage/repositories/butler-follow-up-task-repository.js +252 -0
- package/dist/server/storage/repositories/butler-follow-up-task-repository.js.map +1 -0
- package/dist/server/storage/repositories/butler-inbox-item-repository.d.ts +15 -0
- package/dist/server/storage/repositories/butler-inbox-item-repository.js +111 -0
- package/dist/server/storage/repositories/butler-inbox-item-repository.js.map +1 -0
- package/dist/server/storage/repositories/butler-notification-archive-repository.d.ts +9 -0
- package/dist/server/storage/repositories/butler-notification-archive-repository.js +48 -0
- package/dist/server/storage/repositories/butler-notification-archive-repository.js.map +1 -0
- package/dist/server/storage/repositories/butler-profile-repository.d.ts +9 -0
- package/dist/server/storage/repositories/butler-profile-repository.js +86 -0
- package/dist/server/storage/repositories/butler-profile-repository.js.map +1 -0
- package/dist/server/storage/repositories/butler-project-repository.d.ts +14 -0
- package/dist/server/storage/repositories/butler-project-repository.js +140 -0
- package/dist/server/storage/repositories/butler-project-repository.js.map +1 -0
- package/dist/server/storage/repositories/butler-session-repository.d.ts +11 -0
- package/dist/server/storage/repositories/butler-session-repository.js +106 -0
- package/dist/server/storage/repositories/butler-session-repository.js.map +1 -0
- package/dist/server/storage/repositories/butler-session-summary-state-repository.d.ts +8 -0
- package/dist/server/storage/repositories/butler-session-summary-state-repository.js +62 -0
- package/dist/server/storage/repositories/butler-session-summary-state-repository.js.map +1 -0
- package/dist/server/storage/repositories/patrol-plan-repository.d.ts +27 -0
- package/dist/server/storage/repositories/patrol-plan-repository.js +119 -0
- package/dist/server/storage/repositories/patrol-plan-repository.js.map +1 -0
- package/dist/server/storage/repositories/patrol-run-repository.d.ts +28 -0
- package/dist/server/storage/repositories/patrol-run-repository.js +121 -0
- package/dist/server/storage/repositories/patrol-run-repository.js.map +1 -0
- package/dist/server/storage/repositories/project-memory-repository.d.ts +15 -0
- package/dist/server/storage/repositories/project-memory-repository.js +150 -0
- package/dist/server/storage/repositories/project-memory-repository.js.map +1 -0
- package/dist/server/storage/repositories/session-checkpoint-repository.d.ts +9 -0
- package/dist/server/storage/repositories/session-checkpoint-repository.js +72 -0
- package/dist/server/storage/repositories/session-checkpoint-repository.js.map +1 -0
- package/dist/server/storage/repositories/session-message-origin-repository.d.ts +10 -0
- package/dist/server/storage/repositories/session-message-origin-repository.js +93 -0
- package/dist/server/storage/repositories/session-message-origin-repository.js.map +1 -0
- package/dist/server/storage/repositories/verification-run-repository.d.ts +29 -0
- package/dist/server/storage/repositories/verification-run-repository.js +125 -0
- package/dist/server/storage/repositories/verification-run-repository.js.map +1 -0
- package/dist/server/storage/sqlite/client.js +39 -0
- package/dist/server/storage/sqlite/client.js.map +1 -1
- package/dist/server/storage/sqlite/schema.sql +324 -0
- package/dist/server/types/domain.d.ts +261 -1
- package/dist/server/ws/ws-server.d.ts +2 -1
- package/dist/server/ws/ws-server.js +2 -1
- package/dist/server/ws/ws-server.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/index.d.ts +4 -0
- package/node_modules/@codingns/session-sync-core/dist/index.js +4 -0
- package/node_modules/@codingns/session-sync-core/dist/index.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/kimi-message-normalizer.d.ts +18 -0
- package/node_modules/@codingns/session-sync-core/dist/kimi-message-normalizer.js +659 -0
- package/node_modules/@codingns/session-sync-core/dist/kimi-message-normalizer.js.map +1 -0
- package/node_modules/@codingns/session-sync-core/dist/kimi-shared.d.ts +11 -0
- package/node_modules/@codingns/session-sync-core/dist/kimi-shared.js +72 -0
- package/node_modules/@codingns/session-sync-core/dist/kimi-shared.js.map +1 -0
- package/node_modules/@codingns/session-sync-core/dist/patch-builder.d.ts +8 -0
- package/node_modules/@codingns/session-sync-core/dist/patch-builder.js +89 -0
- package/node_modules/@codingns/session-sync-core/dist/patch-builder.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/codex.js +4 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/codex.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/gemini.d.ts +41 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/gemini.js +1086 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/gemini.js.map +1 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/kimi.d.ts +29 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/kimi.js +578 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/kimi.js.map +1 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/opencode.js +2 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/opencode.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/utils.js +30 -2
- package/node_modules/@codingns/session-sync-core/dist/providers/utils.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/active-run-registry.d.ts +2 -0
- package/node_modules/@codingns/session-sync-core/dist/runtime/active-run-registry.js +43 -5
- package/node_modules/@codingns/session-sync-core/dist/runtime/active-run-registry.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.d.ts +2 -0
- package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js +320 -69
- package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/gemini-runtime.d.ts +21 -0
- package/node_modules/@codingns/session-sync-core/dist/runtime/gemini-runtime.js +537 -0
- package/node_modules/@codingns/session-sync-core/dist/runtime/gemini-runtime.js.map +1 -0
- package/node_modules/@codingns/session-sync-core/dist/runtime/kimi-runtime.d.ts +38 -0
- package/node_modules/@codingns/session-sync-core/dist/runtime/kimi-runtime.js +911 -0
- package/node_modules/@codingns/session-sync-core/dist/runtime/kimi-runtime.js.map +1 -0
- package/node_modules/@codingns/session-sync-core/dist/sqlite/node-sqlite.d.ts +6 -0
- package/node_modules/@codingns/session-sync-core/dist/sqlite/node-sqlite.js +9 -0
- package/node_modules/@codingns/session-sync-core/dist/sqlite/node-sqlite.js.map +1 -0
- package/node_modules/@codingns/session-sync-core/package.json +8 -0
- package/package.json +1 -1
- package/dist/public/assets/index-9hnprhO7.css +0 -1
- package/dist/public/assets/index-BTpmuKhG.js +0 -108
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { existsSync, readdirSync } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { performance } from "node:perf_hooks";
|
|
4
|
+
import { ClaudeRuntimeAdapter, CodexRuntimeAdapter, GeminiRuntimeAdapter, KimiRuntimeAdapter, OpenCodeRuntimeAdapter, ProviderRuntimeService } from "@codingns/session-sync-core";
|
|
4
5
|
import { AppError } from "../../shared/errors/app-error.js";
|
|
5
6
|
import { createId } from "../../shared/utils/id.js";
|
|
7
|
+
import { isPerfDebugEnabled, logPerformance } from "../../shared/utils/perf-log.js";
|
|
6
8
|
import { logPermissionDebug } from "../../shared/utils/permission-debug-log.js";
|
|
7
9
|
import { nowIso } from "../../shared/utils/time.js";
|
|
8
10
|
import { SessionActivityAuthorityService } from "./session-activity-authority-service.js";
|
|
@@ -10,6 +12,8 @@ import { SessionPermissionRequestService } from "./session-permission-request-se
|
|
|
10
12
|
import { mapSessionProviderError } from "./session-provider-error-mapper.js";
|
|
11
13
|
import { ClaudeRuntimeHelperAdapter } from "./claude-runtime-helper-client.js";
|
|
12
14
|
import { CodexAppServerHelperClient } from "./codex-app-server-helper-client.js";
|
|
15
|
+
const RUNTIME_START_BINDING_WAIT_TIMEOUT_MS = 10_000;
|
|
16
|
+
const START_BINDING_POLL_INTERVAL_MS = 50;
|
|
13
17
|
export class SessionLiveRuntimeService {
|
|
14
18
|
sessionHistoryService;
|
|
15
19
|
sessionMessageAttachmentService;
|
|
@@ -28,10 +32,12 @@ export class SessionLiveRuntimeService {
|
|
|
28
32
|
runtimeAdapterDisposables;
|
|
29
33
|
externalRuntimeSnapshots = new Map();
|
|
30
34
|
runtimeListeners = new Map();
|
|
35
|
+
terminalStateListeners = new Set();
|
|
31
36
|
runtimeMessageSeenSessions = new Set();
|
|
32
37
|
runtimeHistoryFallbackSentSessions = new Set();
|
|
33
38
|
queueDispatchSessions = new Set();
|
|
34
39
|
queueRetryTimers = new Map();
|
|
40
|
+
pendingSendDebugTracesBySessionId = new Map();
|
|
35
41
|
constructor(sessionHistoryService, sessionMessageAttachmentService, workspaceService, sessionChangedFileService, sessionBindingRepository, authUserRepository, sessionSendQueueRepository, sessionIndexRepository, sessionStateRepository, sessionStatusSnapshotRepository, config, sessionActivityAuthorityService = new SessionActivityAuthorityService()) {
|
|
36
42
|
this.sessionHistoryService = sessionHistoryService;
|
|
37
43
|
this.sessionMessageAttachmentService = sessionMessageAttachmentService;
|
|
@@ -58,63 +64,109 @@ export class SessionLiveRuntimeService {
|
|
|
58
64
|
}
|
|
59
65
|
async startLiveSession(input) {
|
|
60
66
|
const requestStartedAt = nowIso();
|
|
61
|
-
const capabilities = this.sessionHistoryService.getProviderCapabilitiesSnapshot(input.provider);
|
|
62
|
-
const workspace = this.workspaceService.getWorkspaceOrThrow(input.workspaceId);
|
|
63
67
|
const sessionId = createId();
|
|
64
|
-
this.
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
this.ensureCapability(capabilities.canStartSession, "provider", "provider 不支持 start-live");
|
|
68
|
-
this.ensureCapability(capabilities.canSendMessage, "provider", "provider 不支持实时对话");
|
|
69
|
-
const handle = await this.launchRuntimeRun({
|
|
70
|
-
sessionId,
|
|
71
|
-
workspaceId: workspace.id,
|
|
72
|
-
workspacePath: workspace.path,
|
|
73
|
-
provider: input.provider,
|
|
74
|
-
providerSessionId: null,
|
|
75
|
-
rawStoreRef: null,
|
|
76
|
-
sequenceBase: 1,
|
|
77
|
-
options: {
|
|
78
|
-
content: input.content,
|
|
79
|
-
clientRequestId: input.clientRequestId,
|
|
80
|
-
model: input.runtimeOptions?.model ?? null,
|
|
81
|
-
reasoningLevel: input.runtimeOptions?.reasoningLevel ?? null,
|
|
82
|
-
permissionMode: input.runtimeOptions?.permissionMode ?? null,
|
|
83
|
-
providerPrompt,
|
|
84
|
-
attachments: persistedAttachments.runtimeAttachments
|
|
85
|
-
}
|
|
86
|
-
}, "start");
|
|
87
|
-
const snapshot = handle.getSnapshot();
|
|
88
|
-
this.attachRuntimePersistence(handle, sessionId, workspace.id, input.userId);
|
|
89
|
-
this.createRuntimeBackedSession({
|
|
68
|
+
const workspace = this.workspaceService.getWorkspaceOrThrow(input.workspaceId);
|
|
69
|
+
const debugTrace = this.beginPendingSendDebugTrace({
|
|
70
|
+
mode: "start_live",
|
|
90
71
|
sessionId,
|
|
91
72
|
workspaceId: workspace.id,
|
|
92
|
-
userId: input.userId,
|
|
93
73
|
provider: input.provider,
|
|
94
|
-
|
|
95
|
-
snapshot
|
|
74
|
+
clientRequestId: input.clientRequestId
|
|
96
75
|
});
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
provider
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
76
|
+
try {
|
|
77
|
+
const capabilities = this.sessionHistoryService.getProviderCapabilitiesSnapshot(input.provider);
|
|
78
|
+
this.ensurePendingSessionBinding(sessionId, workspace.id, input.provider);
|
|
79
|
+
const persistedAttachments = this.persistMessageAttachments(sessionId, input.clientRequestId, input.runtimeOptions?.attachments ?? []);
|
|
80
|
+
const providerPrompt = this.sessionMessageAttachmentService.buildProviderPrompt(input.provider, input.content, persistedAttachments.runtimeAttachments);
|
|
81
|
+
this.ensureCapability(capabilities.canStartSession, "provider", "provider 不支持 start-live");
|
|
82
|
+
this.ensureCapability(capabilities.canSendMessage, "provider", "provider 不支持实时对话");
|
|
83
|
+
const launchRuntimeStartedAtMs = performance.now();
|
|
84
|
+
const handle = await this.launchRuntimeRun({
|
|
85
|
+
sessionId,
|
|
86
|
+
workspaceId: workspace.id,
|
|
87
|
+
workspacePath: workspace.path,
|
|
88
|
+
provider: input.provider,
|
|
89
|
+
providerSessionId: null,
|
|
90
|
+
rawStoreRef: null,
|
|
91
|
+
sequenceBase: 1,
|
|
92
|
+
options: {
|
|
93
|
+
content: input.content,
|
|
94
|
+
clientRequestId: input.clientRequestId,
|
|
95
|
+
model: input.runtimeOptions?.model ?? null,
|
|
96
|
+
reasoningLevel: input.runtimeOptions?.reasoningLevel ?? null,
|
|
97
|
+
permissionMode: input.runtimeOptions?.permissionMode ?? null,
|
|
98
|
+
providerPrompt,
|
|
99
|
+
attachments: persistedAttachments.runtimeAttachments
|
|
111
100
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
101
|
+
}, "start");
|
|
102
|
+
this.logSendDebugStep(debugTrace, "launch_runtime", launchRuntimeStartedAtMs, {
|
|
103
|
+
userId: input.userId
|
|
104
|
+
});
|
|
105
|
+
const snapshot = handle.getSnapshot();
|
|
106
|
+
this.attachRuntimePersistence(handle, sessionId, workspace.id, input.userId);
|
|
107
|
+
this.createRuntimeBackedSession({
|
|
108
|
+
sessionId,
|
|
109
|
+
workspaceId: workspace.id,
|
|
110
|
+
userId: input.userId,
|
|
111
|
+
provider: input.provider,
|
|
112
|
+
initialContent: input.content,
|
|
113
|
+
snapshot
|
|
114
|
+
});
|
|
115
|
+
const startBindingTask = this.waitForResolvedStartBinding(sessionId, workspace.id, input.provider, handle).catch(() => {
|
|
116
|
+
return;
|
|
117
|
+
});
|
|
118
|
+
if (shouldAwaitStartBindingBeforeAcceptedUserLookup(input.provider)) {
|
|
119
|
+
const bindingWaitStartedAtMs = performance.now();
|
|
120
|
+
await Promise.race([
|
|
121
|
+
startBindingTask,
|
|
122
|
+
waitForAcceptedUserLookupWindow()
|
|
123
|
+
]);
|
|
124
|
+
this.logSendDebugStep(debugTrace, "binding_wait", bindingWaitStartedAtMs, {
|
|
125
|
+
provider: input.provider
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
const binding = this.sessionHistoryService.getBindingOrThrow(sessionId);
|
|
129
|
+
const acceptedLookupStartedAtMs = performance.now();
|
|
130
|
+
const acceptedMessage = shouldAwaitAcceptedUserMessage(input.provider)
|
|
131
|
+
? await this.findAcceptedUserMessage(sessionId, this.sessionMessageAttachmentService.buildAcceptedContentCandidates(input.content, providerPrompt), requestStartedAt)
|
|
132
|
+
: null;
|
|
133
|
+
this.logSendDebugStep(debugTrace, "accepted_user_lookup", acceptedLookupStartedAtMs, {
|
|
134
|
+
awaited: shouldAwaitAcceptedUserMessage(input.provider),
|
|
135
|
+
matched: Boolean(acceptedMessage)
|
|
136
|
+
});
|
|
137
|
+
if (!shouldAwaitStartBindingBeforeAcceptedUserLookup(input.provider)) {
|
|
138
|
+
void startBindingTask;
|
|
139
|
+
}
|
|
140
|
+
const acceptedAt = acceptedMessage?.timestamp ?? nowIso();
|
|
141
|
+
const boundAttachments = this.sessionMessageAttachmentService.bindClientRequestToMessage(sessionId, input.clientRequestId, acceptedMessage?.messageId ?? null);
|
|
142
|
+
const session = this.sessionHistoryService.getSession(sessionId, input.userId);
|
|
143
|
+
this.markSendDebugResponseReady(debugTrace, {
|
|
144
|
+
returnedAcceptedMessage: Boolean(acceptedMessage),
|
|
145
|
+
returnedSyntheticUser: !acceptedMessage,
|
|
146
|
+
providerSessionId: binding.providerSessionId
|
|
147
|
+
});
|
|
148
|
+
return {
|
|
149
|
+
sessionId: session.sessionId,
|
|
150
|
+
provider: input.provider,
|
|
151
|
+
providerSessionId: binding.providerSessionId,
|
|
152
|
+
acceptedAt,
|
|
153
|
+
clientRequestId: input.clientRequestId,
|
|
154
|
+
message: (acceptedMessage
|
|
155
|
+
? {
|
|
156
|
+
...acceptedMessage,
|
|
157
|
+
attachments: boundAttachments
|
|
158
|
+
}
|
|
159
|
+
: null) ??
|
|
160
|
+
createSyntheticUserMessage(input.provider, binding.providerSessionId, input.content, acceptedAt, 1, boundAttachments.length > 0
|
|
161
|
+
? boundAttachments
|
|
162
|
+
: persistedAttachments.messageAttachments),
|
|
163
|
+
session
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
this.failPendingSendDebugTrace(debugTrace, error);
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
118
170
|
}
|
|
119
171
|
async sendLiveMessage(input) {
|
|
120
172
|
return this.sendLiveMessageDirect(input);
|
|
@@ -169,7 +221,8 @@ export class SessionLiveRuntimeService {
|
|
|
169
221
|
field: "queueItemId"
|
|
170
222
|
});
|
|
171
223
|
}
|
|
172
|
-
const
|
|
224
|
+
const runtimeSessionId = this.resolveRuntimeSessionId(sessionId);
|
|
225
|
+
const runtimeSnapshot = this.providerRuntimeService.getSnapshot(runtimeSessionId);
|
|
173
226
|
if (!runtimeSnapshot || !isActiveRuntimeState(runtimeSnapshot.runningState)) {
|
|
174
227
|
throw new AppError({
|
|
175
228
|
statusCode: 409,
|
|
@@ -225,7 +278,7 @@ export class SessionLiveRuntimeService {
|
|
|
225
278
|
};
|
|
226
279
|
}
|
|
227
280
|
catch (error) {
|
|
228
|
-
if (
|
|
281
|
+
if (isQueueDispatchRetryableError(error)) {
|
|
229
282
|
this.sessionSendQueueRepository.markQueued(queueItem.id, nowIso());
|
|
230
283
|
this.scheduleQueueRetry(sessionId);
|
|
231
284
|
}
|
|
@@ -368,8 +421,9 @@ export class SessionLiveRuntimeService {
|
|
|
368
421
|
};
|
|
369
422
|
}
|
|
370
423
|
async getSessionRuntime(sessionId, userId) {
|
|
371
|
-
const
|
|
372
|
-
const
|
|
424
|
+
const runtimeSessionId = this.resolveRuntimeSessionId(sessionId);
|
|
425
|
+
const runtimeSnapshot = this.providerRuntimeService.getSnapshot(runtimeSessionId);
|
|
426
|
+
const externalRuntimeSnapshot = this.externalRuntimeSnapshots.get(runtimeSessionId) ?? null;
|
|
373
427
|
const session = runtimeSnapshot || externalRuntimeSnapshot
|
|
374
428
|
? this.sessionHistoryService.getSession(sessionId, userId)
|
|
375
429
|
: await this.sessionHistoryService.refreshRuntimeFallbackSession(sessionId, userId);
|
|
@@ -377,9 +431,9 @@ export class SessionLiveRuntimeService {
|
|
|
377
431
|
const capabilities = await this.sessionHistoryService.getSessionCapabilities(sessionId);
|
|
378
432
|
const contextUsage = await this.sessionHistoryService.getSessionContextUsage(sessionId).catch(() => null);
|
|
379
433
|
const resolution = runtimeSnapshot
|
|
380
|
-
? this.sessionActivityAuthorityService.observe(createRuntimeActivityObservation(
|
|
434
|
+
? this.sessionActivityAuthorityService.observe(createRuntimeActivityObservation(runtimeSessionId, runtimeSnapshot))
|
|
381
435
|
: externalRuntimeSnapshot
|
|
382
|
-
? this.sessionActivityAuthorityService.observe(createExternalRuntimeActivityObservation(
|
|
436
|
+
? this.sessionActivityAuthorityService.observe(createExternalRuntimeActivityObservation(runtimeSessionId, externalRuntimeSnapshot))
|
|
383
437
|
: this.sessionActivityAuthorityService.resolvePersistedSession(session);
|
|
384
438
|
if (runtimeSnapshot) {
|
|
385
439
|
return {
|
|
@@ -451,7 +505,8 @@ export class SessionLiveRuntimeService {
|
|
|
451
505
|
}
|
|
452
506
|
async interruptSession(sessionId, userId) {
|
|
453
507
|
this.sessionHistoryService.getSession(sessionId, userId);
|
|
454
|
-
const
|
|
508
|
+
const runtimeSessionId = this.resolveRuntimeSessionId(sessionId);
|
|
509
|
+
const runtime = this.providerRuntimeService.getSnapshot(runtimeSessionId);
|
|
455
510
|
if (!runtime || (runtime.runningState !== "running" && runtime.runningState !== "starting")) {
|
|
456
511
|
throw new AppError({
|
|
457
512
|
statusCode: 409,
|
|
@@ -460,7 +515,7 @@ export class SessionLiveRuntimeService {
|
|
|
460
515
|
field: "sessionId"
|
|
461
516
|
});
|
|
462
517
|
}
|
|
463
|
-
const interrupted = await this.providerRuntimeService.interrupt(
|
|
518
|
+
const interrupted = await this.providerRuntimeService.interrupt(runtimeSessionId).catch((error) => {
|
|
464
519
|
if (error instanceof Error && error.message === "INTERRUPT_NOT_SUPPORTED") {
|
|
465
520
|
throw new AppError({
|
|
466
521
|
statusCode: 400,
|
|
@@ -477,6 +532,14 @@ export class SessionLiveRuntimeService {
|
|
|
477
532
|
detail: interrupted.detail ?? "interrupt requested"
|
|
478
533
|
};
|
|
479
534
|
}
|
|
535
|
+
registerTerminalStateListener(listener) {
|
|
536
|
+
this.terminalStateListeners.add(listener);
|
|
537
|
+
return {
|
|
538
|
+
close: () => {
|
|
539
|
+
this.terminalStateListeners.delete(listener);
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
}
|
|
480
543
|
async listPermissionRequests(sessionId, userId) {
|
|
481
544
|
return this.sessionPermissionRequestService.listSessionPermissionRequests(sessionId, userId);
|
|
482
545
|
}
|
|
@@ -484,9 +547,10 @@ export class SessionLiveRuntimeService {
|
|
|
484
547
|
return this.sessionPermissionRequestService.replyToSessionPermissionRequest(sessionId, userId, requestId, input);
|
|
485
548
|
}
|
|
486
549
|
subscribeRuntime(sessionId, onEnvelope) {
|
|
487
|
-
const
|
|
488
|
-
const
|
|
489
|
-
const
|
|
550
|
+
const runtimeSessionId = this.resolveRuntimeSessionId(sessionId);
|
|
551
|
+
const runtimeSnapshot = this.providerRuntimeService.getSnapshot(runtimeSessionId);
|
|
552
|
+
const externalRuntimeSnapshot = this.externalRuntimeSnapshots.get(runtimeSessionId) ?? null;
|
|
553
|
+
const initialActivityEnvelope = this.buildSessionActivityEnvelope(sessionId, runtimeSessionId);
|
|
490
554
|
if (runtimeSnapshot) {
|
|
491
555
|
void onEnvelope({
|
|
492
556
|
type: "session.runtime_status",
|
|
@@ -508,16 +572,21 @@ export class SessionLiveRuntimeService {
|
|
|
508
572
|
if (initialActivityEnvelope) {
|
|
509
573
|
void onEnvelope(initialActivityEnvelope);
|
|
510
574
|
}
|
|
511
|
-
const runtimeSubscription = this.providerRuntimeService.subscribe(
|
|
512
|
-
const envelope = this.mapRuntimeEventToEnvelope(sessionId, event);
|
|
575
|
+
const runtimeSubscription = this.providerRuntimeService.subscribe(runtimeSessionId, async (event) => {
|
|
576
|
+
const envelope = this.mapRuntimeEventToEnvelope(sessionId, event, runtimeSessionId);
|
|
513
577
|
if (!envelope) {
|
|
514
578
|
return;
|
|
515
579
|
}
|
|
516
580
|
await onEnvelope(envelope);
|
|
517
581
|
});
|
|
518
|
-
const externalSubscription = this.subscribeExternalRuntime(
|
|
519
|
-
|
|
520
|
-
|
|
582
|
+
const externalSubscription = this.subscribeExternalRuntime(runtimeSessionId, async (envelope) => {
|
|
583
|
+
await onEnvelope({
|
|
584
|
+
...envelope,
|
|
585
|
+
sessionId
|
|
586
|
+
});
|
|
587
|
+
});
|
|
588
|
+
const activitySubscription = this.sessionActivityAuthorityService.subscribe(runtimeSessionId, async () => {
|
|
589
|
+
const envelope = this.buildSessionActivityEnvelope(sessionId, runtimeSessionId);
|
|
521
590
|
if (!envelope) {
|
|
522
591
|
return;
|
|
523
592
|
}
|
|
@@ -578,31 +647,67 @@ export class SessionLiveRuntimeService {
|
|
|
578
647
|
await listener(envelope);
|
|
579
648
|
}));
|
|
580
649
|
}
|
|
581
|
-
buildSessionActivityEnvelope(sessionId) {
|
|
582
|
-
const runtimeSnapshot = this.providerRuntimeService.getSnapshot(
|
|
650
|
+
buildSessionActivityEnvelope(sessionId, runtimeSessionId = sessionId) {
|
|
651
|
+
const runtimeSnapshot = this.providerRuntimeService.getSnapshot(runtimeSessionId);
|
|
583
652
|
if (runtimeSnapshot) {
|
|
584
|
-
const resolution = this.sessionActivityAuthorityService.observe(createRuntimeActivityObservation(
|
|
585
|
-
return
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
653
|
+
const resolution = this.sessionActivityAuthorityService.observe(createRuntimeActivityObservation(runtimeSessionId, runtimeSnapshot));
|
|
654
|
+
return {
|
|
655
|
+
...this.mapResolutionToActivityEnvelope(resolution, {
|
|
656
|
+
hasActiveRun: true,
|
|
657
|
+
canInterrupt: runtimeSnapshot.supportsInterrupt
|
|
658
|
+
}),
|
|
659
|
+
sessionId
|
|
660
|
+
};
|
|
589
661
|
}
|
|
590
|
-
const externalRuntimeSnapshot = this.externalRuntimeSnapshots.get(
|
|
662
|
+
const externalRuntimeSnapshot = this.externalRuntimeSnapshots.get(runtimeSessionId) ?? null;
|
|
591
663
|
if (externalRuntimeSnapshot) {
|
|
592
|
-
const resolution = this.sessionActivityAuthorityService.observe(createExternalRuntimeActivityObservation(
|
|
593
|
-
return
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
664
|
+
const resolution = this.sessionActivityAuthorityService.observe(createExternalRuntimeActivityObservation(runtimeSessionId, externalRuntimeSnapshot));
|
|
665
|
+
return {
|
|
666
|
+
...this.mapResolutionToActivityEnvelope(resolution, {
|
|
667
|
+
hasActiveRun: true,
|
|
668
|
+
canInterrupt: false
|
|
669
|
+
}),
|
|
670
|
+
sessionId
|
|
671
|
+
};
|
|
597
672
|
}
|
|
598
|
-
const resolution = this.sessionActivityAuthorityService.getResolution(
|
|
673
|
+
const resolution = this.sessionActivityAuthorityService.getResolution(runtimeSessionId);
|
|
599
674
|
if (!resolution) {
|
|
600
675
|
return null;
|
|
601
676
|
}
|
|
602
|
-
return
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
677
|
+
return {
|
|
678
|
+
...this.mapResolutionToActivityEnvelope(resolution, {
|
|
679
|
+
hasActiveRun: resolution.runningState === "stale" || resolution.runningState === "unknown",
|
|
680
|
+
canInterrupt: false
|
|
681
|
+
}),
|
|
682
|
+
sessionId
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
resolveRuntimeSessionId(sessionId) {
|
|
686
|
+
if (this.providerRuntimeService.getSnapshot(sessionId)
|
|
687
|
+
|| this.externalRuntimeSnapshots.has(sessionId)) {
|
|
688
|
+
return sessionId;
|
|
689
|
+
}
|
|
690
|
+
const listSnapshots = "listSnapshots" in this.providerRuntimeService
|
|
691
|
+
&& typeof this.providerRuntimeService.listSnapshots === "function"
|
|
692
|
+
? this.providerRuntimeService.listSnapshots.bind(this.providerRuntimeService)
|
|
693
|
+
: null;
|
|
694
|
+
if (!listSnapshots) {
|
|
695
|
+
return sessionId;
|
|
696
|
+
}
|
|
697
|
+
const linkedSnapshot = listSnapshots()
|
|
698
|
+
.find((snapshot) => this.isLinkedGeminiRuntimeSession(snapshot.sessionId, sessionId));
|
|
699
|
+
return linkedSnapshot?.sessionId ?? sessionId;
|
|
700
|
+
}
|
|
701
|
+
isLinkedGeminiRuntimeSession(candidateSessionId, targetSessionId) {
|
|
702
|
+
if (candidateSessionId === targetSessionId) {
|
|
703
|
+
return true;
|
|
704
|
+
}
|
|
705
|
+
const binding = this.sessionBindingRepository.findBySessionId(candidateSessionId);
|
|
706
|
+
if (!binding || binding.provider !== "gemini") {
|
|
707
|
+
return false;
|
|
708
|
+
}
|
|
709
|
+
return isGeminiPendingRuntimeAliasBinding(binding.providerSessionId, targetSessionId)
|
|
710
|
+
|| isGeminiPendingRuntimeAliasBinding(binding.rawStoreRef, targetSessionId);
|
|
606
711
|
}
|
|
607
712
|
mapResolutionToActivityEnvelope(resolution, options) {
|
|
608
713
|
return {
|
|
@@ -764,6 +869,13 @@ export class SessionLiveRuntimeService {
|
|
|
764
869
|
};
|
|
765
870
|
await this.emitExternalRuntimeEnvelope(envelope);
|
|
766
871
|
if (isTerminalSessionRunningState(input.runningState)) {
|
|
872
|
+
await this.emitTerminalStateEvent({
|
|
873
|
+
sessionId: input.sessionId,
|
|
874
|
+
status: input.runningState,
|
|
875
|
+
timestamp: input.timestamp,
|
|
876
|
+
detail: input.detail,
|
|
877
|
+
source: "external_runtime"
|
|
878
|
+
});
|
|
767
879
|
void this.dispatchNextQueuedMessage(input.sessionId);
|
|
768
880
|
}
|
|
769
881
|
}
|
|
@@ -794,80 +906,114 @@ export class SessionLiveRuntimeService {
|
|
|
794
906
|
async sendLiveMessageDirect(input, persistedAttachments) {
|
|
795
907
|
const requestStartedAt = nowIso();
|
|
796
908
|
const session = this.sessionHistoryService.getSession(input.sessionId, input.userId);
|
|
797
|
-
const
|
|
798
|
-
|
|
799
|
-
const runtimeMode = shouldStartNativeSessionOnFirstMessage(session);
|
|
800
|
-
const resolvedAttachments = persistedAttachments
|
|
801
|
-
?? this.persistMessageAttachments(input.sessionId, input.clientRequestId, input.runtimeOptions?.attachments ?? []);
|
|
802
|
-
const providerPrompt = this.sessionMessageAttachmentService.buildProviderPrompt(session.provider, input.content, resolvedAttachments.runtimeAttachments);
|
|
803
|
-
this.ensureCapability(capabilities.canSendMessage, "sessionId", "provider 不支持实时对话");
|
|
804
|
-
const runtimeRequest = {
|
|
909
|
+
const debugTrace = this.beginPendingSendDebugTrace({
|
|
910
|
+
mode: "send_live",
|
|
805
911
|
sessionId: input.sessionId,
|
|
806
912
|
workspaceId: session.workspaceId,
|
|
807
|
-
workspacePath: workspace.path,
|
|
808
913
|
provider: session.provider,
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
914
|
+
clientRequestId: input.clientRequestId
|
|
915
|
+
});
|
|
916
|
+
try {
|
|
917
|
+
const capabilities = await this.sessionHistoryService.getSessionCapabilities(input.sessionId);
|
|
918
|
+
const workspace = this.workspaceService.getWorkspaceOrThrow(session.workspaceId);
|
|
919
|
+
const runtimeMode = shouldStartNativeSessionOnFirstMessage(session);
|
|
920
|
+
const nextUserSequence = runtimeMode === "start"
|
|
812
921
|
? 1
|
|
813
|
-
:
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
922
|
+
: await this.resolveNextUserSequence(input.sessionId, session.messageCount);
|
|
923
|
+
const resolvedAttachments = persistedAttachments
|
|
924
|
+
?? this.persistMessageAttachments(input.sessionId, input.clientRequestId, input.runtimeOptions?.attachments ?? []);
|
|
925
|
+
const providerPrompt = this.sessionMessageAttachmentService.buildProviderPrompt(session.provider, input.content, resolvedAttachments.runtimeAttachments);
|
|
926
|
+
this.ensureCapability(capabilities.canSendMessage, "sessionId", "provider 不支持实时对话");
|
|
927
|
+
const runtimeRequest = {
|
|
928
|
+
sessionId: input.sessionId,
|
|
929
|
+
workspaceId: session.workspaceId,
|
|
930
|
+
workspacePath: workspace.path,
|
|
931
|
+
provider: session.provider,
|
|
932
|
+
providerSessionId: runtimeMode === "start" ? null : session.providerSessionId,
|
|
933
|
+
rawStoreRef: runtimeMode === "start" ? null : session.rawStoreRef,
|
|
934
|
+
sequenceBase: nextUserSequence,
|
|
935
|
+
options: {
|
|
936
|
+
content: input.content,
|
|
937
|
+
clientRequestId: input.clientRequestId,
|
|
938
|
+
model: input.runtimeOptions?.model ?? null,
|
|
939
|
+
reasoningLevel: input.runtimeOptions?.reasoningLevel ?? null,
|
|
940
|
+
permissionMode: input.runtimeOptions?.permissionMode ?? null,
|
|
941
|
+
providerPrompt,
|
|
942
|
+
attachments: resolvedAttachments.runtimeAttachments
|
|
943
|
+
}
|
|
944
|
+
};
|
|
945
|
+
const runtimeSessionId = this.resolveRuntimeSessionId(input.sessionId);
|
|
946
|
+
const activeRun = this.providerRuntimeService.getSnapshot(runtimeSessionId);
|
|
947
|
+
const externalRuntimeSnapshot = this.externalRuntimeSnapshots.get(runtimeSessionId);
|
|
948
|
+
if (activeRun &&
|
|
949
|
+
activeRun.provider === "claude-code" &&
|
|
950
|
+
isActiveRuntimeState(activeRun.runningState)) {
|
|
951
|
+
this.clearExternalRuntimeSnapshot(runtimeSessionId);
|
|
822
952
|
}
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
isActiveRuntimeState(
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
953
|
+
if (!activeRun &&
|
|
954
|
+
session.provider === "claude-code" &&
|
|
955
|
+
externalRuntimeSnapshot &&
|
|
956
|
+
isActiveRuntimeState(externalRuntimeSnapshot.runningState)) {
|
|
957
|
+
throw new AppError({
|
|
958
|
+
statusCode: 409,
|
|
959
|
+
errorCode: "SESSION_EXTERNAL_RUN_ACTIVE",
|
|
960
|
+
detail: "当前 Claude 外部会话仍在运行,不能直接追加;请加入队列或等待当前轮结束",
|
|
961
|
+
field: "sessionId"
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
if (activeRun && isActiveRuntimeState(activeRun.runningState)) {
|
|
965
|
+
const submitStartedAtMs = performance.now();
|
|
966
|
+
await this.providerRuntimeService.submitToActiveRun(runtimeSessionId, runtimeRequest.options)
|
|
967
|
+
.catch((error) => {
|
|
968
|
+
throw mapSessionProviderError(error);
|
|
969
|
+
});
|
|
970
|
+
this.logSendDebugStep(debugTrace, "submit_to_active_run", submitStartedAtMs, {
|
|
971
|
+
runtimeMode,
|
|
972
|
+
activeRunState: activeRun.runningState
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
else {
|
|
976
|
+
const startRuntimeStartedAtMs = performance.now();
|
|
977
|
+
await this.startRuntimeRun(runtimeRequest, input.userId, runtimeMode);
|
|
978
|
+
this.logSendDebugStep(debugTrace, "start_runtime_run", startRuntimeStartedAtMs, {
|
|
979
|
+
runtimeMode
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
const binding = this.sessionHistoryService.getBindingOrThrow(input.sessionId);
|
|
983
|
+
const acceptedLookupStartedAtMs = performance.now();
|
|
984
|
+
const acceptedMessage = await this.findAcceptedUserMessage(input.sessionId, this.sessionMessageAttachmentService.buildAcceptedContentCandidates(input.content, providerPrompt), requestStartedAt);
|
|
985
|
+
this.logSendDebugStep(debugTrace, "accepted_user_lookup", acceptedLookupStartedAtMs, {
|
|
986
|
+
matched: Boolean(acceptedMessage)
|
|
840
987
|
});
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
988
|
+
const acceptedAt = acceptedMessage?.timestamp ?? nowIso();
|
|
989
|
+
const boundAttachments = this.sessionMessageAttachmentService.bindClientRequestToMessage(input.sessionId, input.clientRequestId, acceptedMessage?.messageId ?? null);
|
|
990
|
+
this.markSendDebugResponseReady(debugTrace, {
|
|
991
|
+
runtimeMode,
|
|
992
|
+
returnedAcceptedMessage: Boolean(acceptedMessage),
|
|
993
|
+
returnedSyntheticUser: !acceptedMessage,
|
|
994
|
+
providerSessionId: binding.providerSessionId
|
|
846
995
|
});
|
|
996
|
+
return {
|
|
997
|
+
sessionId: input.sessionId,
|
|
998
|
+
provider: session.provider,
|
|
999
|
+
providerSessionId: binding.providerSessionId,
|
|
1000
|
+
acceptedAt,
|
|
1001
|
+
clientRequestId: input.clientRequestId,
|
|
1002
|
+
message: (acceptedMessage
|
|
1003
|
+
? {
|
|
1004
|
+
...acceptedMessage,
|
|
1005
|
+
attachments: boundAttachments
|
|
1006
|
+
}
|
|
1007
|
+
: null) ??
|
|
1008
|
+
createSyntheticUserMessage(session.provider, binding.providerSessionId, input.content, acceptedAt, nextUserSequence, boundAttachments.length > 0
|
|
1009
|
+
? boundAttachments
|
|
1010
|
+
: resolvedAttachments.messageAttachments)
|
|
1011
|
+
};
|
|
847
1012
|
}
|
|
848
|
-
|
|
849
|
-
|
|
1013
|
+
catch (error) {
|
|
1014
|
+
this.failPendingSendDebugTrace(debugTrace, error);
|
|
1015
|
+
throw error;
|
|
850
1016
|
}
|
|
851
|
-
const binding = this.sessionHistoryService.getBindingOrThrow(input.sessionId);
|
|
852
|
-
const acceptedMessage = await this.findAcceptedUserMessage(input.sessionId, this.sessionMessageAttachmentService.buildAcceptedContentCandidates(input.content, providerPrompt), requestStartedAt);
|
|
853
|
-
const acceptedAt = acceptedMessage?.timestamp ?? nowIso();
|
|
854
|
-
const boundAttachments = this.sessionMessageAttachmentService.bindClientRequestToMessage(input.sessionId, input.clientRequestId, acceptedMessage?.messageId ?? null);
|
|
855
|
-
return {
|
|
856
|
-
sessionId: input.sessionId,
|
|
857
|
-
provider: session.provider,
|
|
858
|
-
providerSessionId: binding.providerSessionId,
|
|
859
|
-
acceptedAt,
|
|
860
|
-
clientRequestId: input.clientRequestId,
|
|
861
|
-
message: (acceptedMessage
|
|
862
|
-
? {
|
|
863
|
-
...acceptedMessage,
|
|
864
|
-
attachments: boundAttachments
|
|
865
|
-
}
|
|
866
|
-
: null) ??
|
|
867
|
-
createSyntheticUserMessage(session.provider, binding.providerSessionId, input.content, acceptedAt, Math.max(session.messageCount + 1, 1), boundAttachments.length > 0
|
|
868
|
-
? boundAttachments
|
|
869
|
-
: resolvedAttachments.messageAttachments)
|
|
870
|
-
};
|
|
871
1017
|
}
|
|
872
1018
|
async dispatchNextQueuedMessage(sessionId) {
|
|
873
1019
|
if (this.queueDispatchSessions.has(sessionId)) {
|
|
@@ -919,7 +1065,7 @@ export class SessionLiveRuntimeService {
|
|
|
919
1065
|
this.sessionSendQueueRepository.delete(nextQueueItem.id);
|
|
920
1066
|
}
|
|
921
1067
|
catch (error) {
|
|
922
|
-
if (
|
|
1068
|
+
if (isQueueDispatchRetryableError(error)) {
|
|
923
1069
|
this.sessionSendQueueRepository.markQueued(nextQueueItem.id, nowIso());
|
|
924
1070
|
this.scheduleQueueRetry(sessionId);
|
|
925
1071
|
return;
|
|
@@ -1053,6 +1199,7 @@ export class SessionLiveRuntimeService {
|
|
|
1053
1199
|
};
|
|
1054
1200
|
}
|
|
1055
1201
|
async persistRuntimeEvent(sessionId, workspaceId, userId, event) {
|
|
1202
|
+
this.observePendingSendDebugTraceEvent(sessionId, event);
|
|
1056
1203
|
this.sessionHistoryService.persistSessionBinding(sessionId, workspaceId, {
|
|
1057
1204
|
provider: event.provider,
|
|
1058
1205
|
providerSessionId: event.providerSessionId,
|
|
@@ -1152,9 +1299,151 @@ export class SessionLiveRuntimeService {
|
|
|
1152
1299
|
});
|
|
1153
1300
|
await this.maybeEmitRuntimeHistoryFallback(sessionId, event);
|
|
1154
1301
|
if (isTerminalRuntimeEventStatus(event.status)) {
|
|
1302
|
+
if (!isTerminalSessionRunningState(currentRunningState)) {
|
|
1303
|
+
await this.emitTerminalStateEvent({
|
|
1304
|
+
sessionId,
|
|
1305
|
+
status: event.status,
|
|
1306
|
+
timestamp: event.timestamp,
|
|
1307
|
+
detail: event.detail ?? null,
|
|
1308
|
+
source: "runtime"
|
|
1309
|
+
});
|
|
1310
|
+
}
|
|
1155
1311
|
void this.dispatchNextQueuedMessage(sessionId);
|
|
1156
1312
|
}
|
|
1157
1313
|
}
|
|
1314
|
+
async emitTerminalStateEvent(event) {
|
|
1315
|
+
for (const listener of this.terminalStateListeners) {
|
|
1316
|
+
await listener(event);
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
beginPendingSendDebugTrace(input) {
|
|
1320
|
+
if (!isPerfDebugEnabled()) {
|
|
1321
|
+
return null;
|
|
1322
|
+
}
|
|
1323
|
+
const trace = {
|
|
1324
|
+
...input,
|
|
1325
|
+
startedAtMs: performance.now(),
|
|
1326
|
+
responseReadyAtMs: null,
|
|
1327
|
+
firstRuntimeEventAtMs: null
|
|
1328
|
+
};
|
|
1329
|
+
const queue = this.pendingSendDebugTracesBySessionId.get(input.sessionId) ?? [];
|
|
1330
|
+
queue.push(trace);
|
|
1331
|
+
this.pendingSendDebugTracesBySessionId.set(input.sessionId, queue);
|
|
1332
|
+
logPerformance(`session_send.${trace.mode}.begin`, 0, this.buildSendDebugDetail(trace), {
|
|
1333
|
+
force: true,
|
|
1334
|
+
thresholdMs: 0
|
|
1335
|
+
});
|
|
1336
|
+
return trace;
|
|
1337
|
+
}
|
|
1338
|
+
logSendDebugStep(trace, step, startedAtMs, detail = {}) {
|
|
1339
|
+
if (!trace) {
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
logPerformance(`session_send.${trace.mode}.${step}`, performance.now() - startedAtMs, {
|
|
1343
|
+
...this.buildSendDebugDetail(trace),
|
|
1344
|
+
...detail
|
|
1345
|
+
}, {
|
|
1346
|
+
force: true,
|
|
1347
|
+
thresholdMs: 0
|
|
1348
|
+
});
|
|
1349
|
+
}
|
|
1350
|
+
markSendDebugResponseReady(trace, detail = {}) {
|
|
1351
|
+
if (!trace || trace.responseReadyAtMs !== null) {
|
|
1352
|
+
return;
|
|
1353
|
+
}
|
|
1354
|
+
trace.responseReadyAtMs = performance.now();
|
|
1355
|
+
logPerformance(`session_send.${trace.mode}.response_ready`, trace.responseReadyAtMs - trace.startedAtMs, {
|
|
1356
|
+
...this.buildSendDebugDetail(trace),
|
|
1357
|
+
...detail
|
|
1358
|
+
}, {
|
|
1359
|
+
force: true,
|
|
1360
|
+
thresholdMs: 0
|
|
1361
|
+
});
|
|
1362
|
+
}
|
|
1363
|
+
failPendingSendDebugTrace(trace, error) {
|
|
1364
|
+
if (!trace) {
|
|
1365
|
+
return;
|
|
1366
|
+
}
|
|
1367
|
+
logPerformance(`session_send.${trace.mode}.error`, performance.now() - trace.startedAtMs, {
|
|
1368
|
+
...this.buildSendDebugDetail(trace),
|
|
1369
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1370
|
+
}, {
|
|
1371
|
+
force: true,
|
|
1372
|
+
thresholdMs: 0
|
|
1373
|
+
});
|
|
1374
|
+
this.removePendingSendDebugTrace(trace);
|
|
1375
|
+
}
|
|
1376
|
+
observePendingSendDebugTraceEvent(sessionId, event) {
|
|
1377
|
+
const trace = this.peekPendingSendDebugTrace(sessionId);
|
|
1378
|
+
if (!trace) {
|
|
1379
|
+
return;
|
|
1380
|
+
}
|
|
1381
|
+
const nowMs = performance.now();
|
|
1382
|
+
if (trace.firstRuntimeEventAtMs === null) {
|
|
1383
|
+
trace.firstRuntimeEventAtMs = nowMs;
|
|
1384
|
+
logPerformance(`session_send.${trace.mode}.first_runtime_event`, trace.firstRuntimeEventAtMs - trace.startedAtMs, {
|
|
1385
|
+
...this.buildSendDebugDetail(trace),
|
|
1386
|
+
eventType: event.type,
|
|
1387
|
+
status: event.status,
|
|
1388
|
+
role: event.type === "message" ? event.message.role : null,
|
|
1389
|
+
kind: event.type === "message" ? event.message.kind : null,
|
|
1390
|
+
responseReady: trace.responseReadyAtMs !== null
|
|
1391
|
+
}, {
|
|
1392
|
+
force: true,
|
|
1393
|
+
thresholdMs: 0
|
|
1394
|
+
});
|
|
1395
|
+
}
|
|
1396
|
+
if (event.type === "message" && event.message.role === "assistant") {
|
|
1397
|
+
logPerformance(`session_send.${trace.mode}.first_assistant_message`, nowMs - trace.startedAtMs, {
|
|
1398
|
+
...this.buildSendDebugDetail(trace),
|
|
1399
|
+
kind: event.message.kind,
|
|
1400
|
+
contentLength: event.message.content.length,
|
|
1401
|
+
responseToAssistantMs: trace.responseReadyAtMs === null ? null : nowMs - trace.responseReadyAtMs
|
|
1402
|
+
}, {
|
|
1403
|
+
force: true,
|
|
1404
|
+
thresholdMs: 0
|
|
1405
|
+
});
|
|
1406
|
+
this.removePendingSendDebugTrace(trace);
|
|
1407
|
+
return;
|
|
1408
|
+
}
|
|
1409
|
+
if (event.type === "error" ||
|
|
1410
|
+
(event.type !== "message" && isTerminalRuntimeEventStatus(event.status))) {
|
|
1411
|
+
logPerformance(`session_send.${trace.mode}.completed_without_assistant`, nowMs - trace.startedAtMs, {
|
|
1412
|
+
...this.buildSendDebugDetail(trace),
|
|
1413
|
+
eventType: event.type,
|
|
1414
|
+
status: event.status,
|
|
1415
|
+
detail: event.detail
|
|
1416
|
+
}, {
|
|
1417
|
+
force: true,
|
|
1418
|
+
thresholdMs: 0
|
|
1419
|
+
});
|
|
1420
|
+
this.removePendingSendDebugTrace(trace);
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
peekPendingSendDebugTrace(sessionId) {
|
|
1424
|
+
const queue = this.pendingSendDebugTracesBySessionId.get(sessionId);
|
|
1425
|
+
return queue && queue.length > 0 ? queue[0] : null;
|
|
1426
|
+
}
|
|
1427
|
+
removePendingSendDebugTrace(trace) {
|
|
1428
|
+
const queue = this.pendingSendDebugTracesBySessionId.get(trace.sessionId);
|
|
1429
|
+
if (!queue || queue.length === 0) {
|
|
1430
|
+
return;
|
|
1431
|
+
}
|
|
1432
|
+
const nextQueue = queue.filter((item) => item !== trace);
|
|
1433
|
+
if (nextQueue.length === 0) {
|
|
1434
|
+
this.pendingSendDebugTracesBySessionId.delete(trace.sessionId);
|
|
1435
|
+
return;
|
|
1436
|
+
}
|
|
1437
|
+
this.pendingSendDebugTracesBySessionId.set(trace.sessionId, nextQueue);
|
|
1438
|
+
}
|
|
1439
|
+
buildSendDebugDetail(trace) {
|
|
1440
|
+
return {
|
|
1441
|
+
sessionId: trace.sessionId,
|
|
1442
|
+
workspaceId: trace.workspaceId,
|
|
1443
|
+
provider: trace.provider,
|
|
1444
|
+
clientRequestId: trace.clientRequestId
|
|
1445
|
+
};
|
|
1446
|
+
}
|
|
1158
1447
|
async findAcceptedUserMessage(sessionId, content, minTimestamp) {
|
|
1159
1448
|
try {
|
|
1160
1449
|
return await withTimeout(this.sessionHistoryService.findLatestUserMessage(sessionId, content, 12, minTimestamp), 1200);
|
|
@@ -1163,6 +1452,36 @@ export class SessionLiveRuntimeService {
|
|
|
1163
1452
|
return null;
|
|
1164
1453
|
}
|
|
1165
1454
|
}
|
|
1455
|
+
async resolveNextUserSequence(sessionId, messageCount) {
|
|
1456
|
+
let maxSequence = Math.max(messageCount, 0);
|
|
1457
|
+
const envelope = await Promise.resolve(this.sessionHistoryService.readRecentHistoryEnvelope(sessionId, 10)).catch(() => {
|
|
1458
|
+
return null;
|
|
1459
|
+
});
|
|
1460
|
+
for (const message of envelope?.messages ?? []) {
|
|
1461
|
+
if (Number.isFinite(message.sequence) && message.sequence > maxSequence) {
|
|
1462
|
+
maxSequence = message.sequence;
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
return Math.max(maxSequence + 1, 1);
|
|
1466
|
+
}
|
|
1467
|
+
async waitForResolvedStartBinding(sessionId, workspaceId, provider, handle) {
|
|
1468
|
+
if (provider !== "gemini" && provider !== "kimi") {
|
|
1469
|
+
return;
|
|
1470
|
+
}
|
|
1471
|
+
const startedAt = Date.now();
|
|
1472
|
+
while (Date.now() - startedAt < RUNTIME_START_BINDING_WAIT_TIMEOUT_MS) {
|
|
1473
|
+
const snapshot = handle.getSnapshot();
|
|
1474
|
+
if (hasResolvedRuntimeBinding(snapshot.providerSessionId, snapshot.rawStoreRef)) {
|
|
1475
|
+
this.sessionHistoryService.persistSessionBinding(sessionId, workspaceId, {
|
|
1476
|
+
provider: snapshot.provider,
|
|
1477
|
+
providerSessionId: snapshot.providerSessionId,
|
|
1478
|
+
rawStoreRef: snapshot.rawStoreRef
|
|
1479
|
+
});
|
|
1480
|
+
return;
|
|
1481
|
+
}
|
|
1482
|
+
await waitForRuntimeBindingPoll();
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1166
1485
|
persistMessageAttachments(sessionId, clientRequestId, attachments) {
|
|
1167
1486
|
if (!clientRequestId || attachments.length === 0) {
|
|
1168
1487
|
return {
|
|
@@ -1176,12 +1495,12 @@ export class SessionLiveRuntimeService {
|
|
|
1176
1495
|
attachments
|
|
1177
1496
|
});
|
|
1178
1497
|
}
|
|
1179
|
-
mapRuntimeEventToEnvelope(sessionId, event) {
|
|
1498
|
+
mapRuntimeEventToEnvelope(sessionId, event, originSessionId = sessionId) {
|
|
1180
1499
|
if (event.type === "message") {
|
|
1181
1500
|
return {
|
|
1182
1501
|
type: "session.runtime_message",
|
|
1183
1502
|
sessionId,
|
|
1184
|
-
message: event.message,
|
|
1503
|
+
message: this.sessionHistoryService.resolveMessageOrigin(originSessionId, event.message),
|
|
1185
1504
|
source: "runtime"
|
|
1186
1505
|
};
|
|
1187
1506
|
}
|
|
@@ -1465,12 +1784,25 @@ function isTerminalRuntimeEventStatus(status) {
|
|
|
1465
1784
|
function isPendingSessionRunningState(state) {
|
|
1466
1785
|
return state === "starting" || state === "running";
|
|
1467
1786
|
}
|
|
1468
|
-
function
|
|
1787
|
+
function isQueueDispatchRetryableError(error) {
|
|
1469
1788
|
if (error instanceof AppError) {
|
|
1470
|
-
|
|
1789
|
+
if (error.errorCode === "ACTIVE_RUN_EXISTS"
|
|
1790
|
+
|| error.errorCode === "SESSION_NOT_RUNNING"
|
|
1791
|
+
|| error.errorCode === "IN_RUN_INPUT_NOT_SUPPORTED"
|
|
1792
|
+
|| error.errorCode === "SESSION_EXTERNAL_RUN_ACTIVE"
|
|
1793
|
+
|| error.errorCode === "PROVIDER_RUNTIME_UNAVAILABLE"
|
|
1794
|
+
|| error.errorCode === "PROVIDER_RUNTIME_TIMEOUT") {
|
|
1795
|
+
return true;
|
|
1796
|
+
}
|
|
1797
|
+
return error.statusCode >= 500;
|
|
1471
1798
|
}
|
|
1472
1799
|
if (error instanceof Error) {
|
|
1473
|
-
return error.message === "ACTIVE_RUN_EXISTS"
|
|
1800
|
+
return (error.message === "ACTIVE_RUN_EXISTS"
|
|
1801
|
+
|| error.message === "SESSION_NOT_RUNNING"
|
|
1802
|
+
|| error.message === "IN_RUN_INPUT_NOT_SUPPORTED"
|
|
1803
|
+
|| error.message === "SESSION_EXTERNAL_RUN_ACTIVE"
|
|
1804
|
+
|| error.message === "SERVER_UNAVAILABLE"
|
|
1805
|
+
|| error.message === "SERVER_TIMEOUT");
|
|
1474
1806
|
}
|
|
1475
1807
|
return false;
|
|
1476
1808
|
}
|
|
@@ -1493,6 +1825,32 @@ function mapQueueItemRecordToView(record) {
|
|
|
1493
1825
|
function isTerminalSessionRunningState(state) {
|
|
1494
1826
|
return state === "completed" || state === "interrupted" || state === "failed";
|
|
1495
1827
|
}
|
|
1828
|
+
function hasResolvedRuntimeBinding(providerSessionId, rawStoreRef) {
|
|
1829
|
+
if (!providerSessionId?.trim() || !rawStoreRef?.trim()) {
|
|
1830
|
+
return false;
|
|
1831
|
+
}
|
|
1832
|
+
return !providerSessionId.trim().toLowerCase().startsWith("pending://")
|
|
1833
|
+
&& !rawStoreRef.trim().toLowerCase().startsWith("pending://");
|
|
1834
|
+
}
|
|
1835
|
+
function waitForRuntimeBindingPoll() {
|
|
1836
|
+
return new Promise((resolve) => {
|
|
1837
|
+
setTimeout(resolve, START_BINDING_POLL_INTERVAL_MS);
|
|
1838
|
+
});
|
|
1839
|
+
}
|
|
1840
|
+
function isGeminiPendingRuntimeAliasBinding(value, targetSessionId) {
|
|
1841
|
+
return value.trim().toLowerCase() === `pending://gemini/${targetSessionId.trim().toLowerCase()}`;
|
|
1842
|
+
}
|
|
1843
|
+
function shouldAwaitAcceptedUserMessage(provider) {
|
|
1844
|
+
return provider !== "gemini";
|
|
1845
|
+
}
|
|
1846
|
+
function shouldAwaitStartBindingBeforeAcceptedUserLookup(provider) {
|
|
1847
|
+
return provider === "kimi";
|
|
1848
|
+
}
|
|
1849
|
+
function waitForAcceptedUserLookupWindow() {
|
|
1850
|
+
return new Promise((resolve) => {
|
|
1851
|
+
setTimeout(resolve, 1200);
|
|
1852
|
+
});
|
|
1853
|
+
}
|
|
1496
1854
|
function createProviderRuntimeAdapters(config, options = {}) {
|
|
1497
1855
|
const claudeHookBridgeConfig = buildClaudeHookBridgeConfig(config);
|
|
1498
1856
|
const claudeAdapter = process.env.VITEST
|
|
@@ -1518,7 +1876,9 @@ function createProviderRuntimeAdapters(config, options = {}) {
|
|
|
1518
1876
|
}
|
|
1519
1877
|
const codexTransportHelper = process.env.VITEST
|
|
1520
1878
|
? null
|
|
1521
|
-
: new CodexAppServerHelperClient(config.codexCliPath
|
|
1879
|
+
: new CodexAppServerHelperClient(config.codexCliPath, {
|
|
1880
|
+
homeDir: config.codexHomeDir
|
|
1881
|
+
});
|
|
1522
1882
|
if (codexTransportHelper) {
|
|
1523
1883
|
disposables.push(codexTransportHelper);
|
|
1524
1884
|
}
|
|
@@ -1531,6 +1891,14 @@ function createProviderRuntimeAdapters(config, options = {}) {
|
|
|
1531
1891
|
transportFactory: codexTransportHelper?.createTransport.bind(codexTransportHelper),
|
|
1532
1892
|
handleServerRequest: options.handleCodexServerRequest
|
|
1533
1893
|
}),
|
|
1894
|
+
new GeminiRuntimeAdapter({
|
|
1895
|
+
homeDir: config.geminiHomeDir,
|
|
1896
|
+
commandPath: config.geminiCliPath
|
|
1897
|
+
}),
|
|
1898
|
+
new KimiRuntimeAdapter({
|
|
1899
|
+
homeDir: config.kimiHomeDir,
|
|
1900
|
+
commandPath: config.kimiCliPath
|
|
1901
|
+
}),
|
|
1534
1902
|
new OpenCodeRuntimeAdapter({
|
|
1535
1903
|
baseUrl: config.opencodeBaseUrl,
|
|
1536
1904
|
baseUrlResolver: config.opencodeBaseUrlResolver?.resolve.bind(config.opencodeBaseUrlResolver)
|