yepanywhere 0.6.0 → 0.6.2
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/bundled/@yep-anywhere/shared/dist/app-types.d.ts +25 -0
- package/bundled/@yep-anywhere/shared/dist/app-types.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/app-types.js.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/codex-schema/session.d.ts +179 -14
- package/bundled/@yep-anywhere/shared/dist/codex-schema/session.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/codex-schema/session.js +89 -0
- package/bundled/@yep-anywhere/shared/dist/codex-schema/session.js.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/codex-tool-correlation.d.ts +25 -0
- package/bundled/@yep-anywhere/shared/dist/codex-tool-correlation.d.ts.map +1 -0
- package/bundled/@yep-anywhere/shared/dist/codex-tool-correlation.js +52 -0
- package/bundled/@yep-anywhere/shared/dist/codex-tool-correlation.js.map +1 -0
- package/bundled/@yep-anywhere/shared/dist/codex-web-run.d.ts +46 -0
- package/bundled/@yep-anywhere/shared/dist/codex-web-run.d.ts.map +1 -0
- package/bundled/@yep-anywhere/shared/dist/codex-web-run.js +14 -0
- package/bundled/@yep-anywhere/shared/dist/codex-web-run.js.map +1 -0
- package/bundled/@yep-anywhere/shared/dist/git-status.d.ts +29 -6
- package/bundled/@yep-anywhere/shared/dist/git-status.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/git-status.js +1 -6
- package/bundled/@yep-anywhere/shared/dist/git-status.js.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/index.d.ts +7 -2
- package/bundled/@yep-anywhere/shared/dist/index.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/index.js +2 -0
- package/bundled/@yep-anywhere/shared/dist/index.js.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/server-capabilities.d.ts +248 -0
- package/bundled/@yep-anywhere/shared/dist/server-capabilities.d.ts.map +1 -0
- package/bundled/@yep-anywhere/shared/dist/server-capabilities.js +251 -0
- package/bundled/@yep-anywhere/shared/dist/server-capabilities.js.map +1 -0
- package/bundled/@yep-anywhere/shared/dist/tool-display-actions.d.ts +26 -0
- package/bundled/@yep-anywhere/shared/dist/tool-display-actions.d.ts.map +1 -0
- package/bundled/@yep-anywhere/shared/dist/tool-display-actions.js +9 -0
- package/bundled/@yep-anywhere/shared/dist/tool-display-actions.js.map +1 -0
- package/bundled/@yep-anywhere/shared/package.json +1 -1
- package/client-dist/assets/de-BNhVdIq4.js +6 -0
- package/client-dist/assets/es-Csn9n24J.js +6 -0
- package/client-dist/assets/fr-DKx4tSpo.js +6 -0
- package/client-dist/assets/index-1y2h7U7U.js +582 -0
- package/client-dist/assets/index-Cn_ZDP6u.css +1 -0
- package/client-dist/assets/ja-DAkhkwQZ.js +6 -0
- package/client-dist/assets/zh-CN-B7lY0cc6.js +6 -0
- package/client-dist/index.html +2 -2
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js.map +1 -1
- package/dist/codex/codeModeExec.d.ts +30 -0
- package/dist/codex/codeModeExec.d.ts.map +1 -0
- package/dist/codex/codeModeExec.js +419 -0
- package/dist/codex/codeModeExec.js.map +1 -0
- package/dist/codex/displayActions.d.ts +48 -0
- package/dist/codex/displayActions.d.ts.map +1 -0
- package/dist/codex/displayActions.js +674 -0
- package/dist/codex/displayActions.js.map +1 -0
- package/dist/codex/normalization.d.ts +10 -7
- package/dist/codex/normalization.d.ts.map +1 -1
- package/dist/codex/normalization.js +179 -502
- package/dist/codex/normalization.js.map +1 -1
- package/dist/codex/webRun.d.ts +42 -0
- package/dist/codex/webRun.d.ts.map +1 -0
- package/dist/codex/webRun.js +199 -0
- package/dist/codex/webRun.js.map +1 -0
- package/dist/indexes/SessionIndexService.d.ts +1 -1
- package/dist/indexes/SessionIndexService.d.ts.map +1 -1
- package/dist/indexes/SessionIndexService.js +16 -4
- package/dist/indexes/SessionIndexService.js.map +1 -1
- package/dist/routes/git-status.d.ts.map +1 -1
- package/dist/routes/git-status.js +70 -0
- package/dist/routes/git-status.js.map +1 -1
- package/dist/routes/project-queue.d.ts.map +1 -1
- package/dist/routes/project-queue.js.map +1 -1
- package/dist/routes/public-shares.d.ts +1 -1
- package/dist/routes/public-shares.d.ts.map +1 -1
- package/dist/routes/public-shares.js +4 -6
- package/dist/routes/public-shares.js.map +1 -1
- package/dist/routes/session-metadata-patch.d.ts +24 -0
- package/dist/routes/session-metadata-patch.d.ts.map +1 -0
- package/dist/routes/session-metadata-patch.js +119 -0
- package/dist/routes/session-metadata-patch.js.map +1 -0
- package/dist/routes/session-project-routing.d.ts +25 -0
- package/dist/routes/session-project-routing.d.ts.map +1 -0
- package/dist/routes/session-project-routing.js +32 -0
- package/dist/routes/session-project-routing.js.map +1 -0
- package/dist/routes/session-provider-resolution.d.ts +28 -0
- package/dist/routes/session-provider-resolution.d.ts.map +1 -0
- package/dist/routes/session-provider-resolution.js +22 -0
- package/dist/routes/session-provider-resolution.js.map +1 -0
- package/dist/routes/session-queue-summaries.d.ts +21 -0
- package/dist/routes/session-queue-summaries.d.ts.map +1 -0
- package/dist/routes/session-queue-summaries.js +79 -0
- package/dist/routes/session-queue-summaries.js.map +1 -0
- package/dist/routes/session-recovered-queue.d.ts +43 -0
- package/dist/routes/session-recovered-queue.d.ts.map +1 -0
- package/dist/routes/session-recovered-queue.js +132 -0
- package/dist/routes/session-recovered-queue.js.map +1 -0
- package/dist/routes/session-thinking-options.d.ts +12 -0
- package/dist/routes/session-thinking-options.d.ts.map +1 -0
- package/dist/routes/session-thinking-options.js +7 -0
- package/dist/routes/session-thinking-options.js.map +1 -0
- package/dist/routes/sessions.d.ts.map +1 -1
- package/dist/routes/sessions.js +110 -409
- package/dist/routes/sessions.js.map +1 -1
- package/dist/routes/settings-parsers.d.ts +37 -0
- package/dist/routes/settings-parsers.d.ts.map +1 -0
- package/dist/routes/settings-parsers.js +896 -0
- package/dist/routes/settings-parsers.js.map +1 -0
- package/dist/routes/settings.d.ts.map +1 -1
- package/dist/routes/settings.js +4 -894
- package/dist/routes/settings.js.map +1 -1
- package/dist/routes/version.d.ts +0 -2
- package/dist/routes/version.d.ts.map +1 -1
- package/dist/routes/version.js +8 -10
- package/dist/routes/version.js.map +1 -1
- package/dist/sdk/cli-detection.d.ts +15 -1
- package/dist/sdk/cli-detection.d.ts.map +1 -1
- package/dist/sdk/cli-detection.js +159 -28
- package/dist/sdk/cli-detection.js.map +1 -1
- package/dist/sdk/messageQueue.d.ts +5 -0
- package/dist/sdk/messageQueue.d.ts.map +1 -1
- package/dist/sdk/messageQueue.js +21 -0
- package/dist/sdk/messageQueue.js.map +1 -1
- package/dist/sdk/providers/codex-model-catalog.d.ts +34 -0
- package/dist/sdk/providers/codex-model-catalog.d.ts.map +1 -0
- package/dist/sdk/providers/codex-model-catalog.js +378 -0
- package/dist/sdk/providers/codex-model-catalog.js.map +1 -0
- package/dist/sdk/providers/codex-notification-guards.d.ts +15 -0
- package/dist/sdk/providers/codex-notification-guards.d.ts.map +1 -0
- package/dist/sdk/providers/codex-notification-guards.js +159 -0
- package/dist/sdk/providers/codex-notification-guards.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/ImageGenerationItem.d.ts +9 -0
- package/dist/sdk/providers/codex-protocol/generated/ImageGenerationItem.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/ImageGenerationItem.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/ImageGenerationItem.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/MultiAgentMode.d.ts +5 -5
- package/dist/sdk/providers/codex-protocol/generated/MultiAgentMode.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/ResponseItem.d.ts +1 -0
- package/dist/sdk/providers/codex-protocol/generated/ResponseItem.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/ThreadId.d.ts +5 -0
- package/dist/sdk/providers/codex-protocol/generated/ThreadId.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/WebSearchItem.d.ts +7 -0
- package/dist/sdk/providers/codex-protocol/generated/WebSearchItem.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/WebSearchItem.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/WebSearchItem.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/AskForApproval.d.ts +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/AskForApproval.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/CapabilityRootLocation.d.ts +3 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/CapabilityRootLocation.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/CodexErrorInfo.d.ts +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/CodexErrorInfo.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/McpToolCallAppContext.d.ts +3 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/McpToolCallAppContext.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/Thread.d.ts +13 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/Thread.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadExtra.d.ts +5 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadExtra.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadExtra.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadExtra.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadForkParams.d.ts +7 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadForkParams.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadHistoryMode.d.ts +2 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadHistoryMode.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadHistoryMode.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadHistoryMode.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadItem.d.ts +5 -13
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadItem.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadRollbackParams.d.ts +3 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadRollbackParams.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadStartParams.d.ts +10 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadStartParams.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/Turn.d.ts +3 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/Turn.d.ts.map +1 -1
- package/dist/sdk/providers/codex-summary-helpers.d.ts +41 -0
- package/dist/sdk/providers/codex-summary-helpers.d.ts.map +1 -0
- package/dist/sdk/providers/codex-summary-helpers.js +207 -0
- package/dist/sdk/providers/codex-summary-helpers.js.map +1 -0
- package/dist/sdk/providers/codex.d.ts +0 -25
- package/dist/sdk/providers/codex.d.ts.map +1 -1
- package/dist/sdk/providers/codex.js +160 -703
- package/dist/sdk/providers/codex.js.map +1 -1
- package/dist/sdk/providers/opencode-models.d.ts +17 -0
- package/dist/sdk/providers/opencode-models.d.ts.map +1 -0
- package/dist/sdk/providers/opencode-models.js +83 -0
- package/dist/sdk/providers/opencode-models.js.map +1 -0
- package/dist/sdk/providers/opencode.d.ts +1 -9
- package/dist/sdk/providers/opencode.d.ts.map +1 -1
- package/dist/sdk/providers/opencode.js +1 -82
- package/dist/sdk/providers/opencode.js.map +1 -1
- package/dist/sdk/types.d.ts +3 -1
- package/dist/sdk/types.d.ts.map +1 -1
- package/dist/services/ProjectQueueService.d.ts.map +1 -1
- package/dist/services/ProjectQueueService.js +3 -1
- package/dist/services/ProjectQueueService.js.map +1 -1
- package/dist/sessions/claude-summary.d.ts.map +1 -1
- package/dist/sessions/claude-summary.js +13 -1
- package/dist/sessions/claude-summary.js.map +1 -1
- package/dist/sessions/codex-reader.d.ts +0 -2
- package/dist/sessions/codex-reader.d.ts.map +1 -1
- package/dist/sessions/codex-reader.js +46 -84
- package/dist/sessions/codex-reader.js.map +1 -1
- package/dist/sessions/codex-user-turn-provenance.d.ts +40 -0
- package/dist/sessions/codex-user-turn-provenance.d.ts.map +1 -0
- package/dist/sessions/codex-user-turn-provenance.js +165 -0
- package/dist/sessions/codex-user-turn-provenance.js.map +1 -0
- package/dist/sessions/normalization.d.ts.map +1 -1
- package/dist/sessions/normalization.js +80 -51
- package/dist/sessions/normalization.js.map +1 -1
- package/dist/sessions/pagination.d.ts +6 -0
- package/dist/sessions/pagination.d.ts.map +1 -1
- package/dist/sessions/pagination.js +42 -2
- package/dist/sessions/pagination.js.map +1 -1
- package/dist/subscriptions.d.ts.map +1 -1
- package/dist/subscriptions.js +1 -0
- package/dist/subscriptions.js.map +1 -1
- package/dist/supervisor/Process.d.ts +12 -0
- package/dist/supervisor/Process.d.ts.map +1 -1
- package/dist/supervisor/Process.js +178 -22
- package/dist/supervisor/Process.js.map +1 -1
- package/dist/supervisor/Supervisor.d.ts +5 -1
- package/dist/supervisor/Supervisor.d.ts.map +1 -1
- package/dist/supervisor/Supervisor.js +47 -0
- package/dist/supervisor/Supervisor.js.map +1 -1
- package/package.json +2 -2
- package/client-dist/assets/de-CHMDbVD5.js +0 -6
- package/client-dist/assets/es-CK8MPF_C.js +0 -6
- package/client-dist/assets/fr-49PXQiUL.js +0 -6
- package/client-dist/assets/index-B-09fVut.js +0 -557
- package/client-dist/assets/index-uJnfvD1f.css +0 -1
- package/client-dist/assets/ja-CrCGPmoH.js +0 -6
- package/client-dist/assets/zh-CN-AFJxv5ke.js +0 -6
package/dist/routes/sessions.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ALL_PERMISSION_MODES,
|
|
1
|
+
import { ALL_PERMISSION_MODES, buildEffectiveAgentContext, getModelContextWindow, isUrlProjectId, isWorkstreamId, mainWorkstreamId, truncateSessionTitle, } from "../../bundled/@yep-anywhere/shared/dist/index.js";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { mkdir } from "node:fs/promises";
|
|
4
4
|
import { performance } from "node:perf_hooks";
|
|
@@ -6,6 +6,7 @@ import { Hono } from "hono";
|
|
|
6
6
|
import { augmentTextBlocks } from "../augments/markdown-augments.js";
|
|
7
7
|
import { getLogger } from "../logging/logger.js";
|
|
8
8
|
import { DETACHED_PROJECT_PATH, encodeProjectId } from "../projects/paths.js";
|
|
9
|
+
import { resolveCanonicalProjectRedirect } from "./session-project-routing.js";
|
|
9
10
|
import { ensureRemoteDirectory } from "../sdk/remote-spawn.js";
|
|
10
11
|
import { parseSlashCommandSubmission } from "../sdk/slashCommandEmulation.js";
|
|
11
12
|
import { getProjectDirFromCwd, syncSessions } from "../sdk/session-sync.js";
|
|
@@ -16,7 +17,7 @@ import { GrokSessionReader } from "../sessions/grok-reader.js";
|
|
|
16
17
|
import { extractLastAgentExcerpt } from "../sessions/agent-excerpt.js";
|
|
17
18
|
import { normalizeSession } from "../sessions/normalization.js";
|
|
18
19
|
import { applyRecapOverlayToSession, applyRecapOverlayToSummary, hasEquivalentRecapMessage, hasUnreadProviderContent, latestRecapMessage, mergeRecapMessages, } from "../sessions/recap-overlays.js";
|
|
19
|
-
import { sliceAfterMessageIdWithMatch, sliceAtCompactBoundaries, sliceAtUserTurnBoundary, } from "../sessions/pagination.js";
|
|
20
|
+
import { sliceAfterMessageIdWithMatch, sliceAtCompactAndUserTurnBoundaries, sliceAtCompactBoundaries, sliceAtUserTurnBoundary, } from "../sessions/pagination.js";
|
|
20
21
|
import { augmentTaskListSnapshots, pruneTaskListSnapshotsToLatest, } from "../augments/task-list-augments.js";
|
|
21
22
|
import { augmentEditToolUses, augmentPersistedSessionMessages, } from "../sessions/persisted-augments.js";
|
|
22
23
|
import { findSessionSummaryAcrossProviders, getSessionSources, } from "../sessions/provider-resolution.js";
|
|
@@ -26,6 +27,11 @@ import { ResumeCompactionError } from "../supervisor/Supervisor.js";
|
|
|
26
27
|
import { buildUserMessageMetadata, normalizeOptionalServiceTier, parseHelperSettings, parseOptionalExecutor, parseOptionalResumeMode, } from "./session-request-helpers.js";
|
|
27
28
|
import { resolveCompactPercent, resolveCompactWindow, } from "./session-compact-thresholds.js";
|
|
28
29
|
import { getClaudeResumeBlockerFromReader, } from "./session-claude-resume-guard.js";
|
|
30
|
+
import { isClaudeSdkProviderName, isCodexProviderName, providerResolutionDeps, } from "./session-provider-resolution.js";
|
|
31
|
+
import { parseSessionMetadataPatch } from "./session-metadata-patch.js";
|
|
32
|
+
import { recoveredPatientQueueSummaries, sessionQueueSummaries, } from "./session-queue-summaries.js";
|
|
33
|
+
import { reportableProcessState, resolveRecoveredGroupForDelivery, resumeRecoveredGroup, } from "./session-recovered-queue.js";
|
|
34
|
+
import { buildThinkingOptions } from "./session-thinking-options.js";
|
|
29
35
|
const SESSION_DETAIL_SLOW_LOG_MS = 250;
|
|
30
36
|
const DEFAULT_SESSION_DETAIL_TAIL_COMPACTIONS = 2;
|
|
31
37
|
const LARGE_FULL_HISTORY_MESSAGE_THRESHOLD = 1000;
|
|
@@ -40,9 +46,6 @@ async function getSessionSlashCommands(process, provider) {
|
|
|
40
46
|
function roundedMs(value) {
|
|
41
47
|
return Math.round(value * 10) / 10;
|
|
42
48
|
}
|
|
43
|
-
function isClaudeSdkProviderName(provider) {
|
|
44
|
-
return provider === "claude" || provider === "claude-ollama";
|
|
45
|
-
}
|
|
46
49
|
/**
|
|
47
50
|
* Type guard to check if a result is a QueuedResponse
|
|
48
51
|
*/
|
|
@@ -55,111 +58,15 @@ function isQueuedResponse(result) {
|
|
|
55
58
|
function isQueueFullResponse(result) {
|
|
56
59
|
return "error" in result && result.error === "queue_full";
|
|
57
60
|
}
|
|
58
|
-
function isCodexProviderName(provider) {
|
|
59
|
-
return provider === "codex" || provider === "codex-oss";
|
|
60
|
-
}
|
|
61
61
|
const AUTO_COMPACT_CONTEXT_PERCENT_THRESHOLD = 85;
|
|
62
62
|
const AUTO_COMPACT_MODEL_PREFIXES = ["gpt-5.3-codex-spark"];
|
|
63
63
|
const AUTO_COMPACT_TARGET_PROVIDERS = new Set([
|
|
64
64
|
"codex",
|
|
65
65
|
"codex-oss",
|
|
66
66
|
]);
|
|
67
|
-
function providerResolutionDeps(deps) {
|
|
68
|
-
return {
|
|
69
|
-
readerFactory: deps.readerFactory,
|
|
70
|
-
sessionIndexService: deps.sessionIndexService,
|
|
71
|
-
codexSessionsDir: deps.codexSessionsDir,
|
|
72
|
-
codexReaderFactory: deps.codexReaderFactory,
|
|
73
|
-
geminiSessionsDir: deps.geminiSessionsDir,
|
|
74
|
-
geminiReaderFactory: deps.geminiReaderFactory,
|
|
75
|
-
geminiHashToCwd: deps.geminiScanner?.getHashToCwd(),
|
|
76
|
-
grokSessionsDir: deps.grokSessionsDir,
|
|
77
|
-
grokReaderFactory: deps.grokReaderFactory,
|
|
78
|
-
piSessionsDir: deps.piSessionsDir,
|
|
79
|
-
piReaderFactory: deps.piReaderFactory,
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
function persistedPatientQueueSummary(item) {
|
|
83
|
-
const attachmentCount = (item.message.attachments?.length ?? 0) +
|
|
84
|
-
(item.message.images?.length ?? 0) +
|
|
85
|
-
(item.message.documents?.length ?? 0);
|
|
86
|
-
const tempId = item.message.tempId ?? item.source?.tempId;
|
|
87
|
-
return {
|
|
88
|
-
id: item.id,
|
|
89
|
-
...(tempId ? { tempId } : {}),
|
|
90
|
-
content: item.message.text,
|
|
91
|
-
timestamp: item.queuedAt,
|
|
92
|
-
...(item.message.attachments?.length
|
|
93
|
-
? { attachments: item.message.attachments }
|
|
94
|
-
: {}),
|
|
95
|
-
...(attachmentCount > 0 ? { attachmentCount } : {}),
|
|
96
|
-
...(item.message.metadata ? { metadata: item.message.metadata } : {}),
|
|
97
|
-
kind: "patient",
|
|
98
|
-
status: item.status === "paused-after-restart" ? item.status : "queued",
|
|
99
|
-
sessionId: item.sessionId,
|
|
100
|
-
projectId: item.projectId,
|
|
101
|
-
queuedAt: item.queuedAt,
|
|
102
|
-
createdAt: item.createdAt,
|
|
103
|
-
updatedAt: item.updatedAt,
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
67
|
function isApprovalAuditLogEnabled(deps) {
|
|
107
68
|
return (deps.serverSettingsService?.getSetting("approvalAuditLogEnabled") === true);
|
|
108
69
|
}
|
|
109
|
-
function recoveredPatientQueueSummaries(deps, sessionId) {
|
|
110
|
-
return recoveredPatientQueueItems(deps, sessionId).map(persistedPatientQueueSummary);
|
|
111
|
-
}
|
|
112
|
-
function recoveredPatientQueueItems(deps, sessionId) {
|
|
113
|
-
if (!deps.sessionQueuePersistenceService) {
|
|
114
|
-
return [];
|
|
115
|
-
}
|
|
116
|
-
return deps.sessionQueuePersistenceService
|
|
117
|
-
.listSession(sessionId)
|
|
118
|
-
.filter((item) => item.kind === "patient" && item.status === "paused-after-restart")
|
|
119
|
-
.sort((left, right) => left.queuedAt.localeCompare(right.queuedAt));
|
|
120
|
-
}
|
|
121
|
-
function sessionQueueSummaries(deps, sessionId, process) {
|
|
122
|
-
const recovered = recoveredPatientQueueSummaries(deps, sessionId);
|
|
123
|
-
if (process && typeof process.getDeferredQueueSummary === "function") {
|
|
124
|
-
const messages = [
|
|
125
|
-
...process.getDeferredQueueSummary(),
|
|
126
|
-
...recovered,
|
|
127
|
-
];
|
|
128
|
-
return messages.sort((left, right) => (left.queuedAt ?? left.timestamp).localeCompare(right.queuedAt ?? right.timestamp));
|
|
129
|
-
}
|
|
130
|
-
if (process) {
|
|
131
|
-
return recovered;
|
|
132
|
-
}
|
|
133
|
-
return recovered;
|
|
134
|
-
}
|
|
135
|
-
function recoveredPatientUserMessage(item) {
|
|
136
|
-
const mode = item.message.mode ?? item.mode;
|
|
137
|
-
const metadata = {
|
|
138
|
-
...item.message.metadata,
|
|
139
|
-
deliveryIntent: "patient",
|
|
140
|
-
};
|
|
141
|
-
// Live-queue chip actions (cancel, steer) address entries by tempId, so a
|
|
142
|
-
// recovered entry that was persisted without one gets a stable fallback.
|
|
143
|
-
const tempId = item.message.tempId ?? item.source?.tempId ?? `recovered-${item.id}`;
|
|
144
|
-
return {
|
|
145
|
-
...item.message,
|
|
146
|
-
tempId,
|
|
147
|
-
...(mode ? { mode } : {}),
|
|
148
|
-
metadata,
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Count live patient queue entries composed after the given recovered entry.
|
|
153
|
-
* Resuming or steering the recovered entry would deliver its older content
|
|
154
|
-
* behind these newer ones, so callers reject while any exist. Regular
|
|
155
|
-
* deferred entries never block recovered work: the regular lane delivers on
|
|
156
|
-
* turn boundaries and may pass patient work by design.
|
|
157
|
-
*/
|
|
158
|
-
function livePatientEntriesNewerThan(process, queuedAt) {
|
|
159
|
-
const live = process?.getDeferredQueueSummary() ?? [];
|
|
160
|
-
return live.filter((entry) => entry.metadata?.deliveryIntent === "patient" &&
|
|
161
|
-
entry.timestamp.localeCompare(queuedAt) > 0).length;
|
|
162
|
-
}
|
|
163
70
|
async function resolveSessionReaderForAgentContent({ deps, project, sessionId, projectId, }) {
|
|
164
71
|
const metadataProvider = deps.sessionMetadataService?.getProvider(sessionId);
|
|
165
72
|
const resolved = await findSessionSummaryAcrossProviders(project, sessionId, projectId, providerResolutionDeps(deps), metadataProvider, { readMode: "head" });
|
|
@@ -701,6 +608,7 @@ function isCompactSummaryUserMessage(message) {
|
|
|
701
608
|
}
|
|
702
609
|
function isUserAuthoredRequest(message) {
|
|
703
610
|
return (isHumanUserMessage(message) &&
|
|
611
|
+
message.isSynthetic !== true &&
|
|
704
612
|
!isCompactSummaryUserMessage(message) &&
|
|
705
613
|
!isSlashCommandSkillBodyUserMessage(message));
|
|
706
614
|
}
|
|
@@ -1132,30 +1040,43 @@ export function createSessionsRoutes(deps) {
|
|
|
1132
1040
|
};
|
|
1133
1041
|
const resolveSessionProjectRouting = async (requestProjectId, sessionId) => {
|
|
1134
1042
|
const workingProjectId = deps.sessionMetadataService?.getMetadata(sessionId)?.workingProjectId;
|
|
1135
|
-
if (workingProjectId && workingProjectId !== requestProjectId) {
|
|
1136
|
-
return { redirectProjectId: workingProjectId };
|
|
1137
|
-
}
|
|
1138
1043
|
const activeProcess = deps.supervisor.getProcessForSession(sessionId);
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
activeProcess
|
|
1143
|
-
|
|
1044
|
+
const redirectProjectId = resolveCanonicalProjectRedirect({
|
|
1045
|
+
requestProjectId,
|
|
1046
|
+
workingProjectId,
|
|
1047
|
+
activeProcessProjectId: typeof activeProcess?.projectId === "string"
|
|
1048
|
+
? activeProcess.projectId
|
|
1049
|
+
: undefined,
|
|
1050
|
+
});
|
|
1051
|
+
if (redirectProjectId) {
|
|
1052
|
+
return { redirectProjectId };
|
|
1144
1053
|
}
|
|
1145
1054
|
const workingProject = await deps.scanner.getOrCreateProject(requestProjectId);
|
|
1146
1055
|
if (!workingProject) {
|
|
1147
1056
|
return { error: "Project not found", status: 404 };
|
|
1148
1057
|
}
|
|
1149
1058
|
const metadata = deps.sessionMetadataService?.getMetadata(sessionId);
|
|
1150
|
-
const
|
|
1151
|
-
metadata.transcriptProjectId
|
|
1059
|
+
const overlayTranscriptProjectId = metadata?.workingProjectId === requestProjectId &&
|
|
1060
|
+
metadata.transcriptProjectId &&
|
|
1061
|
+
metadata.transcriptProjectId !== requestProjectId
|
|
1152
1062
|
? metadata.transcriptProjectId
|
|
1153
|
-
:
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1063
|
+
: undefined;
|
|
1064
|
+
// Default: the transcript lives under the working (request) project.
|
|
1065
|
+
let transcriptProjectId = requestProjectId;
|
|
1066
|
+
let transcriptProject = workingProject;
|
|
1067
|
+
// Overlay case (session "moved" to a different working project): the
|
|
1068
|
+
// transcript may live under a distinct project. Trust the recorded pointer
|
|
1069
|
+
// only if the transcript is actually findable there — a stale/wrong pointer
|
|
1070
|
+
// must not permanently brick viewing, so fall back to the working project.
|
|
1071
|
+
if (overlayTranscriptProjectId) {
|
|
1072
|
+
const overlayProject = await deps.scanner.getOrCreateProject(overlayTranscriptProjectId);
|
|
1073
|
+
const overlayHasTranscript = overlayProject
|
|
1074
|
+
? Boolean(await findSessionSummaryAcrossProviders(overlayProject, sessionId, overlayTranscriptProjectId, providerResolutionDeps(deps), deps.sessionMetadataService?.getProvider(sessionId), { readMode: "head" }))
|
|
1075
|
+
: false;
|
|
1076
|
+
if (overlayProject && overlayHasTranscript) {
|
|
1077
|
+
transcriptProjectId = overlayTranscriptProjectId;
|
|
1078
|
+
transcriptProject = overlayProject;
|
|
1079
|
+
}
|
|
1159
1080
|
}
|
|
1160
1081
|
return {
|
|
1161
1082
|
transcriptProject,
|
|
@@ -1425,7 +1346,9 @@ export function createSessionsRoutes(deps) {
|
|
|
1425
1346
|
const lastSeenAt = lastSeenEntry?.timestamp;
|
|
1426
1347
|
// Get pending input request from active process
|
|
1427
1348
|
const pendingInputRequest = process?.state.type === "waiting-input" ? process.state.request : null;
|
|
1428
|
-
const providerRuntimeStatus =
|
|
1349
|
+
const providerRuntimeStatus = deps.supervisor.getProviderRuntimeStatusForSession?.(sessionId) ??
|
|
1350
|
+
process?.getProviderRuntimeStatus() ??
|
|
1351
|
+
null;
|
|
1429
1352
|
// Read minimal session info from disk (just for title/timestamps, no messages)
|
|
1430
1353
|
const metadataProvider = metadata?.provider ??
|
|
1431
1354
|
deps.sessionMetadataService?.getProvider(sessionId);
|
|
@@ -1617,9 +1540,9 @@ export function createSessionsRoutes(deps) {
|
|
|
1617
1540
|
// ?afterMessageId=<id> - incremental forward-fetch (append new messages)
|
|
1618
1541
|
// ?tailCompactions=<n> - return only last N compact boundaries worth of messages
|
|
1619
1542
|
// ?beforeMessageId=<id> - cursor for loading older chunks (used with tailCompactions)
|
|
1620
|
-
// ?tailTurns=<n> -
|
|
1621
|
-
// ?tailFrom=<id> -
|
|
1622
|
-
// ?fullHistory=1 -
|
|
1543
|
+
// ?tailTurns=<n> - recent-turn selector within the authorized history scope
|
|
1544
|
+
// ?tailFrom=<id> - start selector within the authorized history scope
|
|
1545
|
+
// ?fullHistory=1 - explicitly authorize selectors to inspect full history
|
|
1623
1546
|
routes.get("/projects/:projectId/sessions/:sessionId", async (c) => {
|
|
1624
1547
|
const requestStartMs = performance.now();
|
|
1625
1548
|
const projectId = c.req.param("projectId");
|
|
@@ -1648,9 +1571,10 @@ export function createSessionsRoutes(deps) {
|
|
|
1648
1571
|
: undefined;
|
|
1649
1572
|
const defaultedToCompactTail = !fullHistory &&
|
|
1650
1573
|
!afterMessageId &&
|
|
1651
|
-
!tailFrom &&
|
|
1652
|
-
requestedTailTurns === undefined &&
|
|
1653
1574
|
requestedTailCompactions === undefined;
|
|
1575
|
+
const unboundedRequestDefaultedToCompactTail = defaultedToCompactTail &&
|
|
1576
|
+
!tailFrom &&
|
|
1577
|
+
requestedTailTurns === undefined;
|
|
1654
1578
|
const effectiveTailCompactions = requestedTailCompactions ??
|
|
1655
1579
|
(defaultedToCompactTail
|
|
1656
1580
|
? DEFAULT_SESSION_DETAIL_TAIL_COMPACTIONS
|
|
@@ -1724,7 +1648,9 @@ export function createSessionsRoutes(deps) {
|
|
|
1724
1648
|
// Get pending input request from active process (for tool approval prompts)
|
|
1725
1649
|
// This ensures clients get pending requests immediately without waiting for SSE
|
|
1726
1650
|
const pendingInputRequest = process?.state.type === "waiting-input" ? process.state.request : null;
|
|
1727
|
-
const providerRuntimeStatus =
|
|
1651
|
+
const providerRuntimeStatus = deps.supervisor.getProviderRuntimeStatusForSession?.(sessionId) ??
|
|
1652
|
+
process?.getProviderRuntimeStatus() ??
|
|
1653
|
+
null;
|
|
1728
1654
|
// Get available slash commands (for "/" button and typed slash menu)
|
|
1729
1655
|
// The init message that normally carries these gets discarded from the SSE buffer
|
|
1730
1656
|
// after ~30s, so we attach them to the REST response. Providers with known
|
|
@@ -1812,12 +1738,21 @@ export function createSessionsRoutes(deps) {
|
|
|
1812
1738
|
// Get notification data (lastSeenAt, hasUnread)
|
|
1813
1739
|
const lastSeenEntry = deps.notificationService?.getLastSeen(sessionId);
|
|
1814
1740
|
const lastSeenAt = lastSeenEntry?.timestamp;
|
|
1815
|
-
// Apply pagination
|
|
1816
|
-
//
|
|
1817
|
-
//
|
|
1818
|
-
//
|
|
1741
|
+
// Apply pagination BEFORE expensive augmentation. Compact boundaries set
|
|
1742
|
+
// the authorized history scope by default; turn selectors may narrow that
|
|
1743
|
+
// scope but cannot broaden it unless fullHistory=1 removed the default.
|
|
1744
|
+
// Skip initial-window slicing for incremental forward fetches.
|
|
1819
1745
|
let paginationInfo;
|
|
1820
1746
|
if (!afterMessageId &&
|
|
1747
|
+
effectiveTailCompactions !== undefined &&
|
|
1748
|
+
!beforeMessageId &&
|
|
1749
|
+
(tailFrom || requestedTailTurns !== undefined)) {
|
|
1750
|
+
const sliced = sliceAtCompactAndUserTurnBoundaries(session.messages, effectiveTailCompactions, requestedTailTurns ?? 20, tailFrom);
|
|
1751
|
+
session = { ...session, messages: sliced.messages };
|
|
1752
|
+
paginationInfo = sliced.pagination;
|
|
1753
|
+
}
|
|
1754
|
+
else if (!afterMessageId &&
|
|
1755
|
+
effectiveTailCompactions === undefined &&
|
|
1821
1756
|
(tailFrom || requestedTailTurns !== undefined)) {
|
|
1822
1757
|
const sliced = sliceAtUserTurnBoundary(session.messages, requestedTailTurns ?? 20, tailFrom);
|
|
1823
1758
|
session = { ...session, messages: sliced.messages };
|
|
@@ -1889,7 +1824,7 @@ export function createSessionsRoutes(deps) {
|
|
|
1889
1824
|
}
|
|
1890
1825
|
const { messages: _messages, ...sessionMetadata } = session;
|
|
1891
1826
|
const totalMs = performance.now() - requestStartMs;
|
|
1892
|
-
if (
|
|
1827
|
+
if (unboundedRequestDefaultedToCompactTail &&
|
|
1893
1828
|
normalizedMessageCount >= LARGE_FULL_HISTORY_MESSAGE_THRESHOLD) {
|
|
1894
1829
|
getLogger().warn({
|
|
1895
1830
|
beforeMessageId: beforeMessageId ?? null,
|
|
@@ -2048,10 +1983,7 @@ export function createSessionsRoutes(deps) {
|
|
|
2048
1983
|
tempId: body.tempId,
|
|
2049
1984
|
metadata: buildUserMessageMetadata(body, serverTimestamp, "direct"),
|
|
2050
1985
|
};
|
|
2051
|
-
|
|
2052
|
-
const { thinking, effort } = body.thinking
|
|
2053
|
-
? thinkingOptionToConfig(body.thinking, body.showThinking)
|
|
2054
|
-
: { thinking: undefined, effort: undefined };
|
|
1986
|
+
const { thinking, effort } = buildThinkingOptions(body);
|
|
2055
1987
|
// Convert model option (undefined or "default" means use CLI default)
|
|
2056
1988
|
const model = body.model && body.model !== "default" ? body.model : undefined;
|
|
2057
1989
|
const serviceTier = normalizeOptionalServiceTier(body.serviceTier);
|
|
@@ -2130,10 +2062,7 @@ export function createSessionsRoutes(deps) {
|
|
|
2130
2062
|
if ("error" in workstreamTarget) {
|
|
2131
2063
|
return c.json({ error: workstreamTarget.error }, workstreamTarget.status);
|
|
2132
2064
|
}
|
|
2133
|
-
|
|
2134
|
-
const { thinking, effort } = body.thinking
|
|
2135
|
-
? thinkingOptionToConfig(body.thinking, body.showThinking)
|
|
2136
|
-
: { thinking: undefined, effort: undefined };
|
|
2065
|
+
const { thinking, effort } = buildThinkingOptions(body);
|
|
2137
2066
|
// Convert model option (undefined or "default" means use CLI default)
|
|
2138
2067
|
const model = body.model && body.model !== "default" ? body.model : undefined;
|
|
2139
2068
|
const serviceTier = normalizeOptionalServiceTier(body.serviceTier);
|
|
@@ -2204,9 +2133,7 @@ export function createSessionsRoutes(deps) {
|
|
|
2204
2133
|
tempId: body.tempId,
|
|
2205
2134
|
metadata: buildUserMessageMetadata(body, serverTimestamp, "direct"),
|
|
2206
2135
|
};
|
|
2207
|
-
const { thinking, effort } = body
|
|
2208
|
-
? thinkingOptionToConfig(body.thinking, body.showThinking)
|
|
2209
|
-
: { thinking: undefined, effort: undefined };
|
|
2136
|
+
const { thinking, effort } = buildThinkingOptions(body);
|
|
2210
2137
|
const model = body.model && body.model !== "default" ? body.model : undefined;
|
|
2211
2138
|
const serviceTier = normalizeOptionalServiceTier(body.serviceTier);
|
|
2212
2139
|
const result = await deps.supervisor.startSession(projectPath, userMessage, body.mode, {
|
|
@@ -2258,9 +2185,7 @@ export function createSessionsRoutes(deps) {
|
|
|
2258
2185
|
return c.json({ error: helperSettings.error }, 400);
|
|
2259
2186
|
}
|
|
2260
2187
|
const projectPath = await ensureDetachedProjectPath(executor);
|
|
2261
|
-
const { thinking, effort } = body
|
|
2262
|
-
? thinkingOptionToConfig(body.thinking, body.showThinking)
|
|
2263
|
-
: { thinking: undefined, effort: undefined };
|
|
2188
|
+
const { thinking, effort } = buildThinkingOptions(body);
|
|
2264
2189
|
const model = body.model && body.model !== "default" ? body.model : undefined;
|
|
2265
2190
|
const serviceTier = normalizeOptionalServiceTier(body.serviceTier);
|
|
2266
2191
|
const result = await deps.supervisor.createSession(projectPath, body.mode, {
|
|
@@ -2340,10 +2265,7 @@ export function createSessionsRoutes(deps) {
|
|
|
2340
2265
|
tempId: body.tempId,
|
|
2341
2266
|
metadata: buildUserMessageMetadata(body, serverTimestamp, "direct"),
|
|
2342
2267
|
};
|
|
2343
|
-
|
|
2344
|
-
const { thinking, effort } = body.thinking
|
|
2345
|
-
? thinkingOptionToConfig(body.thinking, body.showThinking)
|
|
2346
|
-
: { thinking: undefined, effort: undefined };
|
|
2268
|
+
const { thinking, effort } = buildThinkingOptions(body);
|
|
2347
2269
|
// Convert model option (undefined or "default" means use CLI default). When
|
|
2348
2270
|
// the client sends no model (e.g. resume after a server restart), recover the
|
|
2349
2271
|
// YA model id persisted at launch so the process keeps its requested alias
|
|
@@ -2578,9 +2500,7 @@ export function createSessionsRoutes(deps) {
|
|
|
2578
2500
|
? body.model
|
|
2579
2501
|
: metadata?.requestedModel;
|
|
2580
2502
|
const model = rawModel && rawModel !== "default" ? rawModel : undefined;
|
|
2581
|
-
const { thinking, effort } = body
|
|
2582
|
-
? thinkingOptionToConfig(body.thinking, body.showThinking)
|
|
2583
|
-
: { thinking: undefined, effort: undefined };
|
|
2503
|
+
const { thinking, effort } = buildThinkingOptions(body);
|
|
2584
2504
|
let process;
|
|
2585
2505
|
try {
|
|
2586
2506
|
process = await deps.supervisor.reactivateSession(project.path, sessionId, body.mode, {
|
|
@@ -2742,9 +2662,7 @@ export function createSessionsRoutes(deps) {
|
|
|
2742
2662
|
const sourceProvider = sourceSession.provider ?? preferredSourceProvider;
|
|
2743
2663
|
const providerName = body.provider ?? sourceProvider;
|
|
2744
2664
|
const originalMetadata = deps.sessionMetadataService?.getMetadata(sessionId);
|
|
2745
|
-
const { thinking, effort } = body
|
|
2746
|
-
? thinkingOptionToConfig(body.thinking, body.showThinking)
|
|
2747
|
-
: { thinking: undefined, effort: undefined };
|
|
2665
|
+
const { thinking, effort } = buildThinkingOptions(body);
|
|
2748
2666
|
const model = body.model && body.model !== "default" ? body.model : undefined;
|
|
2749
2667
|
const serviceTier = normalizeOptionalServiceTier(body.serviceTier);
|
|
2750
2668
|
if (restartMode === "fork") {
|
|
@@ -3569,10 +3487,7 @@ export function createSessionsRoutes(deps) {
|
|
|
3569
3487
|
serverTimestamp,
|
|
3570
3488
|
});
|
|
3571
3489
|
}
|
|
3572
|
-
|
|
3573
|
-
const { thinking, effort } = body.thinking
|
|
3574
|
-
? thinkingOptionToConfig(body.thinking, body.showThinking)
|
|
3575
|
-
: { thinking: undefined, effort: undefined };
|
|
3490
|
+
const { thinking, effort } = buildThinkingOptions(body);
|
|
3576
3491
|
const metadataProvider = deps.sessionMetadataService?.getProvider(sessionId);
|
|
3577
3492
|
const metadataExecutor = parseOptionalExecutor(deps.sessionMetadataService?.getExecutor(sessionId));
|
|
3578
3493
|
if (metadataExecutor.error) {
|
|
@@ -3656,131 +3571,12 @@ export function createSessionsRoutes(deps) {
|
|
|
3656
3571
|
deferredMessages: recoveredPatientQueueSummaries(deps, sessionId),
|
|
3657
3572
|
});
|
|
3658
3573
|
});
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
const parsedExecutor = parseOptionalExecutor(item.executor ?? metadata?.executor);
|
|
3666
|
-
if (parsedExecutor.error) {
|
|
3667
|
-
return { error: parsedExecutor.error, status: 400 };
|
|
3668
|
-
}
|
|
3669
|
-
const rawModel = item.model ?? metadata?.requestedModel;
|
|
3670
|
-
const model = rawModel && rawModel !== "default" ? rawModel : undefined;
|
|
3671
|
-
if (!process) {
|
|
3672
|
-
try {
|
|
3673
|
-
process = await deps.supervisor.reactivateSession(item.projectPath, sessionId, mode, {
|
|
3674
|
-
model,
|
|
3675
|
-
serviceTier: item.serviceTier,
|
|
3676
|
-
providerName: item.provider,
|
|
3677
|
-
executor: parsedExecutor.executor,
|
|
3678
|
-
globalInstructions: getGlobalInstructions(),
|
|
3679
|
-
recapAfterSeconds: metadata?.recapAfterSeconds,
|
|
3680
|
-
promptSuggestionMode: metadata?.promptSuggestionMode,
|
|
3681
|
-
});
|
|
3682
|
-
}
|
|
3683
|
-
catch (error) {
|
|
3684
|
-
return {
|
|
3685
|
-
error: error instanceof Error
|
|
3686
|
-
? error.message
|
|
3687
|
-
: "Failed to reactivate session",
|
|
3688
|
-
status: 503,
|
|
3689
|
-
};
|
|
3690
|
-
}
|
|
3691
|
-
await persistLaunchMetadata(sessionId, item.provider, parsedExecutor.executor, undefined, item.model ?? metadata?.requestedModel, metadata?.promptSuggestionMode, metadata?.recapAfterSeconds);
|
|
3692
|
-
}
|
|
3693
|
-
else if (mode) {
|
|
3694
|
-
process.setPermissionMode(mode);
|
|
3695
|
-
}
|
|
3696
|
-
return { process };
|
|
3697
|
-
};
|
|
3698
|
-
// Move recovered entries back into the live patient queue in queuedAt
|
|
3699
|
-
// order. On a mid-group failure the earlier resumes stand; the caller
|
|
3700
|
-
// reports the failed entry.
|
|
3701
|
-
const resumeRecoveredGroup = async (process, group, options) => {
|
|
3702
|
-
let last;
|
|
3703
|
-
let lastMessage;
|
|
3704
|
-
for (const item of group) {
|
|
3705
|
-
const userMessage = recoveredPatientUserMessage(item);
|
|
3706
|
-
await process.primeSupportedCommandsForMessage(userMessage);
|
|
3707
|
-
const result = process.deferMessage(userMessage, {
|
|
3708
|
-
promoteIfReady: options.promoteIfReady,
|
|
3709
|
-
persistedQueueId: item.id,
|
|
3710
|
-
timestamp: item.queuedAt,
|
|
3711
|
-
});
|
|
3712
|
-
if (!result.success) {
|
|
3713
|
-
return {
|
|
3714
|
-
last,
|
|
3715
|
-
lastMessage,
|
|
3716
|
-
error: result.error ?? "Failed to queue message",
|
|
3717
|
-
};
|
|
3718
|
-
}
|
|
3719
|
-
last = result;
|
|
3720
|
-
lastMessage = userMessage;
|
|
3721
|
-
}
|
|
3722
|
-
return { last, lastMessage };
|
|
3723
|
-
};
|
|
3724
|
-
const reportableProcessState = (process) => process.state.type === "waiting-input" || process.state.type === "in-turn"
|
|
3725
|
-
? process.state.type
|
|
3726
|
-
: "idle";
|
|
3727
|
-
// Shared prologue for the recovered-queue resume/steer routes: resolve the
|
|
3728
|
-
// target and the recovered group composed before it, refuse while newer
|
|
3729
|
-
// live patient entries exist, and ensure a live process. The newer-entries
|
|
3730
|
-
// guard runs again after the ensure — its await is a window for new
|
|
3731
|
-
// arrivals, and recovered context must never jump a newer patient entry.
|
|
3732
|
-
const resolveRecoveredGroupForDelivery = async (sessionId, queueId, refusal) => {
|
|
3733
|
-
if (!deps.sessionQueuePersistenceService) {
|
|
3734
|
-
return {
|
|
3735
|
-
ok: false,
|
|
3736
|
-
status: 503,
|
|
3737
|
-
body: { error: "Session queue persistence unavailable" },
|
|
3738
|
-
};
|
|
3739
|
-
}
|
|
3740
|
-
const recoveredItems = recoveredPatientQueueItems(deps, sessionId);
|
|
3741
|
-
const targetIndex = recoveredItems.findIndex((candidate) => candidate.id === queueId);
|
|
3742
|
-
const target = recoveredItems[targetIndex];
|
|
3743
|
-
if (!target) {
|
|
3744
|
-
return {
|
|
3745
|
-
ok: false,
|
|
3746
|
-
status: 404,
|
|
3747
|
-
body: { error: "Recovered queued message not found" },
|
|
3748
|
-
};
|
|
3749
|
-
}
|
|
3750
|
-
const group = recoveredItems.slice(0, targetIndex + 1);
|
|
3751
|
-
let process = deps.supervisor.getProcessForSession(sessionId);
|
|
3752
|
-
if (process?.isTerminated) {
|
|
3753
|
-
process = undefined;
|
|
3754
|
-
}
|
|
3755
|
-
const refuseIfNewerEntries = (candidate) => livePatientEntriesNewerThan(candidate, target.queuedAt) > 0
|
|
3756
|
-
? {
|
|
3757
|
-
ok: false,
|
|
3758
|
-
status: 409,
|
|
3759
|
-
body: {
|
|
3760
|
-
error: refusal,
|
|
3761
|
-
headQueueId: target.id,
|
|
3762
|
-
deferredMessages: sessionQueueSummaries(deps, sessionId, candidate),
|
|
3763
|
-
},
|
|
3764
|
-
}
|
|
3765
|
-
: null;
|
|
3766
|
-
const refusedBefore = refuseIfNewerEntries(process);
|
|
3767
|
-
if (refusedBefore) {
|
|
3768
|
-
return refusedBefore;
|
|
3769
|
-
}
|
|
3770
|
-
const ensured = await ensureProcessForRecoveredItem(sessionId, target, process);
|
|
3771
|
-
if ("error" in ensured) {
|
|
3772
|
-
return {
|
|
3773
|
-
ok: false,
|
|
3774
|
-
status: ensured.status,
|
|
3775
|
-
body: { error: ensured.error },
|
|
3776
|
-
};
|
|
3777
|
-
}
|
|
3778
|
-
process = ensured.process;
|
|
3779
|
-
const refusedAfter = refuseIfNewerEntries(process);
|
|
3780
|
-
if (refusedAfter) {
|
|
3781
|
-
return refusedAfter;
|
|
3782
|
-
}
|
|
3783
|
-
return { ok: true, process, group };
|
|
3574
|
+
const recoveredQueueDeps = {
|
|
3575
|
+
sessionQueuePersistenceService: deps.sessionQueuePersistenceService,
|
|
3576
|
+
sessionMetadataService: deps.sessionMetadataService,
|
|
3577
|
+
supervisor: deps.supervisor,
|
|
3578
|
+
getGlobalInstructions,
|
|
3579
|
+
persistLaunchMetadata,
|
|
3784
3580
|
};
|
|
3785
3581
|
// POST /api/sessions/:sessionId/recovered-queue/:queueId/resume - Move
|
|
3786
3582
|
// restart-paused patient queue entries back into the live patient queue,
|
|
@@ -3789,7 +3585,7 @@ export function createSessionsRoutes(deps) {
|
|
|
3789
3585
|
routes.post("/sessions/:sessionId/recovered-queue/:queueId/resume", async (c) => {
|
|
3790
3586
|
const sessionId = c.req.param("sessionId");
|
|
3791
3587
|
const queueId = c.req.param("queueId");
|
|
3792
|
-
const resolved = await resolveRecoveredGroupForDelivery(sessionId, queueId, "Drain or cancel newer queued messages before resuming recovered work.");
|
|
3588
|
+
const resolved = await resolveRecoveredGroupForDelivery(recoveredQueueDeps, sessionId, queueId, "Drain or cancel newer queued messages before resuming recovered work.");
|
|
3793
3589
|
if (!resolved.ok) {
|
|
3794
3590
|
return c.json(resolved.body, resolved.status);
|
|
3795
3591
|
}
|
|
@@ -3827,7 +3623,7 @@ export function createSessionsRoutes(deps) {
|
|
|
3827
3623
|
routes.post("/sessions/:sessionId/recovered-queue/:queueId/steer", async (c) => {
|
|
3828
3624
|
const sessionId = c.req.param("sessionId");
|
|
3829
3625
|
const queueId = c.req.param("queueId");
|
|
3830
|
-
const resolved = await resolveRecoveredGroupForDelivery(sessionId, queueId, "Drain or cancel newer queued messages before steering recovered work.");
|
|
3626
|
+
const resolved = await resolveRecoveredGroupForDelivery(recoveredQueueDeps, sessionId, queueId, "Drain or cancel newer queued messages before steering recovered work.");
|
|
3831
3627
|
if (!resolved.ok) {
|
|
3832
3628
|
return c.json(resolved.body, resolved.status);
|
|
3833
3629
|
}
|
|
@@ -3875,6 +3671,21 @@ export function createSessionsRoutes(deps) {
|
|
|
3875
3671
|
await process.waitForPatientQueuePersistenceIdle();
|
|
3876
3672
|
return c.json({ cancelled: true });
|
|
3877
3673
|
});
|
|
3674
|
+
// DELETE /api/sessions/:sessionId/steering/:tempId - Cancel a sent steering
|
|
3675
|
+
// message that has not yet been consumed by the provider.
|
|
3676
|
+
routes.delete("/sessions/:sessionId/steering/:tempId", async (c) => {
|
|
3677
|
+
const sessionId = c.req.param("sessionId");
|
|
3678
|
+
const tempId = c.req.param("tempId");
|
|
3679
|
+
const process = deps.supervisor.getProcessForSession(sessionId);
|
|
3680
|
+
if (!process) {
|
|
3681
|
+
return c.json({ error: "No active process for session" }, 404);
|
|
3682
|
+
}
|
|
3683
|
+
const cancelled = process.cancelUnconfirmedSteerMessage(tempId);
|
|
3684
|
+
if (!cancelled) {
|
|
3685
|
+
return c.json({ error: "Steering message already acted on or not found" }, 404);
|
|
3686
|
+
}
|
|
3687
|
+
return c.json({ cancelled: true });
|
|
3688
|
+
});
|
|
3878
3689
|
// POST /api/sessions/:sessionId/deferred/:tempId/steer - Steer a patient
|
|
3879
3690
|
// queued message, and every patient entry ahead of it, into the session now.
|
|
3880
3691
|
routes.post("/sessions/:sessionId/deferred/:tempId/steer", async (c) => {
|
|
@@ -4116,137 +3927,27 @@ export function createSessionsRoutes(deps) {
|
|
|
4116
3927
|
catch {
|
|
4117
3928
|
return c.json({ error: "Invalid JSON body" }, 400);
|
|
4118
3929
|
}
|
|
4119
|
-
|
|
4120
|
-
if (
|
|
4121
|
-
|
|
4122
|
-
body.starred === undefined &&
|
|
4123
|
-
body.parentSessionId === undefined &&
|
|
4124
|
-
body.heartbeatTurnsEnabled === undefined &&
|
|
4125
|
-
body.heartbeatTurnsAfterMinutes === undefined &&
|
|
4126
|
-
body.heartbeatTurnText === undefined &&
|
|
4127
|
-
body.heartbeatForceAfterMinutes === undefined &&
|
|
4128
|
-
body.promptSuggestionMode === undefined &&
|
|
4129
|
-
body.recapAfterSeconds === undefined) {
|
|
4130
|
-
return c.json({
|
|
4131
|
-
error: "At least one session metadata field must be provided",
|
|
4132
|
-
}, 400);
|
|
4133
|
-
}
|
|
4134
|
-
let heartbeatForceAfterMinutes;
|
|
4135
|
-
if (body.heartbeatForceAfterMinutes !== undefined) {
|
|
4136
|
-
if (body.heartbeatForceAfterMinutes === null ||
|
|
4137
|
-
body.heartbeatForceAfterMinutes === 0) {
|
|
4138
|
-
heartbeatForceAfterMinutes = null;
|
|
4139
|
-
}
|
|
4140
|
-
else if (typeof body.heartbeatForceAfterMinutes === "number" &&
|
|
4141
|
-
Number.isInteger(body.heartbeatForceAfterMinutes) &&
|
|
4142
|
-
body.heartbeatForceAfterMinutes >= 1 &&
|
|
4143
|
-
body.heartbeatForceAfterMinutes <= 1440) {
|
|
4144
|
-
heartbeatForceAfterMinutes = body.heartbeatForceAfterMinutes;
|
|
4145
|
-
}
|
|
4146
|
-
else {
|
|
4147
|
-
return c.json({
|
|
4148
|
-
error: "heartbeatForceAfterMinutes must be null or an integer between 1 and 1440",
|
|
4149
|
-
}, 400);
|
|
4150
|
-
}
|
|
4151
|
-
}
|
|
4152
|
-
let heartbeatTurnsAfterMinutes;
|
|
4153
|
-
if (body.heartbeatTurnsAfterMinutes !== undefined) {
|
|
4154
|
-
if (body.heartbeatTurnsAfterMinutes === null ||
|
|
4155
|
-
body.heartbeatTurnsAfterMinutes === 0) {
|
|
4156
|
-
heartbeatTurnsAfterMinutes = null;
|
|
4157
|
-
}
|
|
4158
|
-
else if (typeof body.heartbeatTurnsAfterMinutes === "number" &&
|
|
4159
|
-
Number.isInteger(body.heartbeatTurnsAfterMinutes) &&
|
|
4160
|
-
body.heartbeatTurnsAfterMinutes >= 1 &&
|
|
4161
|
-
body.heartbeatTurnsAfterMinutes <= 1440) {
|
|
4162
|
-
heartbeatTurnsAfterMinutes = body.heartbeatTurnsAfterMinutes;
|
|
4163
|
-
}
|
|
4164
|
-
else {
|
|
4165
|
-
return c.json({
|
|
4166
|
-
error: "heartbeatTurnsAfterMinutes must be null or an integer between 1 and 1440",
|
|
4167
|
-
}, 400);
|
|
4168
|
-
}
|
|
4169
|
-
}
|
|
4170
|
-
const heartbeatTurnText = body.heartbeatTurnText === undefined
|
|
4171
|
-
? undefined
|
|
4172
|
-
: body.heartbeatTurnText === null || body.heartbeatTurnText === ""
|
|
4173
|
-
? null
|
|
4174
|
-
: typeof body.heartbeatTurnText === "string"
|
|
4175
|
-
? body.heartbeatTurnText.slice(0, 200)
|
|
4176
|
-
: null;
|
|
4177
|
-
if (body.heartbeatTurnText !== undefined &&
|
|
4178
|
-
body.heartbeatTurnText !== null &&
|
|
4179
|
-
body.heartbeatTurnText !== "" &&
|
|
4180
|
-
typeof body.heartbeatTurnText !== "string") {
|
|
4181
|
-
return c.json({ error: "heartbeatTurnText must be a string or null" }, 400);
|
|
4182
|
-
}
|
|
4183
|
-
if (body.parentSessionId !== undefined &&
|
|
4184
|
-
body.parentSessionId !== null &&
|
|
4185
|
-
typeof body.parentSessionId !== "string") {
|
|
4186
|
-
return c.json({ error: "parentSessionId must be a string or null" }, 400);
|
|
4187
|
-
}
|
|
4188
|
-
const parentSessionId = body.parentSessionId === undefined
|
|
4189
|
-
? undefined
|
|
4190
|
-
: typeof body.parentSessionId === "string"
|
|
4191
|
-
? body.parentSessionId.trim() || null
|
|
4192
|
-
: null;
|
|
4193
|
-
// promptSuggestionMode: null/"" clears the preference (revert to default);
|
|
4194
|
-
// a valid enum value is stored; any other value is rejected.
|
|
4195
|
-
let promptSuggestionMode;
|
|
4196
|
-
if (body.promptSuggestionMode !== undefined) {
|
|
4197
|
-
if (body.promptSuggestionMode === null ||
|
|
4198
|
-
body.promptSuggestionMode === "") {
|
|
4199
|
-
promptSuggestionMode = null;
|
|
4200
|
-
}
|
|
4201
|
-
else if (typeof body.promptSuggestionMode === "string" &&
|
|
4202
|
-
PROMPT_SUGGESTION_MODES.includes(body.promptSuggestionMode)) {
|
|
4203
|
-
promptSuggestionMode =
|
|
4204
|
-
body.promptSuggestionMode;
|
|
4205
|
-
}
|
|
4206
|
-
else {
|
|
4207
|
-
return c.json({ error: "promptSuggestionMode must be one of: off, native" }, 400);
|
|
4208
|
-
}
|
|
3930
|
+
const parsed = parseSessionMetadataPatch(body);
|
|
3931
|
+
if (!parsed.ok) {
|
|
3932
|
+
return c.json({ error: parsed.error }, parsed.status);
|
|
4209
3933
|
}
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
if (body.recapAfterSeconds === null || body.recapAfterSeconds === "") {
|
|
4213
|
-
recapAfterSeconds = null;
|
|
4214
|
-
}
|
|
4215
|
-
else if (typeof body.recapAfterSeconds === "number" &&
|
|
4216
|
-
Number.isFinite(body.recapAfterSeconds)) {
|
|
4217
|
-
recapAfterSeconds = clampRecapAfterSeconds(body.recapAfterSeconds);
|
|
4218
|
-
}
|
|
4219
|
-
else {
|
|
4220
|
-
return c.json({ error: "recapAfterSeconds must be null or a finite number" }, 400);
|
|
4221
|
-
}
|
|
4222
|
-
}
|
|
4223
|
-
await deps.sessionMetadataService.updateMetadata(sessionId, {
|
|
4224
|
-
title: body.title,
|
|
4225
|
-
archived: body.archived,
|
|
4226
|
-
starred: body.starred,
|
|
4227
|
-
parentSessionId,
|
|
4228
|
-
heartbeatTurnsEnabled: body.heartbeatTurnsEnabled,
|
|
4229
|
-
heartbeatTurnsAfterMinutes,
|
|
4230
|
-
heartbeatTurnText,
|
|
4231
|
-
heartbeatForceAfterMinutes,
|
|
4232
|
-
promptSuggestionMode,
|
|
4233
|
-
recapAfterSeconds,
|
|
4234
|
-
});
|
|
3934
|
+
const { patch } = parsed;
|
|
3935
|
+
await deps.sessionMetadataService.updateMetadata(sessionId, patch);
|
|
4235
3936
|
// Emit SSE event so sidebar and other clients can update
|
|
4236
3937
|
if (deps.eventBus) {
|
|
4237
3938
|
deps.eventBus.emit({
|
|
4238
3939
|
type: "session-metadata-changed",
|
|
4239
3940
|
sessionId,
|
|
4240
|
-
title:
|
|
4241
|
-
archived:
|
|
4242
|
-
starred:
|
|
4243
|
-
parentSessionId,
|
|
4244
|
-
heartbeatTurnsEnabled:
|
|
4245
|
-
heartbeatTurnsAfterMinutes,
|
|
4246
|
-
heartbeatTurnText,
|
|
4247
|
-
heartbeatForceAfterMinutes,
|
|
4248
|
-
promptSuggestionMode: promptSuggestionMode ?? undefined,
|
|
4249
|
-
recapAfterSeconds: recapAfterSeconds ?? undefined,
|
|
3941
|
+
title: patch.title,
|
|
3942
|
+
archived: patch.archived,
|
|
3943
|
+
starred: patch.starred,
|
|
3944
|
+
parentSessionId: patch.parentSessionId,
|
|
3945
|
+
heartbeatTurnsEnabled: patch.heartbeatTurnsEnabled,
|
|
3946
|
+
heartbeatTurnsAfterMinutes: patch.heartbeatTurnsAfterMinutes,
|
|
3947
|
+
heartbeatTurnText: patch.heartbeatTurnText,
|
|
3948
|
+
heartbeatForceAfterMinutes: patch.heartbeatForceAfterMinutes,
|
|
3949
|
+
promptSuggestionMode: patch.promptSuggestionMode ?? undefined,
|
|
3950
|
+
recapAfterSeconds: patch.recapAfterSeconds ?? undefined,
|
|
4250
3951
|
timestamp: new Date().toISOString(),
|
|
4251
3952
|
});
|
|
4252
3953
|
}
|