@prestyj/cli 5.6.0 → 5.8.0
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/README.md +2 -2
- package/dist/app-sidecar.js +369 -92
- package/dist/app-sidecar.js.map +1 -1
- package/dist/cli/auth.d.ts.map +1 -1
- package/dist/cli/auth.js +5 -2
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli/shared.d.ts.map +1 -1
- package/dist/cli/shared.js +2 -0
- package/dist/cli/shared.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +33 -3
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/config.test.js +7 -0
- package/dist/config.test.js.map +1 -1
- package/dist/core/agent-session-compaction.test.js +521 -10
- package/dist/core/agent-session-compaction.test.js.map +1 -1
- package/dist/core/agent-session-memory-tail.test.js +1 -1
- package/dist/core/agent-session-memory-tail.test.js.map +1 -1
- package/dist/core/agent-session-queue.test.js +1 -1
- package/dist/core/agent-session-queue.test.js.map +1 -1
- package/dist/core/agent-session-review-coverage.test.d.ts +2 -0
- package/dist/core/agent-session-review-coverage.test.d.ts.map +1 -0
- package/dist/core/agent-session-review-coverage.test.js +83 -0
- package/dist/core/agent-session-review-coverage.test.js.map +1 -0
- package/dist/core/agent-session-tool-result-policy.test.d.ts +2 -0
- package/dist/core/agent-session-tool-result-policy.test.d.ts.map +1 -0
- package/dist/core/agent-session-tool-result-policy.test.js +25 -0
- package/dist/core/agent-session-tool-result-policy.test.js.map +1 -0
- package/dist/core/agent-session.d.ts +51 -12
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +415 -106
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-providers.d.ts.map +1 -1
- package/dist/core/auth-providers.js +15 -8
- package/dist/core/auth-providers.js.map +1 -1
- package/dist/core/compaction/active-context.d.ts +17 -0
- package/dist/core/compaction/active-context.d.ts.map +1 -0
- package/dist/core/compaction/active-context.js +20 -0
- package/dist/core/compaction/active-context.js.map +1 -0
- package/dist/core/compaction/active-context.test.d.ts +2 -0
- package/dist/core/compaction/active-context.test.d.ts.map +1 -0
- package/dist/core/compaction/active-context.test.js +36 -0
- package/dist/core/compaction/active-context.test.js.map +1 -0
- package/dist/core/compaction/compactor.d.ts +19 -18
- package/dist/core/compaction/compactor.d.ts.map +1 -1
- package/dist/core/compaction/compactor.js +64 -42
- package/dist/core/compaction/compactor.js.map +1 -1
- package/dist/core/compaction/compactor.test.js +122 -65
- package/dist/core/compaction/compactor.test.js.map +1 -1
- package/dist/core/compaction/token-estimator.d.ts +25 -1
- package/dist/core/compaction/token-estimator.d.ts.map +1 -1
- package/dist/core/compaction/token-estimator.js +86 -1
- package/dist/core/compaction/token-estimator.js.map +1 -1
- package/dist/core/compaction/token-estimator.test.js +147 -1
- package/dist/core/compaction/token-estimator.test.js.map +1 -1
- package/dist/core/compaction/tool-result-pruner.d.ts +37 -0
- package/dist/core/compaction/tool-result-pruner.d.ts.map +1 -0
- package/dist/core/compaction/tool-result-pruner.js +103 -0
- package/dist/core/compaction/tool-result-pruner.js.map +1 -0
- package/dist/core/compaction/tool-result-pruner.test.d.ts +2 -0
- package/dist/core/compaction/tool-result-pruner.test.d.ts.map +1 -0
- package/dist/core/compaction/tool-result-pruner.test.js +148 -0
- package/dist/core/compaction/tool-result-pruner.test.js.map +1 -0
- package/dist/core/event-bus.d.ts +2 -0
- package/dist/core/event-bus.d.ts.map +1 -1
- package/dist/core/event-bus.js.map +1 -1
- package/dist/core/ideal-review.d.ts +33 -0
- package/dist/core/ideal-review.d.ts.map +1 -1
- package/dist/core/ideal-review.js +78 -0
- package/dist/core/ideal-review.js.map +1 -1
- package/dist/core/ideal-review.test.js +43 -1
- package/dist/core/ideal-review.test.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/lsp/client.d.ts +3 -0
- package/dist/core/lsp/client.d.ts.map +1 -1
- package/dist/core/lsp/client.js +20 -0
- package/dist/core/lsp/client.js.map +1 -1
- package/dist/core/lsp/manager.d.ts +32 -9
- package/dist/core/lsp/manager.d.ts.map +1 -1
- package/dist/core/lsp/manager.js +89 -37
- package/dist/core/lsp/manager.js.map +1 -1
- package/dist/core/lsp/manager.test.js +56 -4
- package/dist/core/lsp/manager.test.js.map +1 -1
- package/dist/core/project-discovery.d.ts +6 -9
- package/dist/core/project-discovery.d.ts.map +1 -1
- package/dist/core/project-discovery.js +35 -28
- package/dist/core/project-discovery.js.map +1 -1
- package/dist/core/project-discovery.test.js +148 -0
- package/dist/core/project-discovery.test.js.map +1 -1
- package/dist/core/resolve-start.test.js +1 -0
- package/dist/core/resolve-start.test.js.map +1 -1
- package/dist/core/run-lifecycle.d.ts +40 -0
- package/dist/core/run-lifecycle.d.ts.map +1 -0
- package/dist/core/run-lifecycle.js +95 -0
- package/dist/core/run-lifecycle.js.map +1 -0
- package/dist/core/run-lifecycle.test.d.ts +2 -0
- package/dist/core/run-lifecycle.test.d.ts.map +1 -0
- package/dist/core/run-lifecycle.test.js +64 -0
- package/dist/core/run-lifecycle.test.js.map +1 -0
- package/dist/core/session-compaction.d.ts +3 -0
- package/dist/core/session-compaction.d.ts.map +1 -1
- package/dist/core/session-compaction.js +14 -1
- package/dist/core/session-compaction.js.map +1 -1
- package/dist/core/session-compaction.test.js +5 -0
- package/dist/core/session-compaction.test.js.map +1 -1
- package/dist/core/session-manager.d.ts +33 -2
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +73 -2
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-manager.test.js +97 -2
- package/dist/core/session-manager.test.js.map +1 -1
- package/dist/core/session-preview.d.ts +11 -0
- package/dist/core/session-preview.d.ts.map +1 -0
- package/dist/core/session-preview.js +50 -0
- package/dist/core/session-preview.js.map +1 -0
- package/dist/core/settings-manager.d.ts +1 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +3 -2
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/subagent-manager.d.ts +42 -7
- package/dist/core/subagent-manager.d.ts.map +1 -1
- package/dist/core/subagent-manager.js +346 -30
- package/dist/core/subagent-manager.js.map +1 -1
- package/dist/core/subagent-manager.test.js +201 -5
- package/dist/core/subagent-manager.test.js.map +1 -1
- package/dist/core/subagent-store.d.ts +20 -0
- package/dist/core/subagent-store.d.ts.map +1 -0
- package/dist/core/subagent-store.js +177 -0
- package/dist/core/subagent-store.js.map +1 -0
- package/dist/core/subagent-store.test.d.ts +2 -0
- package/dist/core/subagent-store.test.d.ts.map +1 -0
- package/dist/core/subagent-store.test.js +94 -0
- package/dist/core/subagent-store.test.js.map +1 -0
- package/dist/modes/agent-home-mode.d.ts.map +1 -1
- package/dist/modes/agent-home-mode.js +10 -3
- package/dist/modes/agent-home-mode.js.map +1 -1
- package/dist/modes/serve-mode.d.ts.map +1 -1
- package/dist/modes/serve-mode.js +10 -3
- package/dist/modes/serve-mode.js.map +1 -1
- package/dist/modes/subagent-worker-mode.d.ts +2 -0
- package/dist/modes/subagent-worker-mode.d.ts.map +1 -1
- package/dist/modes/subagent-worker-mode.js +13 -3
- package/dist/modes/subagent-worker-mode.js.map +1 -1
- package/dist/tools/bash.d.ts +9 -0
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +28 -18
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/bash.test.d.ts +2 -0
- package/dist/tools/bash.test.d.ts.map +1 -0
- package/dist/tools/bash.test.js +56 -0
- package/dist/tools/bash.test.js.map +1 -0
- package/dist/tools/goals.d.ts +3 -3
- package/dist/tools/overflow.d.ts +12 -2
- package/dist/tools/overflow.d.ts.map +1 -1
- package/dist/tools/overflow.js +49 -4
- package/dist/tools/overflow.js.map +1 -1
- package/dist/tools/overflow.test.d.ts +2 -0
- package/dist/tools/overflow.test.d.ts.map +1 -0
- package/dist/tools/overflow.test.js +62 -0
- package/dist/tools/overflow.test.js.map +1 -0
- package/dist/tools/subagent-shared.d.ts +8 -0
- package/dist/tools/subagent-shared.d.ts.map +1 -1
- package/dist/tools/subagent-shared.js.map +1 -1
- package/dist/tools/subagent.d.ts +3 -8
- package/dist/tools/subagent.d.ts.map +1 -1
- package/dist/tools/subagent.js +10 -8
- package/dist/tools/subagent.js.map +1 -1
- package/dist/tools/subagent.test.js +17 -1
- package/dist/tools/subagent.test.js.map +1 -1
- package/dist/tools/tasks.d.ts +2 -2
- package/dist/tools/web-fetch.d.ts +1 -1
- package/dist/ui/App.d.ts +7 -3
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +68 -98
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/components/Footer.d.ts +1 -0
- package/dist/ui/components/Footer.d.ts.map +1 -1
- package/dist/ui/components/Footer.js +3 -3
- package/dist/ui/components/Footer.js.map +1 -1
- package/dist/ui/components/Footer.test.d.ts +2 -0
- package/dist/ui/components/Footer.test.d.ts.map +1 -0
- package/dist/ui/components/Footer.test.js +16 -0
- package/dist/ui/components/Footer.test.js.map +1 -0
- package/dist/ui/components/ModelSelector.d.ts.map +1 -1
- package/dist/ui/components/ModelSelector.js +1 -0
- package/dist/ui/components/ModelSelector.js.map +1 -1
- package/dist/ui/components/SubAgentPanel.d.ts +2 -0
- package/dist/ui/components/SubAgentPanel.d.ts.map +1 -1
- package/dist/ui/components/SubAgentPanel.js +4 -2
- package/dist/ui/components/SubAgentPanel.js.map +1 -1
- package/dist/ui/hooks/useAgentLoop.d.ts +9 -6
- package/dist/ui/hooks/useAgentLoop.d.ts.map +1 -1
- package/dist/ui/hooks/useAgentLoop.js +68 -8
- package/dist/ui/hooks/useAgentLoop.js.map +1 -1
- package/dist/ui/hooks/useAgentLoop.test.js +31 -0
- package/dist/ui/hooks/useAgentLoop.test.js.map +1 -1
- package/dist/ui/hooks/useContextCompaction.d.ts +5 -8
- package/dist/ui/hooks/useContextCompaction.d.ts.map +1 -1
- package/dist/ui/hooks/useContextCompaction.js +77 -16
- package/dist/ui/hooks/useContextCompaction.js.map +1 -1
- package/dist/ui/hooks/useContextCompaction.test.d.ts +2 -0
- package/dist/ui/hooks/useContextCompaction.test.d.ts.map +1 -0
- package/dist/ui/hooks/useContextCompaction.test.js +135 -0
- package/dist/ui/hooks/useContextCompaction.test.js.map +1 -0
- package/dist/ui/hooks/useSessionPersistence.d.ts +4 -2
- package/dist/ui/hooks/useSessionPersistence.d.ts.map +1 -1
- package/dist/ui/hooks/useSessionPersistence.js +10 -1
- package/dist/ui/hooks/useSessionPersistence.js.map +1 -1
- package/dist/ui/hooks/useTerminalTitle.d.ts +3 -3
- package/dist/ui/hooks/useTerminalTitle.d.ts.map +1 -1
- package/dist/ui/hooks/useTerminalTitle.js +5 -9
- package/dist/ui/hooks/useTerminalTitle.js.map +1 -1
- package/dist/ui/login.d.ts.map +1 -1
- package/dist/ui/login.js +7 -2
- package/dist/ui/login.js.map +1 -1
- package/dist/ui/render.d.ts +7 -2
- package/dist/ui/render.d.ts.map +1 -1
- package/dist/ui/render.js +4 -4
- package/dist/ui/render.js.map +1 -1
- package/dist/ui/render.test.js +10 -1
- package/dist/ui/render.test.js.map +1 -1
- package/dist/ui/terminal-history.js +6 -2
- package/dist/ui/terminal-history.js.map +1 -1
- package/dist/ui/terminal-history.test.js +2 -2
- package/dist/ui/terminal-history.test.js.map +1 -1
- package/dist/ui/tui-history-parity.test.js +8 -1
- package/dist/ui/tui-history-parity.test.js.map +1 -1
- package/dist/utils/git.d.ts +2 -0
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +12 -0
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/git.test.d.ts +2 -0
- package/dist/utils/git.test.d.ts.map +1 -0
- package/dist/utils/git.test.js +36 -0
- package/dist/utils/git.test.js.map +1 -0
- package/package.json +5 -5
- package/dist/utils/session-title.d.ts +0 -19
- package/dist/utils/session-title.d.ts.map +0 -1
- package/dist/utils/session-title.js +0 -82
- package/dist/utils/session-title.js.map +0 -1
package/dist/ui/App.js
CHANGED
|
@@ -13,6 +13,7 @@ import { useTaskBarStore, useTaskBarPolling, focusTaskBar, exitTaskBar, expandTa
|
|
|
13
13
|
import { playNotificationSound } from "../utils/sound.js";
|
|
14
14
|
import {} from "@prestyj/ai";
|
|
15
15
|
import { downscaleForPreview, extractMediaPaths } from "../utils/image.js";
|
|
16
|
+
import { buildSubAgentCompletionFollowUp, } from "../core/subagent-manager.js";
|
|
16
17
|
import { useAgentLoop } from "./hooks/useAgentLoop.js";
|
|
17
18
|
import { useTranscriptHistory } from "./hooks/useTranscriptHistory.js";
|
|
18
19
|
import { createWebSearchTool } from "../tools/web-search.js";
|
|
@@ -27,7 +28,6 @@ import { getAuthStorageKeys, getModel, getVideoByteLimit } from "../core/model-r
|
|
|
27
28
|
import { SessionManager } from "../core/session-manager.js";
|
|
28
29
|
import { log } from "../core/logger.js";
|
|
29
30
|
import { getPendingUpdate, startPeriodicUpdateCheck, stopPeriodicUpdateCheck, } from "../core/auto-update.js";
|
|
30
|
-
import { generateSessionTitle } from "../utils/session-title.js";
|
|
31
31
|
import { SettingsManager } from "../core/settings-manager.js";
|
|
32
32
|
import { PROMPT_COMMANDS, getPromptCommand } from "../core/prompt-commands.js";
|
|
33
33
|
import { isFirstTimeSetup, markSetupAudited, getAnnouncedLanguages, markLanguagesAnnounced, } from "../core/setup-history.js";
|
|
@@ -234,22 +234,14 @@ export function App(props) {
|
|
|
234
234
|
// measured further down; 0 means "not measured yet" and disables the
|
|
235
235
|
// oversized-item flush below.
|
|
236
236
|
const liveLayoutRef = useRef({ columns, liveAreaRows: 0 });
|
|
237
|
-
// Hoisted before terminal title hook so it can reference them
|
|
238
237
|
const [lastUserMessage, setLastUserMessage] = useState("");
|
|
239
238
|
// Bumped on every prompt submit; the fullscreen transcript scroll controller
|
|
240
239
|
// watches this to snap back to the bottom so the newest output is visible.
|
|
241
240
|
const [scrollResetToken, setScrollResetToken] = useState(0);
|
|
242
241
|
const [exitPending, setExitPending] = useState(false);
|
|
243
242
|
const [quittingSummary, setQuittingSummary] = useState(null);
|
|
244
|
-
//
|
|
245
|
-
// (hoisted here so the hook is always called in the same order)
|
|
243
|
+
// Native terminal title keeps the active project visible outside the app frame.
|
|
246
244
|
const [titleRunning, setTitleRunning] = useState(false);
|
|
247
|
-
const [sessionTitle, setSessionTitle] = useState(() => props.sessionStore?.sessionTitle);
|
|
248
|
-
const sessionTitleGeneratedRef = useRef(props.sessionStore?.sessionTitleGenerated ?? false);
|
|
249
|
-
useTerminalTitle({
|
|
250
|
-
isRunning: titleRunning,
|
|
251
|
-
sessionTitle,
|
|
252
|
-
});
|
|
253
245
|
// Completed transcript rows are kept as durable session data but are no longer
|
|
254
246
|
// rendered through Ink history. They are serialized once into real terminal
|
|
255
247
|
// scrollback via terminalHistoryPrinter, while Ink owns only live rows and
|
|
@@ -353,6 +345,7 @@ export function App(props) {
|
|
|
353
345
|
// Suppress "done" status when a plan overlay is about to open
|
|
354
346
|
const planOverlayPendingRef = useRef(false);
|
|
355
347
|
const [gitBranch, setGitBranch] = useState(null);
|
|
348
|
+
useTerminalTitle({ isRunning: titleRunning, cwd: displayedCwd, gitBranch });
|
|
356
349
|
const [currentModel, setCurrentModel] = useState(props.model);
|
|
357
350
|
const currentModelRef = useRef(props.model);
|
|
358
351
|
const [currentProvider, setCurrentProvider] = useState(props.provider);
|
|
@@ -395,16 +388,13 @@ export function App(props) {
|
|
|
395
388
|
const sessionManagerRef = useRef(props.sessionsDir ? new SessionManager(props.sessionsDir) : null);
|
|
396
389
|
const sessionPathRef = useRef(props.sessionStore?.sessionPath ?? props.sessionPath);
|
|
397
390
|
const persistedIndexRef = useRef(messagesRef.current.length);
|
|
391
|
+
const turnMetricsRef = useRef(props.sessionStore?.turnMetrics ?? []);
|
|
398
392
|
const sessionStatsRef = useRef(props.sessionStore?.sessionStats ??
|
|
399
393
|
createSessionStats({ sessionId: props.sessionStore?.sessionId ?? props.sessionId }));
|
|
400
394
|
const [idealReviewEnabled, setIdealReviewEnabled] = useState(props.sessionStore?.idealReviewEnabled ?? props.idealReviewEnabled ?? true);
|
|
401
395
|
const idealReviewEnabledRef = useRef(idealReviewEnabled);
|
|
402
396
|
const [autoApprovePlansEnabled, setAutoApprovePlansEnabled] = useState(props.sessionStore?.autoApprovePlans ?? props.autoApprovePlans ?? true);
|
|
403
397
|
const autoApprovePlansEnabledRef = useRef(autoApprovePlansEnabled);
|
|
404
|
-
/** Last actual API-reported input token count (from turn_end). */
|
|
405
|
-
const lastActualTokensRef = useRef(0);
|
|
406
|
-
/** Timestamp (ms) when lastActualTokensRef was last updated by turn_end. */
|
|
407
|
-
const lastActualTokensTimestampRef = useRef(0);
|
|
408
398
|
/**
|
|
409
399
|
* Languages whose style packs are currently injected into the system prompt.
|
|
410
400
|
* Grown by `maybeInjectLanguagePacks` after `write`/`bash` tool results when
|
|
@@ -568,10 +558,6 @@ export function App(props) {
|
|
|
568
558
|
if (sessionStore)
|
|
569
559
|
sessionStore.planSteps = planSteps;
|
|
570
560
|
}, [planSteps, sessionStore]);
|
|
571
|
-
useEffect(() => {
|
|
572
|
-
if (sessionStore)
|
|
573
|
-
sessionStore.sessionTitle = sessionTitle;
|
|
574
|
-
}, [sessionTitle, sessionStore]);
|
|
575
561
|
useEffect(() => {
|
|
576
562
|
if (sessionStore)
|
|
577
563
|
sessionStore.overlay = overlay;
|
|
@@ -609,9 +595,9 @@ export function App(props) {
|
|
|
609
595
|
.map((key) => props.credentialsByProvider?.[key])
|
|
610
596
|
.find((c) => c !== undefined);
|
|
611
597
|
const activeApiKey = currentCreds?.accessToken ?? props.apiKey;
|
|
612
|
-
const activeAccountId = currentCreds
|
|
613
|
-
const activeProjectId = currentCreds
|
|
614
|
-
const activeBaseUrl = currentProvider === "gemini" ? undefined :
|
|
598
|
+
const activeAccountId = currentCreds ? currentCreds.accountId : props.accountId;
|
|
599
|
+
const activeProjectId = currentCreds ? currentCreds.projectId : props.projectId;
|
|
600
|
+
const activeBaseUrl = currentProvider === "gemini" ? undefined : currentCreds ? currentCreds.baseUrl : props.baseUrl;
|
|
615
601
|
const contextWindowOptions = useMemo(() => ({ provider: currentProvider, accountId: activeAccountId }), [currentProvider, activeAccountId]);
|
|
616
602
|
// Load git branch — re-runs whenever the displayed cwd changes (e.g. when
|
|
617
603
|
// a pixel fix moves the agent into a different project root).
|
|
@@ -790,16 +776,19 @@ export function App(props) {
|
|
|
790
776
|
useEffect(() => {
|
|
791
777
|
void applyLanguageDetectionRef.current("initial");
|
|
792
778
|
}, []);
|
|
779
|
+
const rebindSubagentsAfterCompaction = useCallback((sessionId) => props.subAgentManager?.rebindParentSession(sessionId) ?? Promise.resolve(), [props.subAgentManager]);
|
|
793
780
|
const { persistCompactedSession, persistNewMessages } = useSessionPersistence({
|
|
794
781
|
sessionManagerRef,
|
|
795
782
|
sessionPathRef,
|
|
796
783
|
sessionStatsRef,
|
|
797
784
|
persistedIndexRef,
|
|
798
785
|
messagesRef,
|
|
786
|
+
turnMetricsRef,
|
|
799
787
|
cwdRef,
|
|
800
788
|
currentProvider,
|
|
801
789
|
currentModel,
|
|
802
790
|
sessionStore,
|
|
791
|
+
onCompactedSession: rebindSubagentsAfterCompaction,
|
|
803
792
|
});
|
|
804
793
|
/**
|
|
805
794
|
* Run the language detector against the current cwd. If the detected set is a
|
|
@@ -835,10 +824,9 @@ export function App(props) {
|
|
|
835
824
|
});
|
|
836
825
|
}
|
|
837
826
|
}, [props.settingsFile]);
|
|
838
|
-
const { compactionAbortRef, compactConversation, transformContext } = useContextCompaction({
|
|
827
|
+
const { compactionAbortRef, compactConversation, transformContext, recordProviderUsage } = useContextCompaction({
|
|
839
828
|
currentModel,
|
|
840
829
|
currentProvider,
|
|
841
|
-
maxTokens: props.maxTokens,
|
|
842
830
|
authStorage: props.authStorage,
|
|
843
831
|
contextWindowOptions,
|
|
844
832
|
activeApiKey,
|
|
@@ -850,8 +838,6 @@ export function App(props) {
|
|
|
850
838
|
approvedPlanPathRef,
|
|
851
839
|
settingsRef,
|
|
852
840
|
messagesRef,
|
|
853
|
-
lastActualTokensRef,
|
|
854
|
-
lastActualTokensTimestampRef,
|
|
855
841
|
persistCompactedSession,
|
|
856
842
|
});
|
|
857
843
|
// ── Background task bar state (external store) ──────────
|
|
@@ -904,6 +890,8 @@ export function App(props) {
|
|
|
904
890
|
projectId: activeProjectId,
|
|
905
891
|
resolveCredentials,
|
|
906
892
|
transformContext,
|
|
893
|
+
lspManager: props.lspManager,
|
|
894
|
+
reviewCoverageTracker: props.reviewCoverageTracker,
|
|
907
895
|
getIdealReviewMessage: (stats, touchedFiles) => {
|
|
908
896
|
if (!idealReviewEnabledRef.current)
|
|
909
897
|
return null;
|
|
@@ -961,56 +949,7 @@ export function App(props) {
|
|
|
961
949
|
// Rebuild system prompt to remove the completed plan from context
|
|
962
950
|
void replaceSystemPrompt({ clearApprovedPlan: true });
|
|
963
951
|
}
|
|
964
|
-
|
|
965
|
-
if (!sessionTitleGeneratedRef.current) {
|
|
966
|
-
sessionTitleGeneratedRef.current = true;
|
|
967
|
-
const msgs = messagesRef.current;
|
|
968
|
-
// Find the first user message and first assistant text
|
|
969
|
-
const userMsg = msgs.find((m) => m.role === "user");
|
|
970
|
-
const assistantMsg = msgs.find((m) => m.role === "assistant");
|
|
971
|
-
const userText = typeof userMsg?.content === "string"
|
|
972
|
-
? userMsg.content
|
|
973
|
-
: Array.isArray(userMsg?.content)
|
|
974
|
-
? userMsg.content
|
|
975
|
-
.filter((c) => c.type === "text")
|
|
976
|
-
.map((c) => c.text)
|
|
977
|
-
.join(" ")
|
|
978
|
-
: "";
|
|
979
|
-
const assistantText = typeof assistantMsg?.content === "string"
|
|
980
|
-
? assistantMsg.content
|
|
981
|
-
: Array.isArray(assistantMsg?.content)
|
|
982
|
-
? assistantMsg.content
|
|
983
|
-
.filter((c) => c.type === "text")
|
|
984
|
-
.map((c) => c.text)
|
|
985
|
-
.join(" ")
|
|
986
|
-
: "";
|
|
987
|
-
if (userText) {
|
|
988
|
-
generateSessionTitle({
|
|
989
|
-
provider: currentProvider,
|
|
990
|
-
userMessage: userText,
|
|
991
|
-
assistantPreview: assistantText.slice(0, 200),
|
|
992
|
-
apiKey: activeApiKey,
|
|
993
|
-
baseUrl: activeBaseUrl,
|
|
994
|
-
accountId: activeAccountId,
|
|
995
|
-
resolveCredentials,
|
|
996
|
-
}).then((title) => {
|
|
997
|
-
setSessionTitle(title);
|
|
998
|
-
log("INFO", "title", `Session title generated: ${title}`);
|
|
999
|
-
}, () => {
|
|
1000
|
-
// Best-effort — silently ignore failures
|
|
1001
|
-
});
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
}, [
|
|
1005
|
-
persistNewMessages,
|
|
1006
|
-
props.cwd,
|
|
1007
|
-
props.skills,
|
|
1008
|
-
currentProvider,
|
|
1009
|
-
activeApiKey,
|
|
1010
|
-
activeAccountId,
|
|
1011
|
-
activeBaseUrl,
|
|
1012
|
-
resolveCredentials,
|
|
1013
|
-
]),
|
|
952
|
+
}, [persistNewMessages, props.cwd, props.skills]),
|
|
1014
953
|
onTurnText: useCallback((text, thinking, thinkingMs) => {
|
|
1015
954
|
const hadStreamedAssistantFlush = streamedAssistantFlushRef.current.flushedChars > 0;
|
|
1016
955
|
const unflushedAssistantText = text.slice(streamedAssistantFlushRef.current.flushedChars);
|
|
@@ -1490,22 +1429,39 @@ export function App(props) {
|
|
|
1490
1429
|
return remaining;
|
|
1491
1430
|
});
|
|
1492
1431
|
}, [queueFlush]),
|
|
1493
|
-
onTurnEnd: useCallback((turn, stopReason, usage) => {
|
|
1432
|
+
onTurnEnd: useCallback((turn, stopReason, usage, timing) => {
|
|
1433
|
+
recordProviderUsage(usage, messagesRef.current);
|
|
1494
1434
|
recordTurnEnd(sessionStatsRef.current, usage);
|
|
1435
|
+
const metric = {
|
|
1436
|
+
version: 1,
|
|
1437
|
+
turn,
|
|
1438
|
+
provider: currentProvider,
|
|
1439
|
+
model: currentModel,
|
|
1440
|
+
stopReason,
|
|
1441
|
+
usage: { ...usage },
|
|
1442
|
+
timing: { ...timing },
|
|
1443
|
+
cost: {
|
|
1444
|
+
status: "unavailable",
|
|
1445
|
+
reason: "No authoritative effective-dated provider pricing is available",
|
|
1446
|
+
},
|
|
1447
|
+
};
|
|
1448
|
+
turnMetricsRef.current.push(metric);
|
|
1449
|
+
if (sessionStore)
|
|
1450
|
+
sessionStore.turnMetrics = [...turnMetricsRef.current];
|
|
1451
|
+
const metricSessionPath = sessionPathRef.current;
|
|
1452
|
+
const metricManager = sessionManagerRef.current;
|
|
1453
|
+
if (metricSessionPath && metricManager) {
|
|
1454
|
+
void metricManager.appendTurnMetric(metricSessionPath, metric);
|
|
1455
|
+
}
|
|
1495
1456
|
log("INFO", "turn", `Turn ${turn} ended`, {
|
|
1496
1457
|
stopReason,
|
|
1497
1458
|
inputTokens: String(usage.inputTokens),
|
|
1498
1459
|
outputTokens: String(usage.outputTokens),
|
|
1499
1460
|
...(usage.cacheRead != null && { cacheRead: String(usage.cacheRead) }),
|
|
1500
1461
|
...(usage.cacheWrite != null && { cacheWrite: String(usage.cacheWrite) }),
|
|
1462
|
+
providerDurationMs: String(timing.providerDurationMs),
|
|
1463
|
+
...(timing.ttftMs != null && { ttftMs: String(timing.ttftMs) }),
|
|
1501
1464
|
});
|
|
1502
|
-
// Track actual token count for compaction decisions.
|
|
1503
|
-
// Anthropic has separate input/output limits — only count input.
|
|
1504
|
-
// All other providers share the context window — count both.
|
|
1505
|
-
const inputContext = usage.inputTokens + (usage.cacheRead ?? 0) + (usage.cacheWrite ?? 0);
|
|
1506
|
-
lastActualTokensRef.current =
|
|
1507
|
-
currentProvider === "anthropic" ? inputContext : inputContext + usage.outputTokens;
|
|
1508
|
-
lastActualTokensTimestampRef.current = Date.now();
|
|
1509
1465
|
// For tool-only turns (no text), flush completed items to finalized
|
|
1510
1466
|
// history so liveItems doesn't grow unbounded across consecutive turns.
|
|
1511
1467
|
setLiveItems((prev) => {
|
|
@@ -1515,7 +1471,7 @@ export function App(props) {
|
|
|
1515
1471
|
}
|
|
1516
1472
|
return remaining;
|
|
1517
1473
|
});
|
|
1518
|
-
}, [queueFlush]),
|
|
1474
|
+
}, [currentModel, currentProvider, queueFlush, recordProviderUsage, sessionStore]),
|
|
1519
1475
|
onDone: useCallback((durationMs, toolsUsed, runStats) => {
|
|
1520
1476
|
log("INFO", "agent", `Agent done`, {
|
|
1521
1477
|
duration: `${durationMs}ms`,
|
|
@@ -1688,6 +1644,9 @@ export function App(props) {
|
|
|
1688
1644
|
// natural completion boundary regardless. The stuck-guard caps
|
|
1689
1645
|
// nudges per step so a genuinely blocked agent surfaces.
|
|
1690
1646
|
getFollowUpMessages: useCallback(() => {
|
|
1647
|
+
const childCompletionFollowUp = buildSubAgentCompletionFollowUp(props.subAgentManager);
|
|
1648
|
+
if (childCompletionFollowUp)
|
|
1649
|
+
return childCompletionFollowUp;
|
|
1691
1650
|
const steps = planStepsRef.current;
|
|
1692
1651
|
if (steps.length === 0 || !approvedPlanPathRef.current)
|
|
1693
1652
|
return null;
|
|
@@ -1711,7 +1670,7 @@ export function App(props) {
|
|
|
1711
1670
|
`or you genuinely need user input.`,
|
|
1712
1671
|
},
|
|
1713
1672
|
];
|
|
1714
|
-
}, []),
|
|
1673
|
+
}, [props.subAgentManager]),
|
|
1715
1674
|
onRetry: useCallback(() => {
|
|
1716
1675
|
// Roll back any pending progressive flushes from the aborted attempt.
|
|
1717
1676
|
// Without this, a stall retry regenerates the preamble and the old
|
|
@@ -2251,8 +2210,6 @@ export function App(props) {
|
|
|
2251
2210
|
persistedIndexRef.current = messagesRef.current.length;
|
|
2252
2211
|
})();
|
|
2253
2212
|
agentLoop.reset();
|
|
2254
|
-
setSessionTitle(undefined);
|
|
2255
|
-
sessionTitleGeneratedRef.current = false;
|
|
2256
2213
|
setLiveItems([{ kind: "info", text: "Session cleared.", id: getId() }]);
|
|
2257
2214
|
},
|
|
2258
2215
|
openThemeSelector: () => setOverlay("theme"),
|
|
@@ -2786,6 +2743,10 @@ export function App(props) {
|
|
|
2786
2743
|
try {
|
|
2787
2744
|
const session = await sm.create(taskCwd, currentProvider, currentModel);
|
|
2788
2745
|
newSessionPath = session.path;
|
|
2746
|
+
sessionStatsRef.current.sessionId = session.id;
|
|
2747
|
+
if (props.sessionStore)
|
|
2748
|
+
props.sessionStore.sessionId = session.id;
|
|
2749
|
+
await props.subAgentManager?.resetParentSession(session.id);
|
|
2789
2750
|
log("INFO", "tasks", "New session for task", { path: session.path });
|
|
2790
2751
|
}
|
|
2791
2752
|
catch {
|
|
@@ -2811,22 +2772,27 @@ export function App(props) {
|
|
|
2811
2772
|
agentLoop.reset();
|
|
2812
2773
|
persistedIndexRef.current = messagesRef.current.length;
|
|
2813
2774
|
const sm = sessionManagerRef.current;
|
|
2814
|
-
if (sm) {
|
|
2815
|
-
void sm.create(taskCwd, currentProvider, currentModel).then((session) => {
|
|
2816
|
-
sessionPathRef.current = session.path;
|
|
2817
|
-
log("INFO", "tasks", "New session for task", { path: session.path });
|
|
2818
|
-
});
|
|
2819
|
-
}
|
|
2820
2775
|
const taskItem = { kind: "task", title, id: getId() };
|
|
2821
2776
|
setLastUserMessage(title);
|
|
2822
2777
|
setDoneStatus(null);
|
|
2823
2778
|
setLiveItems([taskItem]);
|
|
2824
|
-
void
|
|
2825
|
-
|
|
2826
|
-
|
|
2779
|
+
void (async () => {
|
|
2780
|
+
try {
|
|
2781
|
+
if (sm) {
|
|
2782
|
+
const session = await sm.create(taskCwd, currentProvider, currentModel);
|
|
2783
|
+
sessionPathRef.current = session.path;
|
|
2784
|
+
sessionStatsRef.current.sessionId = session.id;
|
|
2785
|
+
await props.subAgentManager?.resetParentSession(session.id);
|
|
2786
|
+
log("INFO", "tasks", "New session for task", { path: session.path });
|
|
2787
|
+
}
|
|
2788
|
+
await agentLoop.run(fullPrompt);
|
|
2827
2789
|
}
|
|
2828
|
-
|
|
2829
|
-
|
|
2790
|
+
catch (err) {
|
|
2791
|
+
if (agentLoop.isRunning)
|
|
2792
|
+
agentLoop.reset();
|
|
2793
|
+
setLiveItems((prev) => [...prev, toErrorItem(err, getId())]);
|
|
2794
|
+
}
|
|
2795
|
+
})();
|
|
2830
2796
|
}, [agentLoop, currentModel, currentProvider, props]);
|
|
2831
2797
|
// Keep the ref in sync so stale closures (task picker, onDone run-all) can
|
|
2832
2798
|
// start a task without being recreated each render.
|
|
@@ -3408,6 +3374,10 @@ export function App(props) {
|
|
|
3408
3374
|
if (sm) {
|
|
3409
3375
|
const s = await sm.create(props.cwd, currentProvider, currentModel);
|
|
3410
3376
|
newSessionPath = s.path;
|
|
3377
|
+
sessionStatsRef.current.sessionId = s.id;
|
|
3378
|
+
if (props.sessionStore)
|
|
3379
|
+
props.sessionStore.sessionId = s.id;
|
|
3380
|
+
await props.subAgentManager?.resetParentSession(s.id);
|
|
3411
3381
|
}
|
|
3412
3382
|
if (props.resetUI && props.sessionStore) {
|
|
3413
3383
|
// Clear the overlay so the new mount lands on the chat,
|