@jingyi0605/codingns 0.1.4 → 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/dist/public/assets/{TerminalPage-4ulgBhv9.js → TerminalPage-4p6EBqrR.js} +1 -1
- 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 +6 -0
- package/dist/server/config/env.js +145 -0
- 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/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/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/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/server/create-server.d.ts +61 -0
- package/dist/server/server/create-server.js +148 -4
- 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-C5lu52cQ.css +0 -1
- package/dist/public/assets/index-WpdUo_Vs.js +0 -108
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
2
|
-
import { CapabilityService, ClaudeCodeAdapter, CodexAdapter, OpenCodeAdapter, ProviderRegistry, SessionSyncService } from "@codingns/session-sync-core";
|
|
2
|
+
import { CapabilityService, ClaudeCodeAdapter, CodexAdapter, GeminiAdapter, KimiAdapter, OpenCodeAdapter, ProviderRegistry, SessionSyncService } from "@codingns/session-sync-core";
|
|
3
3
|
import { AppError } from "../../shared/errors/app-error.js";
|
|
4
|
+
import { hashContent } from "../../shared/utils/hash.js";
|
|
4
5
|
import { createId } from "../../shared/utils/id.js";
|
|
5
6
|
import { logPerformance } from "../../shared/utils/perf-log.js";
|
|
6
7
|
import { nowIso } from "../../shared/utils/time.js";
|
|
@@ -10,6 +11,14 @@ import { mapSessionProviderError } from "./session-provider-error-mapper.js";
|
|
|
10
11
|
import { enrichClaudeCapabilities } from "../provider/claude-model-options.js";
|
|
11
12
|
import { CodexModelOptionsService, enrichCodexCapabilities } from "../provider/codex-model-options.js";
|
|
12
13
|
import { OpenCodeModelOptionsService, enrichOpenCodeCapabilities } from "../provider/opencode-model-options.js";
|
|
14
|
+
const SESSION_START_DEFERRED_PROVIDERS = new Set([
|
|
15
|
+
"codex",
|
|
16
|
+
"claude-code",
|
|
17
|
+
"opencode",
|
|
18
|
+
"gemini",
|
|
19
|
+
"kimi"
|
|
20
|
+
]);
|
|
21
|
+
const MUTABLE_HISTORY_TAIL_REFRESH_INTERVAL_MS = 1_200;
|
|
13
22
|
export class SessionHistoryService {
|
|
14
23
|
db;
|
|
15
24
|
workspaceRepository;
|
|
@@ -19,6 +28,7 @@ export class SessionHistoryService {
|
|
|
19
28
|
sessionMessageAttachmentService;
|
|
20
29
|
sessionStateRepository;
|
|
21
30
|
sessionStatusSnapshotRepository;
|
|
31
|
+
sessionMessageOriginRepository;
|
|
22
32
|
providerRegistry;
|
|
23
33
|
sessionSyncService;
|
|
24
34
|
capabilityService;
|
|
@@ -30,7 +40,7 @@ export class SessionHistoryService {
|
|
|
30
40
|
workspaceDiscoveryInflight = new Map();
|
|
31
41
|
workspaceStateRefreshInflight = new Map();
|
|
32
42
|
workspaceSessionRelations = new Map();
|
|
33
|
-
constructor(db, workspaceRepository, sessionBindingRepository, sessionChangedFileService, sessionIndexRepository, sessionMessageAttachmentService, sessionStateRepository, sessionStatusSnapshotRepository, config, sessionActivityAuthorityService = new SessionActivityAuthorityService()) {
|
|
43
|
+
constructor(db, workspaceRepository, sessionBindingRepository, sessionChangedFileService, sessionIndexRepository, sessionMessageAttachmentService, sessionStateRepository, sessionStatusSnapshotRepository, config, sessionActivityAuthorityService = new SessionActivityAuthorityService(), sessionMessageOriginRepository = null) {
|
|
34
44
|
this.db = db;
|
|
35
45
|
this.workspaceRepository = workspaceRepository;
|
|
36
46
|
this.sessionBindingRepository = sessionBindingRepository;
|
|
@@ -39,11 +49,20 @@ export class SessionHistoryService {
|
|
|
39
49
|
this.sessionMessageAttachmentService = sessionMessageAttachmentService;
|
|
40
50
|
this.sessionStateRepository = sessionStateRepository;
|
|
41
51
|
this.sessionStatusSnapshotRepository = sessionStatusSnapshotRepository;
|
|
52
|
+
this.sessionMessageOriginRepository = sessionMessageOriginRepository;
|
|
42
53
|
this.sessionActivityAuthorityService = sessionActivityAuthorityService;
|
|
43
54
|
this.claudeCodeHomeDir = config.claudeCodeHomeDir;
|
|
44
55
|
this.providerRegistry = new ProviderRegistry([
|
|
45
56
|
new ClaudeCodeAdapter({ homeDir: config.claudeCodeHomeDir }),
|
|
46
57
|
new CodexAdapter({ homeDir: config.codexHomeDir }),
|
|
58
|
+
new GeminiAdapter({
|
|
59
|
+
homeDir: config.geminiHomeDir,
|
|
60
|
+
commandPath: config.geminiCliPath
|
|
61
|
+
}),
|
|
62
|
+
new KimiAdapter({
|
|
63
|
+
homeDir: config.kimiHomeDir,
|
|
64
|
+
defaultModel: config.kimiDefaultModel
|
|
65
|
+
}),
|
|
47
66
|
new OpenCodeAdapter({
|
|
48
67
|
baseUrl: config.opencodeBaseUrl,
|
|
49
68
|
baseUrlResolver: config.opencodeBaseUrlResolver?.resolve.bind(config.opencodeBaseUrlResolver),
|
|
@@ -98,15 +117,16 @@ export class SessionHistoryService {
|
|
|
98
117
|
}
|
|
99
118
|
async readSessionHistory(sessionId, cursor, limit, direction = "forward", userId) {
|
|
100
119
|
const startedAt = Date.now();
|
|
101
|
-
const
|
|
102
|
-
const
|
|
120
|
+
const resolvedSessionId = this.resolveCanonicalSessionId(sessionId, userId);
|
|
121
|
+
const binding = this.getBindingOrThrow(resolvedSessionId);
|
|
122
|
+
const current = this.sessionStatusSnapshotRepository.findBySessionId(resolvedSessionId);
|
|
103
123
|
const safeLimit = clampLimit(limit);
|
|
104
124
|
const knownTotalMessageCount = direction === "backward" && cursor === null
|
|
105
|
-
? this.sessionIndexRepository.findIndexRecordBySessionId(
|
|
125
|
+
? this.sessionIndexRepository.findIndexRecordBySessionId(resolvedSessionId)?.messageCount ?? null
|
|
106
126
|
: null;
|
|
107
127
|
let readDurationMs = 0;
|
|
108
128
|
let refreshStateDurationMs = 0;
|
|
109
|
-
this.upsertSnapshot(
|
|
129
|
+
this.upsertSnapshot(resolvedSessionId, {
|
|
110
130
|
syncStatus: "syncing",
|
|
111
131
|
syncCursor: current?.syncCursor ?? cursor,
|
|
112
132
|
lastSyncAt: current?.lastSyncAt ?? null,
|
|
@@ -116,9 +136,9 @@ export class SessionHistoryService {
|
|
|
116
136
|
});
|
|
117
137
|
try {
|
|
118
138
|
const readStartedAt = Date.now();
|
|
119
|
-
const page = await this.readPage(
|
|
139
|
+
const page = await this.readPage(resolvedSessionId, binding.provider, binding.providerSessionId, binding.rawStoreRef, cursor, safeLimit, direction, knownTotalMessageCount);
|
|
120
140
|
readDurationMs = Date.now() - readStartedAt;
|
|
121
|
-
this.upsertSnapshot(
|
|
141
|
+
this.upsertSnapshot(resolvedSessionId, {
|
|
122
142
|
syncStatus: "idle",
|
|
123
143
|
syncCursor: direction === "backward" && cursor !== null
|
|
124
144
|
? current?.syncCursor ?? page.cursor
|
|
@@ -129,7 +149,8 @@ export class SessionHistoryService {
|
|
|
129
149
|
resumedAt: current?.resumedAt ?? null
|
|
130
150
|
});
|
|
131
151
|
logPerformance("session.read_history", Date.now() - startedAt, {
|
|
132
|
-
sessionId,
|
|
152
|
+
sessionId: resolvedSessionId,
|
|
153
|
+
requestedSessionId: sessionId,
|
|
133
154
|
provider: binding.provider,
|
|
134
155
|
direction,
|
|
135
156
|
limit: safeLimit,
|
|
@@ -145,7 +166,8 @@ export class SessionHistoryService {
|
|
|
145
166
|
}
|
|
146
167
|
catch (error) {
|
|
147
168
|
logPerformance("session.read_history.failed", Date.now() - startedAt, {
|
|
148
|
-
sessionId,
|
|
169
|
+
sessionId: resolvedSessionId,
|
|
170
|
+
requestedSessionId: sessionId,
|
|
149
171
|
provider: binding.provider,
|
|
150
172
|
direction,
|
|
151
173
|
limit: safeLimit,
|
|
@@ -157,10 +179,17 @@ export class SessionHistoryService {
|
|
|
157
179
|
thresholdMs: 0,
|
|
158
180
|
force: true
|
|
159
181
|
});
|
|
160
|
-
this.markSessionError(
|
|
182
|
+
this.markSessionError(resolvedSessionId, "PROVIDER_READ_FAILED", error);
|
|
161
183
|
throw mapSessionProviderError(error);
|
|
162
184
|
}
|
|
163
185
|
}
|
|
186
|
+
resolveMessageOrigin(sessionId, message) {
|
|
187
|
+
return this.resolveMessageOrigins(sessionId, [message])[0] ?? {
|
|
188
|
+
...message,
|
|
189
|
+
origin: null,
|
|
190
|
+
originRef: null
|
|
191
|
+
};
|
|
192
|
+
}
|
|
164
193
|
async findLatestUserMessage(sessionId, content, maxAttempts = 12, minTimestamp = null) {
|
|
165
194
|
const binding = this.getBindingOrThrow(sessionId);
|
|
166
195
|
const acceptedContents = new Set((Array.isArray(content) ? content : [content]).filter((value) => value.trim().length > 0));
|
|
@@ -171,7 +200,7 @@ export class SessionHistoryService {
|
|
|
171
200
|
.reverse()
|
|
172
201
|
.find((message) => message.role === "user" &&
|
|
173
202
|
acceptedContents.has(message.content) &&
|
|
174
|
-
|
|
203
|
+
isAcceptedUserMessageTimestamp(binding.provider, message.timestamp, minTimestamp));
|
|
175
204
|
if (matched) {
|
|
176
205
|
return matched;
|
|
177
206
|
}
|
|
@@ -209,7 +238,9 @@ export class SessionHistoryService {
|
|
|
209
238
|
return this.sessionChangedFileService.listBySessionId(sessionId);
|
|
210
239
|
}
|
|
211
240
|
listWorkspaceSessions(workspaceId, userId) {
|
|
212
|
-
return this.enrichSessionItems(workspaceId, this.sessionIndexRepository
|
|
241
|
+
return this.enrichSessionItems(workspaceId, this.sessionIndexRepository
|
|
242
|
+
.listByWorkspace(workspaceId, userId)
|
|
243
|
+
.filter((item) => !this.isPendingSessionAlias(item)));
|
|
213
244
|
}
|
|
214
245
|
getProviderCapabilitiesSnapshot(provider) {
|
|
215
246
|
try {
|
|
@@ -281,7 +312,7 @@ export class SessionHistoryService {
|
|
|
281
312
|
}
|
|
282
313
|
async startSession(input) {
|
|
283
314
|
const workspace = this.getWorkspaceOrThrow(input.workspaceId);
|
|
284
|
-
if (
|
|
315
|
+
if (SESSION_START_DEFERRED_PROVIDERS.has(input.provider)) {
|
|
285
316
|
throw new AppError({
|
|
286
317
|
statusCode: 409,
|
|
287
318
|
errorCode: "SESSION_START_DEFERRED",
|
|
@@ -385,7 +416,7 @@ export class SessionHistoryService {
|
|
|
385
416
|
};
|
|
386
417
|
}
|
|
387
418
|
async subscribeSession(sessionId, cursor, limit, onEnvelope) {
|
|
388
|
-
const
|
|
419
|
+
const deliveredMessages = createDeliveredHistoryMessageState();
|
|
389
420
|
const safeLimit = clampLimit(limit);
|
|
390
421
|
let currentCursor = cursor;
|
|
391
422
|
const current = this.sessionStatusSnapshotRepository.findBySessionId(sessionId);
|
|
@@ -401,10 +432,10 @@ export class SessionHistoryService {
|
|
|
401
432
|
});
|
|
402
433
|
try {
|
|
403
434
|
if (currentCursor === null) {
|
|
404
|
-
currentCursor = await this.pullRecentSessionHistory(sessionId, safeLimit,
|
|
435
|
+
currentCursor = await this.pullRecentSessionHistory(sessionId, safeLimit, deliveredMessages, onEnvelope, "session.backfill");
|
|
405
436
|
}
|
|
406
437
|
else {
|
|
407
|
-
await this.pullSessionHistory(sessionId, currentCursor, safeLimit,
|
|
438
|
+
await this.pullSessionHistory(sessionId, currentCursor, safeLimit, deliveredMessages, onEnvelope, "session.backfill").then((nextCursor) => {
|
|
408
439
|
currentCursor = nextCursor;
|
|
409
440
|
});
|
|
410
441
|
}
|
|
@@ -418,7 +449,7 @@ export class SessionHistoryService {
|
|
|
418
449
|
return;
|
|
419
450
|
}
|
|
420
451
|
polling = true;
|
|
421
|
-
void this.pullSessionHistory(sessionId, currentCursor, safeLimit,
|
|
452
|
+
void this.pullSessionHistory(sessionId, currentCursor, safeLimit, deliveredMessages, onEnvelope, "session.delta", () => closed)
|
|
422
453
|
.then((nextCursor) => {
|
|
423
454
|
currentCursor = nextCursor;
|
|
424
455
|
})
|
|
@@ -567,7 +598,7 @@ export class SessionHistoryService {
|
|
|
567
598
|
detail: "session 不存在"
|
|
568
599
|
});
|
|
569
600
|
}
|
|
570
|
-
return binding;
|
|
601
|
+
return this.resolvePendingSessionAliasBinding(binding) ?? binding;
|
|
571
602
|
}
|
|
572
603
|
persistSessionBinding(sessionId, workspaceId, snapshot) {
|
|
573
604
|
if (!snapshot.providerSessionId || !snapshot.rawStoreRef) {
|
|
@@ -643,7 +674,8 @@ export class SessionHistoryService {
|
|
|
643
674
|
continue;
|
|
644
675
|
}
|
|
645
676
|
const pendingDuplicate = exactExisting
|
|
646
|
-
?? findClaudePendingDiscoveryDuplicate(session, existingWorkspaceSessions, claimedPendingSessionIds)
|
|
677
|
+
?? findClaudePendingDiscoveryDuplicate(session, existingWorkspaceSessions, claimedPendingSessionIds)
|
|
678
|
+
?? findKimiRuntimeDiscoveryDuplicate(session, existingWorkspaceSessions, claimedPendingSessionIds);
|
|
647
679
|
const existing = exactExisting ?? (pendingDuplicate
|
|
648
680
|
? this.sessionBindingRepository.findBySessionId(pendingDuplicate.sessionId)
|
|
649
681
|
: null);
|
|
@@ -788,7 +820,8 @@ export class SessionHistoryService {
|
|
|
788
820
|
: this.sessionSyncService.readHistory(provider, providerSessionId, rawStoreRef, cursor, limit, direction);
|
|
789
821
|
return historyTask
|
|
790
822
|
.then((page) => {
|
|
791
|
-
const
|
|
823
|
+
const messagesWithAttachments = this.sessionMessageAttachmentService.enrichMessages(sessionId, page.messages);
|
|
824
|
+
const messages = this.enrichMessagesWithOrigin(sessionId, messagesWithAttachments);
|
|
792
825
|
this.persistSessionChangedFiles(sessionId, messages);
|
|
793
826
|
return {
|
|
794
827
|
...page,
|
|
@@ -807,6 +840,64 @@ export class SessionHistoryService {
|
|
|
807
840
|
throw mapSessionProviderError(error);
|
|
808
841
|
});
|
|
809
842
|
}
|
|
843
|
+
enrichMessagesWithOrigin(sessionId, messages) {
|
|
844
|
+
return this.resolveMessageOrigins(sessionId, messages);
|
|
845
|
+
}
|
|
846
|
+
resolveMessageOrigins(sessionId, messages) {
|
|
847
|
+
const originRepository = this.sessionMessageOriginRepository;
|
|
848
|
+
if (!originRepository || messages.length === 0) {
|
|
849
|
+
return messages.map((message) => ({
|
|
850
|
+
...message,
|
|
851
|
+
origin: null,
|
|
852
|
+
originRef: null
|
|
853
|
+
}));
|
|
854
|
+
}
|
|
855
|
+
const messageIds = [...new Set(messages.map((message) => message.messageId).filter(Boolean))];
|
|
856
|
+
const originRows = originRepository.listBySessionAndMessageIds(sessionId, messageIds);
|
|
857
|
+
const originByMessageId = new Map(originRows
|
|
858
|
+
.filter((row) => row.messageId)
|
|
859
|
+
.map((row) => [row.messageId, row]));
|
|
860
|
+
const unresolvedRows = originRepository.listUnresolvedBySessionAndContents(sessionId, [...new Set(messages.map((message) => message.content).filter((content) => content.trim().length > 0))]);
|
|
861
|
+
const unresolvedByContent = new Map();
|
|
862
|
+
for (const row of unresolvedRows) {
|
|
863
|
+
const current = unresolvedByContent.get(row.content) ?? [];
|
|
864
|
+
current.push(row);
|
|
865
|
+
unresolvedByContent.set(row.content, current);
|
|
866
|
+
}
|
|
867
|
+
return messages.map((message) => {
|
|
868
|
+
const resolved = originByMessageId.get(message.messageId) ?? null;
|
|
869
|
+
if (resolved) {
|
|
870
|
+
return {
|
|
871
|
+
...message,
|
|
872
|
+
origin: resolved.origin,
|
|
873
|
+
originRef: resolved.originRef
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
if (message.role !== "user") {
|
|
877
|
+
return {
|
|
878
|
+
...message,
|
|
879
|
+
origin: null,
|
|
880
|
+
originRef: null
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
const candidates = unresolvedByContent.get(message.content) ?? [];
|
|
884
|
+
const matched = candidates.find((row) => isMessageAtOrAfter(message.timestamp, row.createdAt)) ?? null;
|
|
885
|
+
if (!matched) {
|
|
886
|
+
return {
|
|
887
|
+
...message,
|
|
888
|
+
origin: null,
|
|
889
|
+
originRef: null
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
originRepository.resolveMessageId(sessionId, matched.clientRequestId, message.messageId, message.timestamp);
|
|
893
|
+
unresolvedByContent.set(message.content, candidates.filter((candidate) => candidate.clientRequestId !== matched.clientRequestId));
|
|
894
|
+
return {
|
|
895
|
+
...message,
|
|
896
|
+
origin: matched.origin,
|
|
897
|
+
originRef: matched.originRef
|
|
898
|
+
};
|
|
899
|
+
});
|
|
900
|
+
}
|
|
810
901
|
buildWorkspaceSessionRelationMap(sessions, discoveredSessionIds) {
|
|
811
902
|
const relationMap = new Map();
|
|
812
903
|
for (const session of sessions) {
|
|
@@ -863,12 +954,18 @@ export class SessionHistoryService {
|
|
|
863
954
|
const resolution = this.sessionActivityAuthorityService.resolvePersistedSession(nextItem);
|
|
864
955
|
return applySessionActivityResolution(nextItem, resolution);
|
|
865
956
|
}
|
|
866
|
-
async pullSessionHistory(sessionId, cursor, limit,
|
|
957
|
+
async pullSessionHistory(sessionId, cursor, limit, deliveredMessages, onEnvelope, envelopeType, isClosed = () => false) {
|
|
867
958
|
let currentCursor = cursor;
|
|
868
959
|
while (!isClosed()) {
|
|
869
960
|
const binding = this.getBindingOrThrow(sessionId);
|
|
870
961
|
const page = await this.readPage(sessionId, binding.provider, binding.providerSessionId, binding.rawStoreRef, currentCursor, limit);
|
|
871
|
-
await this.publishHistoryEnvelope(sessionId, binding, page,
|
|
962
|
+
await this.publishHistoryEnvelope(sessionId, binding, page, deliveredMessages, onEnvelope, envelopeType);
|
|
963
|
+
if (envelopeType === "session.delta" &&
|
|
964
|
+
shouldRefreshMutableHistoryTail(binding.provider, page, currentCursor, deliveredMessages)) {
|
|
965
|
+
const tailPage = await this.readPage(sessionId, binding.provider, binding.providerSessionId, binding.rawStoreRef, null, Math.max(limit, 20), "backward");
|
|
966
|
+
deliveredMessages.lastMutableTailRefreshAtMs = Date.now();
|
|
967
|
+
await this.publishHistoryEnvelope(sessionId, binding, tailPage, deliveredMessages, onEnvelope, envelopeType);
|
|
968
|
+
}
|
|
872
969
|
currentCursor = page.cursor;
|
|
873
970
|
if (!page.nextCursor) {
|
|
874
971
|
return currentCursor;
|
|
@@ -876,19 +973,21 @@ export class SessionHistoryService {
|
|
|
876
973
|
}
|
|
877
974
|
return currentCursor;
|
|
878
975
|
}
|
|
879
|
-
async pullRecentSessionHistory(sessionId, limit,
|
|
976
|
+
async pullRecentSessionHistory(sessionId, limit, deliveredMessages, onEnvelope, envelopeType) {
|
|
880
977
|
const binding = this.getBindingOrThrow(sessionId);
|
|
881
978
|
const knownTotalMessageCount = this.sessionIndexRepository.findIndexRecordBySessionId(sessionId)?.messageCount ?? null;
|
|
882
979
|
const page = await this.readPage(sessionId, binding.provider, binding.providerSessionId, binding.rawStoreRef, null, limit, "backward", knownTotalMessageCount);
|
|
883
|
-
await this.publishHistoryEnvelope(sessionId, binding, page,
|
|
980
|
+
await this.publishHistoryEnvelope(sessionId, binding, page, deliveredMessages, onEnvelope, envelopeType);
|
|
884
981
|
return page.cursor;
|
|
885
982
|
}
|
|
886
|
-
async publishHistoryEnvelope(sessionId, binding, page,
|
|
983
|
+
async publishHistoryEnvelope(sessionId, binding, page, deliveredMessages, onEnvelope, envelopeType) {
|
|
887
984
|
const messages = page.messages.filter((message) => {
|
|
888
|
-
|
|
985
|
+
const nextSignature = buildDeliveredHistoryMessageSignature(message);
|
|
986
|
+
const previousSignature = deliveredMessages.signaturesByMessageId.get(message.messageId);
|
|
987
|
+
if (previousSignature === nextSignature) {
|
|
889
988
|
return false;
|
|
890
989
|
}
|
|
891
|
-
|
|
990
|
+
rememberDeliveredHistoryMessage(deliveredMessages, message.messageId, nextSignature);
|
|
892
991
|
return true;
|
|
893
992
|
});
|
|
894
993
|
if (messages.length === 0) {
|
|
@@ -980,7 +1079,53 @@ export class SessionHistoryService {
|
|
|
980
1079
|
detail: "session 索引缺失"
|
|
981
1080
|
});
|
|
982
1081
|
}
|
|
983
|
-
|
|
1082
|
+
const aliasTargetSessionId = this.findPendingSessionAliasTargetSessionId(item);
|
|
1083
|
+
if (!aliasTargetSessionId) {
|
|
1084
|
+
return item;
|
|
1085
|
+
}
|
|
1086
|
+
return this.sessionIndexRepository.findBySessionId(aliasTargetSessionId, userId) ?? item;
|
|
1087
|
+
}
|
|
1088
|
+
resolveCanonicalSessionId(sessionId, userId) {
|
|
1089
|
+
if (userId) {
|
|
1090
|
+
const item = this.sessionIndexRepository.findBySessionId(sessionId, userId);
|
|
1091
|
+
const aliasTargetSessionId = this.findPendingSessionAliasTargetSessionId(item);
|
|
1092
|
+
if (aliasTargetSessionId) {
|
|
1093
|
+
return aliasTargetSessionId;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
const binding = this.sessionBindingRepository.findBySessionId(sessionId);
|
|
1097
|
+
return this.findPendingSessionAliasTargetSessionId(binding) ?? sessionId;
|
|
1098
|
+
}
|
|
1099
|
+
isPendingSessionAlias(item) {
|
|
1100
|
+
return Boolean(this.findPendingSessionAliasTargetSessionId(item));
|
|
1101
|
+
}
|
|
1102
|
+
resolvePendingSessionAliasBinding(binding) {
|
|
1103
|
+
const aliasTargetSessionId = this.findPendingSessionAliasTargetSessionId(binding);
|
|
1104
|
+
if (!aliasTargetSessionId) {
|
|
1105
|
+
return null;
|
|
1106
|
+
}
|
|
1107
|
+
return this.sessionBindingRepository.findBySessionId(aliasTargetSessionId);
|
|
1108
|
+
}
|
|
1109
|
+
findPendingSessionAliasTargetSessionId(descriptor) {
|
|
1110
|
+
if (!descriptor || descriptor.provider !== "gemini") {
|
|
1111
|
+
return null;
|
|
1112
|
+
}
|
|
1113
|
+
const aliasTargetSessionId = extractPendingBindingTargetSessionId(descriptor.providerSessionId)
|
|
1114
|
+
?? extractPendingBindingTargetSessionId(descriptor.rawStoreRef);
|
|
1115
|
+
if (!aliasTargetSessionId || aliasTargetSessionId === descriptor.sessionId) {
|
|
1116
|
+
return null;
|
|
1117
|
+
}
|
|
1118
|
+
const targetBinding = this.sessionBindingRepository.findBySessionId(aliasTargetSessionId);
|
|
1119
|
+
if (!targetBinding) {
|
|
1120
|
+
return null;
|
|
1121
|
+
}
|
|
1122
|
+
if (targetBinding.workspaceId !== descriptor.workspaceId
|
|
1123
|
+
|| targetBinding.provider !== descriptor.provider
|
|
1124
|
+
|| isPendingBindingValue(targetBinding.providerSessionId)
|
|
1125
|
+
|| isPendingBindingValue(targetBinding.rawStoreRef)) {
|
|
1126
|
+
return null;
|
|
1127
|
+
}
|
|
1128
|
+
return aliasTargetSessionId;
|
|
984
1129
|
}
|
|
985
1130
|
async refreshRecentSessionStates(sessions, userId) {
|
|
986
1131
|
for (let index = 0; index < sessions.length; index += 1) {
|
|
@@ -1585,12 +1730,20 @@ function isPendingBindingValue(value) {
|
|
|
1585
1730
|
function buildPendingBindingValue(provider, sessionId) {
|
|
1586
1731
|
return `pending://${provider}/${sessionId}`;
|
|
1587
1732
|
}
|
|
1733
|
+
function extractPendingBindingTargetSessionId(value) {
|
|
1734
|
+
if (!isPendingBindingValue(value)) {
|
|
1735
|
+
return null;
|
|
1736
|
+
}
|
|
1737
|
+
const normalizedValue = value.trim();
|
|
1738
|
+
const targetSessionId = normalizedValue.slice(normalizedValue.indexOf("/", "pending://".length) + 1).trim();
|
|
1739
|
+
return targetSessionId || null;
|
|
1740
|
+
}
|
|
1588
1741
|
function isClaudePendingRuntimeRawStoreRef(rawStoreRef) {
|
|
1589
1742
|
const normalizedRawStoreRef = rawStoreRef.replaceAll("\\", "/").toLowerCase();
|
|
1590
1743
|
return normalizedRawStoreRef.includes("/.pending-");
|
|
1591
1744
|
}
|
|
1592
1745
|
function shouldShortCircuitClaudePendingHistory(provider, providerSessionId, rawStoreRef) {
|
|
1593
|
-
if (provider !== "claude-code") {
|
|
1746
|
+
if (provider !== "claude-code" && provider !== "gemini") {
|
|
1594
1747
|
return false;
|
|
1595
1748
|
}
|
|
1596
1749
|
return isPendingBindingValue(providerSessionId) || isPendingBindingValue(rawStoreRef);
|
|
@@ -1639,6 +1792,66 @@ function findClaudePendingDiscoveryDuplicate(session, existingSessions, claimedS
|
|
|
1639
1792
|
});
|
|
1640
1793
|
return activePendingCandidates.length === 1 ? activePendingCandidates[0] : null;
|
|
1641
1794
|
}
|
|
1795
|
+
function findKimiRuntimeDiscoveryDuplicate(session, existingSessions, claimedSessionIds) {
|
|
1796
|
+
if (session.provider !== "kimi" || isPendingBindingValue(session.providerSessionId)) {
|
|
1797
|
+
return null;
|
|
1798
|
+
}
|
|
1799
|
+
const candidates = existingSessions.filter((item) => {
|
|
1800
|
+
if (claimedSessionIds.has(item.sessionId)) {
|
|
1801
|
+
return false;
|
|
1802
|
+
}
|
|
1803
|
+
if (item.provider !== "kimi" || !shouldRecoverKimiRuntimeBinding(item)) {
|
|
1804
|
+
return false;
|
|
1805
|
+
}
|
|
1806
|
+
return isCloseKimiSessionTimestamp(item.lastMessageAt ?? item.createdAt, session.lastMessageAt);
|
|
1807
|
+
});
|
|
1808
|
+
if (candidates.length === 1) {
|
|
1809
|
+
return candidates[0];
|
|
1810
|
+
}
|
|
1811
|
+
const comparableTitle = normalizeKimiComparableTitle(session.title);
|
|
1812
|
+
if (!comparableTitle) {
|
|
1813
|
+
return null;
|
|
1814
|
+
}
|
|
1815
|
+
const titleMatchedCandidates = candidates.filter((item) => normalizeKimiComparableTitle(item.title) === comparableTitle);
|
|
1816
|
+
return titleMatchedCandidates.length === 1
|
|
1817
|
+
? titleMatchedCandidates[0]
|
|
1818
|
+
: null;
|
|
1819
|
+
}
|
|
1820
|
+
function shouldRecoverKimiRuntimeBinding(item) {
|
|
1821
|
+
if (isPendingBindingValue(item.providerSessionId)) {
|
|
1822
|
+
return true;
|
|
1823
|
+
}
|
|
1824
|
+
if (item.messageCount !== 0 || item.activitySource !== "runtime") {
|
|
1825
|
+
return false;
|
|
1826
|
+
}
|
|
1827
|
+
if (item.runningState === "starting") {
|
|
1828
|
+
return true;
|
|
1829
|
+
}
|
|
1830
|
+
if (item.lastErrorCode === "PROVIDER_READ_FAILED") {
|
|
1831
|
+
return true;
|
|
1832
|
+
}
|
|
1833
|
+
return (item.lastErrorDetail ?? "").includes("provider 会话不存在");
|
|
1834
|
+
}
|
|
1835
|
+
function normalizeKimiComparableTitle(title) {
|
|
1836
|
+
const normalized = title.trim().replace(/\s+/g, " ");
|
|
1837
|
+
if (!normalized) {
|
|
1838
|
+
return null;
|
|
1839
|
+
}
|
|
1840
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(normalized)
|
|
1841
|
+
? null
|
|
1842
|
+
: normalized;
|
|
1843
|
+
}
|
|
1844
|
+
function isCloseKimiSessionTimestamp(left, right) {
|
|
1845
|
+
if (!left || !right) {
|
|
1846
|
+
return false;
|
|
1847
|
+
}
|
|
1848
|
+
const leftAt = Date.parse(left);
|
|
1849
|
+
const rightAt = Date.parse(right);
|
|
1850
|
+
if (!Number.isFinite(leftAt) || !Number.isFinite(rightAt)) {
|
|
1851
|
+
return false;
|
|
1852
|
+
}
|
|
1853
|
+
return Math.abs(leftAt - rightAt) <= 2 * 60 * 1_000;
|
|
1854
|
+
}
|
|
1642
1855
|
function normalizeClaudeComparableTitle(title) {
|
|
1643
1856
|
return title?.trim().replace(/\s+/g, " ").toLowerCase() ?? "";
|
|
1644
1857
|
}
|
|
@@ -1670,6 +1883,54 @@ function isMessageAtOrAfter(timestamp, minTimestamp) {
|
|
|
1670
1883
|
}
|
|
1671
1884
|
return messageAt >= minAt;
|
|
1672
1885
|
}
|
|
1886
|
+
function isAcceptedUserMessageTimestamp(provider, timestamp, minTimestamp) {
|
|
1887
|
+
if (provider === "kimi"
|
|
1888
|
+
&& isSyntheticKimiHistoryTimestamp(timestamp)) {
|
|
1889
|
+
return true;
|
|
1890
|
+
}
|
|
1891
|
+
return isMessageAtOrAfter(timestamp, minTimestamp);
|
|
1892
|
+
}
|
|
1893
|
+
function isSyntheticKimiHistoryTimestamp(timestamp) {
|
|
1894
|
+
return timestamp.startsWith("2020-01-01T00:");
|
|
1895
|
+
}
|
|
1896
|
+
function createDeliveredHistoryMessageState() {
|
|
1897
|
+
return {
|
|
1898
|
+
signaturesByMessageId: new Map(),
|
|
1899
|
+
lastMutableTailRefreshAtMs: 0
|
|
1900
|
+
};
|
|
1901
|
+
}
|
|
1902
|
+
function shouldRefreshMutableHistoryTail(provider, page, cursor, deliveredMessages) {
|
|
1903
|
+
if (provider !== "kimi" || cursor === null || page.messages.length > 0) {
|
|
1904
|
+
return false;
|
|
1905
|
+
}
|
|
1906
|
+
return Date.now() - deliveredMessages.lastMutableTailRefreshAtMs >= MUTABLE_HISTORY_TAIL_REFRESH_INTERVAL_MS;
|
|
1907
|
+
}
|
|
1908
|
+
function buildDeliveredHistoryMessageSignature(message) {
|
|
1909
|
+
return hashContent(JSON.stringify({
|
|
1910
|
+
provider: message.provider,
|
|
1911
|
+
providerSessionId: message.providerSessionId,
|
|
1912
|
+
role: message.role,
|
|
1913
|
+
kind: message.kind,
|
|
1914
|
+
content: message.content,
|
|
1915
|
+
toolCall: message.toolCall,
|
|
1916
|
+
attachments: message.attachments ?? [],
|
|
1917
|
+
timestamp: message.timestamp,
|
|
1918
|
+
rawRef: message.rawRef
|
|
1919
|
+
}));
|
|
1920
|
+
}
|
|
1921
|
+
function rememberDeliveredHistoryMessage(state, messageId, signature) {
|
|
1922
|
+
if (state.signaturesByMessageId.has(messageId)) {
|
|
1923
|
+
state.signaturesByMessageId.delete(messageId);
|
|
1924
|
+
}
|
|
1925
|
+
state.signaturesByMessageId.set(messageId, signature);
|
|
1926
|
+
while (state.signaturesByMessageId.size > 2_048) {
|
|
1927
|
+
const oldestMessageId = state.signaturesByMessageId.keys().next().value;
|
|
1928
|
+
if (typeof oldestMessageId !== "string") {
|
|
1929
|
+
break;
|
|
1930
|
+
}
|
|
1931
|
+
state.signaturesByMessageId.delete(oldestMessageId);
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1673
1934
|
function delay(ms) {
|
|
1674
1935
|
return new Promise((resolve) => {
|
|
1675
1936
|
setTimeout(resolve, ms);
|