@kenkaiiii/ggcoder 2.0.0 → 3.0.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/dist/cli.js +12 -3
- package/dist/cli.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +1 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/compactor.d.ts +8 -2
- package/dist/core/compaction/compactor.d.ts.map +1 -1
- package/dist/core/compaction/compactor.js +147 -18
- package/dist/core/compaction/compactor.js.map +1 -1
- package/dist/core/custom-commands.d.ts +13 -0
- package/dist/core/custom-commands.d.ts.map +1 -0
- package/dist/core/custom-commands.js +40 -0
- package/dist/core/custom-commands.js.map +1 -0
- package/dist/core/event-bus.d.ts +4 -0
- package/dist/core/event-bus.d.ts.map +1 -1
- package/dist/core/event-bus.js.map +1 -1
- package/dist/core/logger.d.ts +1 -0
- package/dist/core/logger.d.ts.map +1 -1
- package/dist/core/logger.js +6 -0
- package/dist/core/logger.js.map +1 -1
- package/dist/core/model-registry.d.ts +7 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +21 -3
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/prompt-commands.d.ts +14 -0
- package/dist/core/prompt-commands.d.ts.map +1 -0
- package/dist/core/prompt-commands.js +475 -0
- package/dist/core/prompt-commands.js.map +1 -0
- package/dist/core/settings-manager.d.ts +2 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +3 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/system-prompt.d.ts.map +1 -1
- package/dist/system-prompt.js +9 -5
- package/dist/system-prompt.js.map +1 -1
- package/dist/ui/App.d.ts +15 -1
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +272 -24
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/components/AssistantMessage.d.ts +2 -1
- package/dist/ui/components/AssistantMessage.d.ts.map +1 -1
- package/dist/ui/components/AssistantMessage.js +3 -2
- package/dist/ui/components/AssistantMessage.js.map +1 -1
- package/dist/ui/components/Banner.d.ts.map +1 -1
- package/dist/ui/components/Banner.js +27 -6
- package/dist/ui/components/Banner.js.map +1 -1
- package/dist/ui/components/CompactionNotice.d.ts +10 -0
- package/dist/ui/components/CompactionNotice.d.ts.map +1 -0
- package/dist/ui/components/CompactionNotice.js +31 -0
- package/dist/ui/components/CompactionNotice.js.map +1 -0
- package/dist/ui/components/Footer.d.ts +2 -1
- package/dist/ui/components/Footer.d.ts.map +1 -1
- package/dist/ui/components/Footer.js +9 -5
- package/dist/ui/components/Footer.js.map +1 -1
- package/dist/ui/components/InputArea.d.ts +7 -2
- package/dist/ui/components/InputArea.d.ts.map +1 -1
- package/dist/ui/components/InputArea.js +120 -8
- package/dist/ui/components/InputArea.js.map +1 -1
- package/dist/ui/components/SlashCommandMenu.d.ts +15 -0
- package/dist/ui/components/SlashCommandMenu.d.ts.map +1 -0
- package/dist/ui/components/SlashCommandMenu.js +32 -0
- package/dist/ui/components/SlashCommandMenu.js.map +1 -0
- package/dist/ui/components/StreamingArea.d.ts +2 -1
- package/dist/ui/components/StreamingArea.d.ts.map +1 -1
- package/dist/ui/components/StreamingArea.js +15 -3
- package/dist/ui/components/StreamingArea.js.map +1 -1
- package/dist/ui/components/SubAgentPanel.d.ts.map +1 -1
- package/dist/ui/components/SubAgentPanel.js +54 -16
- package/dist/ui/components/SubAgentPanel.js.map +1 -1
- package/dist/ui/components/ThinkingBlock.d.ts +11 -0
- package/dist/ui/components/ThinkingBlock.d.ts.map +1 -0
- package/dist/ui/components/ThinkingBlock.js +40 -0
- package/dist/ui/components/ThinkingBlock.js.map +1 -0
- package/dist/ui/components/ToolExecution.d.ts.map +1 -1
- package/dist/ui/components/ToolExecution.js +22 -5
- package/dist/ui/components/ToolExecution.js.map +1 -1
- package/dist/ui/components/UserMessage.d.ts +2 -1
- package/dist/ui/components/UserMessage.d.ts.map +1 -1
- package/dist/ui/components/UserMessage.js +4 -2
- package/dist/ui/components/UserMessage.js.map +1 -1
- package/dist/ui/hooks/useAgentLoop.d.ts +6 -3
- package/dist/ui/hooks/useAgentLoop.d.ts.map +1 -1
- package/dist/ui/hooks/useAgentLoop.js +1 -1
- package/dist/ui/hooks/useAgentLoop.js.map +1 -1
- package/dist/ui/render.d.ts.map +1 -1
- package/dist/ui/render.js +22 -2
- package/dist/ui/render.js.map +1 -1
- package/dist/ui/theme/dark.json +2 -1
- package/dist/ui/theme/light.json +2 -1
- package/dist/ui/theme/theme.d.ts +1 -0
- package/dist/ui/theme/theme.d.ts.map +1 -1
- package/dist/utils/image.d.ts +24 -0
- package/dist/utils/image.d.ts.map +1 -0
- package/dist/utils/image.js +137 -0
- package/dist/utils/image.js.map +1 -0
- package/package.json +3 -3
|
@@ -8,7 +8,8 @@ const SettingsSchema = z.object({
|
|
|
8
8
|
defaultProvider: z.enum(["anthropic", "openai", "glm", "moonshot"]).default("anthropic"),
|
|
9
9
|
defaultModel: z.string().optional(),
|
|
10
10
|
maxTokens: z.number().int().min(256).default(16384),
|
|
11
|
-
|
|
11
|
+
thinkingEnabled: z.boolean().default(false),
|
|
12
|
+
thinkingLevel: z.enum(["low", "medium", "high", "max"]).optional(),
|
|
12
13
|
theme: z.enum(["dark", "light"]).default("dark"),
|
|
13
14
|
showTokenUsage: z.boolean().default(true),
|
|
14
15
|
showThinking: z.boolean().default(true),
|
|
@@ -19,6 +20,7 @@ export const DEFAULT_SETTINGS = {
|
|
|
19
20
|
compactThreshold: 0.8,
|
|
20
21
|
defaultProvider: "anthropic",
|
|
21
22
|
maxTokens: 16384,
|
|
23
|
+
thinkingEnabled: false,
|
|
22
24
|
theme: "dark",
|
|
23
25
|
showTokenUsage: true,
|
|
24
26
|
showThinking: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-manager.js","sourceRoot":"","sources":["../../src/core/settings-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,8DAA8D;AAE9D,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,WAAW,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IACtC,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;IAC3D,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;IACxF,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACnC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;IACnD,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE;
|
|
1
|
+
{"version":3,"file":"settings-manager.js","sourceRoot":"","sources":["../../src/core/settings-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../src/system-prompt.ts"],"names":[],"mappings":"AAEA,OAAO,EAAyB,KAAK,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAIrE;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../src/system-prompt.ts"],"names":[],"mappings":"AAEA,OAAO,EAAyB,KAAK,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAIrE;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAgItF"}
|
package/dist/system-prompt.js
CHANGED
|
@@ -98,11 +98,15 @@ export async function buildSystemPrompt(cwd, skills) {
|
|
|
98
98
|
sections.push(skillsSection);
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
|
-
// 9. Environment
|
|
102
|
-
sections.push(`## Environment\n\n` +
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
101
|
+
// 9. Environment (static — cacheable)
|
|
102
|
+
sections.push(`## Environment\n\n` + `- Working directory: ${cwd}\n` + `- Platform: ${process.platform}`);
|
|
103
|
+
// Dynamic section (uncached) — separated by marker so the transform layer
|
|
104
|
+
// can split the system prompt into cached + uncached blocks.
|
|
105
|
+
const today = new Date();
|
|
106
|
+
const day = today.getDate();
|
|
107
|
+
const month = today.toLocaleString("en-US", { month: "long" });
|
|
108
|
+
const year = today.getFullYear();
|
|
109
|
+
sections.push(`<!-- uncached -->\nToday's date: ${day} ${month} ${year}`);
|
|
106
110
|
return sections.join("\n\n");
|
|
107
111
|
}
|
|
108
112
|
//# sourceMappingURL=system-prompt.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../src/system-prompt.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../src/system-prompt.ts"],"names":[],"mappings":"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"}
|
package/dist/ui/App.d.ts
CHANGED
|
@@ -5,12 +5,14 @@ import type { ProcessManager } from "../core/process-manager.js";
|
|
|
5
5
|
interface UserItem {
|
|
6
6
|
kind: "user";
|
|
7
7
|
text: string;
|
|
8
|
+
imageCount?: number;
|
|
8
9
|
id: string;
|
|
9
10
|
}
|
|
10
11
|
interface AssistantItem {
|
|
11
12
|
kind: "assistant";
|
|
12
13
|
text: string;
|
|
13
14
|
thinking?: string;
|
|
15
|
+
thinkingMs?: number;
|
|
14
16
|
id: string;
|
|
15
17
|
}
|
|
16
18
|
interface ToolStartItem {
|
|
@@ -39,6 +41,18 @@ interface InfoItem {
|
|
|
39
41
|
text: string;
|
|
40
42
|
id: string;
|
|
41
43
|
}
|
|
44
|
+
interface CompactingItem {
|
|
45
|
+
kind: "compacting";
|
|
46
|
+
id: string;
|
|
47
|
+
}
|
|
48
|
+
interface CompactedItem {
|
|
49
|
+
kind: "compacted";
|
|
50
|
+
originalCount: number;
|
|
51
|
+
newCount: number;
|
|
52
|
+
tokensBefore: number;
|
|
53
|
+
tokensAfter: number;
|
|
54
|
+
id: string;
|
|
55
|
+
}
|
|
42
56
|
interface DurationItem {
|
|
43
57
|
kind: "duration";
|
|
44
58
|
durationMs: number;
|
|
@@ -71,7 +85,7 @@ interface ServerToolDoneItem {
|
|
|
71
85
|
data: unknown;
|
|
72
86
|
id: string;
|
|
73
87
|
}
|
|
74
|
-
export type CompletedItem = UserItem | AssistantItem | ToolStartItem | ToolDoneItem | ServerToolStartItem | ServerToolDoneItem | ErrorItem | InfoItem | DurationItem | BannerItem | SubAgentGroupItem;
|
|
88
|
+
export type CompletedItem = UserItem | AssistantItem | ToolStartItem | ToolDoneItem | ServerToolStartItem | ServerToolDoneItem | ErrorItem | InfoItem | CompactingItem | CompactedItem | DurationItem | BannerItem | SubAgentGroupItem;
|
|
75
89
|
export interface AppProps {
|
|
76
90
|
provider: Provider;
|
|
77
91
|
model: string;
|
package/dist/ui/App.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/ui/App.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/ui/App.tsx"],"names":[],"mappings":"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"}
|
package/dist/ui/App.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React, { useState, useRef, useCallback, useEffect } from "react";
|
|
2
|
+
import React, { useState, useRef, useCallback, useEffect, useMemo } from "react";
|
|
3
3
|
import { Box, Text, Static, useStdout } from "ink";
|
|
4
4
|
import crypto from "node:crypto";
|
|
5
|
+
import { extractImagePaths } from "../utils/image.js";
|
|
5
6
|
import { useAgentLoop } from "./hooks/useAgentLoop.js";
|
|
6
7
|
import { UserMessage } from "./components/UserMessage.js";
|
|
7
8
|
import { AssistantMessage } from "./components/AssistantMessage.js";
|
|
8
9
|
import { ToolExecution } from "./components/ToolExecution.js";
|
|
9
10
|
import { ServerToolExecution } from "./components/ServerToolExecution.js";
|
|
10
11
|
import { SubAgentPanel } from "./components/SubAgentPanel.js";
|
|
12
|
+
import { CompactionSpinner, CompactionDone } from "./components/CompactionNotice.js";
|
|
11
13
|
import { StreamingArea } from "./components/StreamingArea.js";
|
|
12
14
|
import { ActivityIndicator } from "./components/ActivityIndicator.js";
|
|
13
15
|
import { InputArea } from "./components/InputArea.js";
|
|
@@ -18,10 +20,14 @@ import { BackgroundTasksBar } from "./components/BackgroundTasksBar.js";
|
|
|
18
20
|
import { useTheme } from "./theme/theme.js";
|
|
19
21
|
import { useTerminalTitle } from "./hooks/useTerminalTitle.js";
|
|
20
22
|
import { getGitBranch } from "../utils/git.js";
|
|
21
|
-
import { getModel } from "../core/model-registry.js";
|
|
23
|
+
import { getModel, getContextWindow } from "../core/model-registry.js";
|
|
22
24
|
import { SessionManager } from "../core/session-manager.js";
|
|
23
25
|
import { log } from "../core/logger.js";
|
|
24
26
|
import { SettingsManager } from "../core/settings-manager.js";
|
|
27
|
+
import { shouldCompact, compact } from "../core/compaction/compactor.js";
|
|
28
|
+
import { estimateConversationTokens } from "../core/compaction/token-estimator.js";
|
|
29
|
+
import { PROMPT_COMMANDS, getPromptCommand } from "../core/prompt-commands.js";
|
|
30
|
+
import { loadCustomCommands } from "../core/custom-commands.js";
|
|
25
31
|
// ── Duration summary ─────────────────────────────────────
|
|
26
32
|
function formatDuration(ms) {
|
|
27
33
|
const totalSec = Math.round(ms / 1000);
|
|
@@ -71,29 +77,36 @@ function pickDurationVerb(toolsUsed) {
|
|
|
71
77
|
];
|
|
72
78
|
return phrases[Math.floor(Math.random() * phrases.length)];
|
|
73
79
|
}
|
|
80
|
+
// ── Animated thinking border ────────────────────────────────
|
|
81
|
+
const THINKING_BORDER_COLORS = ["#60a5fa", "#818cf8", "#a78bfa", "#818cf8", "#60a5fa"];
|
|
74
82
|
// ── App Component ──────────────────────────────────────────
|
|
75
83
|
export function App(props) {
|
|
76
84
|
const theme = useTheme();
|
|
85
|
+
const { stdout } = useStdout();
|
|
77
86
|
// Terminal title — updated later after agentLoop is created
|
|
78
87
|
// (hoisted here so the hook is always called in the same order)
|
|
79
88
|
const [titlePhase, setTitlePhase] = useState("idle");
|
|
80
89
|
const [titleRunning, setTitleRunning] = useState(false);
|
|
81
90
|
useTerminalTitle(titlePhase, titleRunning);
|
|
82
|
-
// Items scrolled into Static (history)
|
|
83
|
-
|
|
84
|
-
//
|
|
85
|
-
const
|
|
91
|
+
// Items scrolled into Static (history) — banner and restored history go here
|
|
92
|
+
// immediately so they are rendered once and don't cause live-area redraws
|
|
93
|
+
// (which produce visual duplicates on terminal resize).
|
|
94
|
+
const initialHistory = props.initialHistory
|
|
86
95
|
? [{ kind: "banner", id: "banner" }, ...props.initialHistory]
|
|
87
96
|
: [{ kind: "banner", id: "banner" }];
|
|
88
|
-
const [
|
|
97
|
+
const [history, setHistory] = useState(initialHistory);
|
|
98
|
+
// Items from the current/last turn — rendered in the live area so they stay visible
|
|
99
|
+
const [liveItems, setLiveItems] = useState([]);
|
|
89
100
|
const [overlay, setOverlay] = useState(null);
|
|
90
101
|
const [lastUserMessage, setLastUserMessage] = useState("");
|
|
91
102
|
const [doneStatus, setDoneStatus] = useState(null);
|
|
92
103
|
const [gitBranch, setGitBranch] = useState(null);
|
|
93
104
|
const [currentModel, setCurrentModel] = useState(props.model);
|
|
94
105
|
const [currentProvider, setCurrentProvider] = useState(props.provider);
|
|
106
|
+
const [thinkingEnabled, setThinkingEnabled] = useState(!!props.thinking);
|
|
95
107
|
const messagesRef = useRef(props.messages);
|
|
96
108
|
const nextIdRef = useRef(0);
|
|
109
|
+
const wasRunningRef = useRef(false);
|
|
97
110
|
const sessionManagerRef = useRef(props.sessionsDir ? new SessionManager(props.sessionsDir) : null);
|
|
98
111
|
const persistedIndexRef = useRef(messagesRef.current.length);
|
|
99
112
|
const getId = () => String(nextIdRef.current++);
|
|
@@ -105,6 +118,14 @@ export function App(props) {
|
|
|
105
118
|
useEffect(() => {
|
|
106
119
|
getGitBranch(props.cwd).then(setGitBranch);
|
|
107
120
|
}, [props.cwd]);
|
|
121
|
+
// Load custom commands from .gg/commands/
|
|
122
|
+
const [customCommands, setCustomCommands] = useState([]);
|
|
123
|
+
const reloadCustomCommands = useCallback(() => {
|
|
124
|
+
loadCustomCommands(props.cwd).then(setCustomCommands);
|
|
125
|
+
}, [props.cwd]);
|
|
126
|
+
useEffect(() => {
|
|
127
|
+
reloadCustomCommands();
|
|
128
|
+
}, [reloadCustomCommands]);
|
|
108
129
|
const persistNewMessages = useCallback(async () => {
|
|
109
130
|
const sm = sessionManagerRef.current;
|
|
110
131
|
const sp = props.sessionPath;
|
|
@@ -126,6 +147,76 @@ export function App(props) {
|
|
|
126
147
|
}
|
|
127
148
|
persistedIndexRef.current = allMsgs.length;
|
|
128
149
|
}, [props.sessionPath]);
|
|
150
|
+
// ── Compaction ─────────────────────────────────────────
|
|
151
|
+
// Load settings for auto-compaction
|
|
152
|
+
const settingsRef = useRef(null);
|
|
153
|
+
useEffect(() => {
|
|
154
|
+
if (props.settingsFile) {
|
|
155
|
+
const sm = new SettingsManager(props.settingsFile);
|
|
156
|
+
sm.load().then(() => {
|
|
157
|
+
settingsRef.current = sm;
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}, [props.settingsFile]);
|
|
161
|
+
const compactConversation = useCallback(async (messages) => {
|
|
162
|
+
const contextWindow = getContextWindow(currentModel);
|
|
163
|
+
const tokensBefore = estimateConversationTokens(messages);
|
|
164
|
+
const spinId = getId();
|
|
165
|
+
log("INFO", "compaction", `Running compaction`, {
|
|
166
|
+
messages: String(messages.length),
|
|
167
|
+
estimatedTokens: String(tokensBefore),
|
|
168
|
+
contextWindow: String(contextWindow),
|
|
169
|
+
});
|
|
170
|
+
// Show animated spinner
|
|
171
|
+
setLiveItems((prev) => [...prev, { kind: "compacting", id: spinId }]);
|
|
172
|
+
try {
|
|
173
|
+
const result = await compact(messages, {
|
|
174
|
+
provider: currentProvider,
|
|
175
|
+
model: currentModel,
|
|
176
|
+
apiKey: activeApiKey,
|
|
177
|
+
contextWindow,
|
|
178
|
+
signal: undefined,
|
|
179
|
+
});
|
|
180
|
+
// Replace spinner with completed notice
|
|
181
|
+
setLiveItems((prev) => prev.map((item) => item.id === spinId
|
|
182
|
+
? {
|
|
183
|
+
kind: "compacted",
|
|
184
|
+
originalCount: result.result.originalCount,
|
|
185
|
+
newCount: result.result.newCount,
|
|
186
|
+
tokensBefore: result.result.tokensBeforeEstimate,
|
|
187
|
+
tokensAfter: result.result.tokensAfterEstimate,
|
|
188
|
+
id: spinId,
|
|
189
|
+
}
|
|
190
|
+
: item));
|
|
191
|
+
return result.messages;
|
|
192
|
+
}
|
|
193
|
+
catch (err) {
|
|
194
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
195
|
+
log("ERROR", "compaction", `Compaction failed: ${msg}`);
|
|
196
|
+
// Replace spinner with error
|
|
197
|
+
setLiveItems((prev) => prev.map((item) => item.id === spinId
|
|
198
|
+
? { kind: "error", message: `Compaction failed: ${msg}`, id: spinId }
|
|
199
|
+
: item));
|
|
200
|
+
return messages; // Return unchanged on failure
|
|
201
|
+
}
|
|
202
|
+
}, [currentModel, currentProvider, activeApiKey]);
|
|
203
|
+
/**
|
|
204
|
+
* transformContext callback for the agent loop.
|
|
205
|
+
* Called before each LLM call and on context overflow.
|
|
206
|
+
* Checks if auto-compaction is needed and runs it.
|
|
207
|
+
*/
|
|
208
|
+
const transformContext = useCallback(async (messages) => {
|
|
209
|
+
const settings = settingsRef.current;
|
|
210
|
+
const autoCompact = settings?.get("autoCompact") ?? true;
|
|
211
|
+
const threshold = settings?.get("compactThreshold") ?? 0.8;
|
|
212
|
+
if (!autoCompact)
|
|
213
|
+
return messages;
|
|
214
|
+
const contextWindow = getContextWindow(currentModel);
|
|
215
|
+
if (shouldCompact(messages, contextWindow, threshold)) {
|
|
216
|
+
return compactConversation(messages);
|
|
217
|
+
}
|
|
218
|
+
return messages;
|
|
219
|
+
}, [currentModel, compactConversation]);
|
|
129
220
|
// ── Background task bar state ───────────────────────────
|
|
130
221
|
const [bgTasks, setBgTasks] = useState([]);
|
|
131
222
|
const [taskBarFocused, setTaskBarFocused] = useState(false);
|
|
@@ -184,16 +275,20 @@ export function App(props) {
|
|
|
184
275
|
tools: props.tools,
|
|
185
276
|
serverTools: props.serverTools,
|
|
186
277
|
maxTokens: props.maxTokens,
|
|
187
|
-
thinking: props.thinking,
|
|
278
|
+
thinking: thinkingEnabled ? (props.thinking ?? "medium") : undefined,
|
|
188
279
|
apiKey: activeApiKey,
|
|
189
280
|
baseUrl: props.baseUrl,
|
|
190
281
|
accountId: activeAccountId,
|
|
282
|
+
transformContext,
|
|
191
283
|
}, {
|
|
192
284
|
onComplete: useCallback(() => {
|
|
193
285
|
persistNewMessages();
|
|
194
286
|
}, [persistNewMessages]),
|
|
195
|
-
onTurnText: useCallback((text, thinking) => {
|
|
196
|
-
setLiveItems((prev) => [
|
|
287
|
+
onTurnText: useCallback((text, thinking, thinkingMs) => {
|
|
288
|
+
setLiveItems((prev) => [
|
|
289
|
+
...prev,
|
|
290
|
+
{ kind: "assistant", text, thinking, thinkingMs, id: getId() },
|
|
291
|
+
]);
|
|
197
292
|
}, []),
|
|
198
293
|
onToolStart: useCallback((toolCallId, name, args) => {
|
|
199
294
|
log("INFO", "tool", `Tool call started: ${name}`, { id: toolCallId });
|
|
@@ -344,6 +439,8 @@ export function App(props) {
|
|
|
344
439
|
stopReason,
|
|
345
440
|
inputTokens: String(usage.inputTokens),
|
|
346
441
|
outputTokens: String(usage.outputTokens),
|
|
442
|
+
...(usage.cacheRead != null && { cacheRead: String(usage.cacheRead) }),
|
|
443
|
+
...(usage.cacheWrite != null && { cacheWrite: String(usage.cacheWrite) }),
|
|
347
444
|
});
|
|
348
445
|
}, []),
|
|
349
446
|
onDone: useCallback((durationMs, toolsUsed) => {
|
|
@@ -361,34 +458,123 @@ export function App(props) {
|
|
|
361
458
|
});
|
|
362
459
|
}, []),
|
|
363
460
|
});
|
|
461
|
+
// When agent finishes, move live items into Static history so the live area
|
|
462
|
+
// is minimal. This prevents scroll jumping caused by Ink re-rendering the
|
|
463
|
+
// entire live area on every timer tick (cursor blink, border pulse, etc.).
|
|
464
|
+
useEffect(() => {
|
|
465
|
+
if (wasRunningRef.current && !agentLoop.isRunning) {
|
|
466
|
+
setLiveItems((prev) => {
|
|
467
|
+
if (prev.length > 0) {
|
|
468
|
+
setHistory((h) => [...h, ...prev]);
|
|
469
|
+
}
|
|
470
|
+
return [];
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
wasRunningRef.current = agentLoop.isRunning;
|
|
474
|
+
}, [agentLoop.isRunning]);
|
|
364
475
|
// Sync terminal title with agent loop state
|
|
365
476
|
useEffect(() => {
|
|
366
477
|
setTitlePhase(agentLoop.activityPhase);
|
|
367
478
|
setTitleRunning(agentLoop.isRunning);
|
|
368
479
|
}, [agentLoop.activityPhase, agentLoop.isRunning]);
|
|
369
|
-
|
|
480
|
+
// Animated thinking border
|
|
481
|
+
const [thinkingBorderFrame, setThinkingBorderFrame] = useState(0);
|
|
482
|
+
useEffect(() => {
|
|
483
|
+
if (agentLoop.activityPhase !== "thinking")
|
|
484
|
+
return;
|
|
485
|
+
const timer = setInterval(() => {
|
|
486
|
+
setThinkingBorderFrame((f) => (f + 1) % THINKING_BORDER_COLORS.length);
|
|
487
|
+
}, 500);
|
|
488
|
+
return () => clearInterval(timer);
|
|
489
|
+
}, [agentLoop.activityPhase]);
|
|
490
|
+
// Success flash on turn completion
|
|
491
|
+
const [doneFlash, setDoneFlash] = useState(false);
|
|
492
|
+
useEffect(() => {
|
|
493
|
+
if (doneStatus) {
|
|
494
|
+
setDoneFlash(true);
|
|
495
|
+
const timer = setTimeout(() => setDoneFlash(false), 600);
|
|
496
|
+
return () => clearTimeout(timer);
|
|
497
|
+
}
|
|
498
|
+
}, [doneStatus]);
|
|
499
|
+
const handleSubmit = useCallback(async (input, inputImages = []) => {
|
|
370
500
|
const trimmed = input.trim();
|
|
371
501
|
if (trimmed.startsWith("/")) {
|
|
372
502
|
log("INFO", "command", `Slash command: ${trimmed}`);
|
|
373
503
|
}
|
|
374
504
|
else {
|
|
375
505
|
const truncated = trimmed.length > 100 ? trimmed.slice(0, 100) + "..." : trimmed;
|
|
376
|
-
log("INFO", "input", `User input: ${truncated}`);
|
|
506
|
+
log("INFO", "input", `User input: ${truncated}${inputImages.length > 0 ? ` (+${inputImages.length} image${inputImages.length > 1 ? "s" : ""})` : ""}`);
|
|
377
507
|
}
|
|
378
508
|
// Handle /model directly — open inline selector
|
|
379
509
|
if (trimmed === "/model" || trimmed === "/m") {
|
|
380
510
|
setOverlay("model");
|
|
381
511
|
return;
|
|
382
512
|
}
|
|
383
|
-
// Handle /
|
|
513
|
+
// Handle /compact — compact conversation
|
|
514
|
+
if (trimmed === "/compact" || trimmed === "/c") {
|
|
515
|
+
const compacted = await compactConversation(messagesRef.current);
|
|
516
|
+
if (compacted !== messagesRef.current) {
|
|
517
|
+
messagesRef.current = compacted;
|
|
518
|
+
persistedIndexRef.current = 0; // Re-persist after compaction
|
|
519
|
+
}
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
// Handle /quit — exit the agent
|
|
523
|
+
if (trimmed === "/quit" || trimmed === "/q" || trimmed === "/exit") {
|
|
524
|
+
process.exit(0);
|
|
525
|
+
}
|
|
526
|
+
// Handle /clear — reset session and clear terminal
|
|
384
527
|
if (trimmed === "/clear") {
|
|
385
|
-
|
|
528
|
+
// Clear terminal screen + scrollback — needed because Ink's <Static>
|
|
529
|
+
// writes directly to stdout and can't be removed by clearing React state
|
|
530
|
+
stdout?.write("\x1b[2J\x1b[3J\x1b[H");
|
|
531
|
+
setHistory([{ kind: "banner", id: "banner" }]);
|
|
386
532
|
setLiveItems([]);
|
|
387
533
|
messagesRef.current = messagesRef.current.slice(0, 1); // keep system prompt
|
|
388
534
|
agentLoop.reset();
|
|
389
535
|
setLiveItems([{ kind: "info", text: "Session cleared.", id: getId() }]);
|
|
390
536
|
return;
|
|
391
537
|
}
|
|
538
|
+
// Handle prompt-template commands (built-in + custom from .gg/commands/)
|
|
539
|
+
if (trimmed.startsWith("/")) {
|
|
540
|
+
const cmdName = trimmed.slice(1).split(" ")[0];
|
|
541
|
+
const builtinCmd = getPromptCommand(cmdName);
|
|
542
|
+
const customCmd = !builtinCmd ? customCommands.find((c) => c.name === cmdName) : undefined;
|
|
543
|
+
const promptText = builtinCmd?.prompt ?? customCmd?.prompt;
|
|
544
|
+
if (promptText) {
|
|
545
|
+
log("INFO", "command", `Prompt command: /${cmdName}`);
|
|
546
|
+
// Move live items into history before starting
|
|
547
|
+
setLiveItems((prev) => {
|
|
548
|
+
if (prev.length > 0) {
|
|
549
|
+
setHistory((h) => [...h, ...prev]);
|
|
550
|
+
}
|
|
551
|
+
return [];
|
|
552
|
+
});
|
|
553
|
+
// Show the command name as the user message
|
|
554
|
+
const userItem = { kind: "user", text: trimmed, id: getId() };
|
|
555
|
+
setLastUserMessage(trimmed);
|
|
556
|
+
setDoneStatus(null);
|
|
557
|
+
setLiveItems([userItem]);
|
|
558
|
+
// Send the full prompt to the agent
|
|
559
|
+
try {
|
|
560
|
+
await agentLoop.run(promptText);
|
|
561
|
+
}
|
|
562
|
+
catch (err) {
|
|
563
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
564
|
+
log("ERROR", "error", msg);
|
|
565
|
+
const isAbort = msg.includes("aborted") || msg.includes("abort");
|
|
566
|
+
setLiveItems((prev) => [
|
|
567
|
+
...prev,
|
|
568
|
+
isAbort
|
|
569
|
+
? { kind: "info", text: "Request was stopped.", id: getId() }
|
|
570
|
+
: { kind: "error", message: msg, id: getId() },
|
|
571
|
+
]);
|
|
572
|
+
}
|
|
573
|
+
// Reload custom commands in case a setup command created new ones
|
|
574
|
+
reloadCustomCommands();
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
392
578
|
// Check slash commands
|
|
393
579
|
if (props.onSlashCommand && input.startsWith("/")) {
|
|
394
580
|
const result = await props.onSlashCommand(input);
|
|
@@ -397,21 +583,47 @@ export function App(props) {
|
|
|
397
583
|
return;
|
|
398
584
|
}
|
|
399
585
|
}
|
|
400
|
-
// Move
|
|
586
|
+
// Move any remaining live items into history (Static) before starting new turn
|
|
401
587
|
setLiveItems((prev) => {
|
|
402
588
|
if (prev.length > 0) {
|
|
403
589
|
setHistory((h) => [...h, ...prev]);
|
|
404
590
|
}
|
|
405
591
|
return [];
|
|
406
592
|
});
|
|
407
|
-
//
|
|
408
|
-
const
|
|
593
|
+
// Build display text — strip image paths, show badges instead
|
|
594
|
+
const hasImages = inputImages.length > 0;
|
|
595
|
+
let displayText = input;
|
|
596
|
+
if (hasImages) {
|
|
597
|
+
const { cleanText } = await extractImagePaths(input, props.cwd);
|
|
598
|
+
displayText = cleanText;
|
|
599
|
+
}
|
|
600
|
+
const userItem = {
|
|
601
|
+
kind: "user",
|
|
602
|
+
text: displayText,
|
|
603
|
+
imageCount: hasImages ? inputImages.length : undefined,
|
|
604
|
+
id: getId(),
|
|
605
|
+
};
|
|
409
606
|
setLastUserMessage(input);
|
|
410
607
|
setDoneStatus(null);
|
|
411
608
|
setLiveItems([userItem]);
|
|
609
|
+
// Build user content — plain string or content array with images
|
|
610
|
+
let userContent;
|
|
611
|
+
if (hasImages) {
|
|
612
|
+
const parts = [];
|
|
613
|
+
if (trimmed) {
|
|
614
|
+
parts.push({ type: "text", text: trimmed });
|
|
615
|
+
}
|
|
616
|
+
for (const img of inputImages) {
|
|
617
|
+
parts.push({ type: "image", mediaType: img.mediaType, data: img.data });
|
|
618
|
+
}
|
|
619
|
+
userContent = parts;
|
|
620
|
+
}
|
|
621
|
+
else {
|
|
622
|
+
userContent = input;
|
|
623
|
+
}
|
|
412
624
|
// Run agent
|
|
413
625
|
try {
|
|
414
|
-
await agentLoop.run(
|
|
626
|
+
await agentLoop.run(userContent);
|
|
415
627
|
}
|
|
416
628
|
catch (err) {
|
|
417
629
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -424,7 +636,7 @@ export function App(props) {
|
|
|
424
636
|
: { kind: "error", message: msg, id: getId() },
|
|
425
637
|
]);
|
|
426
638
|
}
|
|
427
|
-
}, [agentLoop, props.onSlashCommand]);
|
|
639
|
+
}, [agentLoop, props.onSlashCommand, compactConversation]);
|
|
428
640
|
const handleAbort = useCallback(() => {
|
|
429
641
|
if (agentLoop.isRunning) {
|
|
430
642
|
agentLoop.abort();
|
|
@@ -433,6 +645,21 @@ export function App(props) {
|
|
|
433
645
|
process.exit(0);
|
|
434
646
|
}
|
|
435
647
|
}, [agentLoop]);
|
|
648
|
+
const handleToggleThinking = useCallback(() => {
|
|
649
|
+
setThinkingEnabled((prev) => {
|
|
650
|
+
const next = !prev;
|
|
651
|
+
log("INFO", "thinking", `Thinking ${next ? "enabled" : "disabled"}`);
|
|
652
|
+
setLiveItems((items) => [
|
|
653
|
+
...items,
|
|
654
|
+
{ kind: "info", text: `Thinking ${next ? "on" : "off"}`, id: getId() },
|
|
655
|
+
]);
|
|
656
|
+
if (props.settingsFile) {
|
|
657
|
+
const sm = new SettingsManager(props.settingsFile);
|
|
658
|
+
sm.load().then(() => sm.set("thinkingEnabled", next));
|
|
659
|
+
}
|
|
660
|
+
return next;
|
|
661
|
+
});
|
|
662
|
+
}, [props.settingsFile]);
|
|
436
663
|
const handleModelSelect = useCallback((value) => {
|
|
437
664
|
setOverlay(null);
|
|
438
665
|
const colonIdx = value.indexOf(":");
|
|
@@ -458,16 +685,31 @@ export function App(props) {
|
|
|
458
685
|
});
|
|
459
686
|
}
|
|
460
687
|
}, [props.settingsFile]);
|
|
461
|
-
|
|
462
|
-
const
|
|
688
|
+
// All available slash commands for the command palette
|
|
689
|
+
const allCommands = useMemo(() => [
|
|
690
|
+
{ name: "model", aliases: ["m"], description: "Switch model" },
|
|
691
|
+
{ name: "compact", aliases: ["c"], description: "Compact conversation" },
|
|
692
|
+
{ name: "clear", aliases: [], description: "Clear session and terminal" },
|
|
693
|
+
{ name: "quit", aliases: ["q", "exit"], description: "Exit the agent" },
|
|
694
|
+
...PROMPT_COMMANDS.map((cmd) => ({
|
|
695
|
+
name: cmd.name,
|
|
696
|
+
aliases: cmd.aliases,
|
|
697
|
+
description: cmd.description,
|
|
698
|
+
})),
|
|
699
|
+
...customCommands.map((cmd) => ({
|
|
700
|
+
name: cmd.name,
|
|
701
|
+
aliases: [],
|
|
702
|
+
description: cmd.description,
|
|
703
|
+
})),
|
|
704
|
+
], [customCommands]);
|
|
463
705
|
const renderItem = (item) => {
|
|
464
706
|
switch (item.kind) {
|
|
465
707
|
case "banner":
|
|
466
708
|
return (_jsx(Banner, { version: props.version, model: props.model, provider: props.provider, cwd: props.cwd }, item.id));
|
|
467
709
|
case "user":
|
|
468
|
-
return _jsx(UserMessage, { text: item.text }, item.id);
|
|
710
|
+
return _jsx(UserMessage, { text: item.text, imageCount: item.imageCount }, item.id);
|
|
469
711
|
case "assistant":
|
|
470
|
-
return (_jsx(AssistantMessage, { text: item.text, thinking: item.thinking, showThinking: props.showThinking }, item.id));
|
|
712
|
+
return (_jsx(AssistantMessage, { text: item.text, thinking: item.thinking, thinkingMs: item.thinkingMs, showThinking: props.showThinking }, item.id));
|
|
471
713
|
case "tool_start":
|
|
472
714
|
return _jsx(ToolExecution, { status: "running", name: item.name, args: item.args }, item.id);
|
|
473
715
|
case "tool_done":
|
|
@@ -480,12 +722,18 @@ export function App(props) {
|
|
|
480
722
|
return (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: theme.error, children: "✗ " }), _jsx(Text, { color: theme.error, children: item.message })] }, item.id));
|
|
481
723
|
case "info":
|
|
482
724
|
return (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: theme.textDim, children: item.text }) }, item.id));
|
|
725
|
+
case "compacting":
|
|
726
|
+
return _jsx(CompactionSpinner, {}, item.id);
|
|
727
|
+
case "compacted":
|
|
728
|
+
return (_jsx(CompactionDone, { originalCount: item.originalCount, newCount: item.newCount, tokensBefore: item.tokensBefore, tokensAfter: item.tokensAfter }, item.id));
|
|
483
729
|
case "duration":
|
|
484
730
|
return (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: theme.textDim, children: ["✻ ", item.verb, " ", formatDuration(item.durationMs)] }) }, item.id));
|
|
485
731
|
case "subagent_group":
|
|
486
732
|
return _jsx(SubAgentPanel, { agents: item.agents, aborted: item.aborted }, item.id);
|
|
487
733
|
}
|
|
488
734
|
};
|
|
489
|
-
return (_jsxs(Box, { flexDirection: "column",
|
|
735
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Static, { items: history, style: { width: "100%" }, children: (item) => renderItem(item) }), _jsxs(Box, { flexDirection: "column", flexGrow: 1, paddingRight: 1, children: [liveItems.map((item) => renderItem(item)), _jsx(StreamingArea, { isRunning: agentLoop.isRunning, streamingText: agentLoop.streamingText, streamingThinking: agentLoop.streamingThinking, showThinking: props.showThinking, thinkingMs: agentLoop.thinkingMs })] }), agentLoop.isRunning && agentLoop.activityPhase !== "idle" ? (_jsx(Box, { marginTop: 1, borderStyle: agentLoop.activityPhase === "thinking" ? "round" : undefined, borderColor: agentLoop.activityPhase === "thinking"
|
|
736
|
+
? THINKING_BORDER_COLORS[thinkingBorderFrame]
|
|
737
|
+
: undefined, paddingLeft: agentLoop.activityPhase === "thinking" ? 1 : 0, paddingRight: agentLoop.activityPhase === "thinking" ? 1 : 0, children: _jsx(ActivityIndicator, { phase: agentLoop.activityPhase, elapsedMs: agentLoop.elapsedMs, thinkingMs: agentLoop.thinkingMs, isThinking: agentLoop.isThinking, tokenEstimate: agentLoop.streamedTokenEstimate, userMessage: lastUserMessage }) })) : (doneStatus && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: doneFlash ? theme.success : theme.textDim, children: ["✻ ", doneStatus.verb, " ", formatDuration(doneStatus.durationMs)] }) }))), _jsx(InputArea, { onSubmit: handleSubmit, onAbort: handleAbort, disabled: agentLoop.isRunning, isActive: !taskBarFocused, onDownAtEnd: handleFocusTaskBar, onShiftTab: handleToggleThinking, cwd: props.cwd, commands: allCommands }), overlay === "model" ? (_jsx(ModelSelector, { onSelect: handleModelSelect, onCancel: () => setOverlay(null), loggedInProviders: props.loggedInProviders ?? [currentProvider], currentModel: currentModel, currentProvider: currentProvider })) : (_jsx(Footer, { model: currentModel, tokensIn: agentLoop.contextUsed, cwd: props.cwd, gitBranch: gitBranch, thinkingEnabled: thinkingEnabled })), bgTasks.length > 0 && (_jsx(BackgroundTasksBar, { tasks: bgTasks, focused: taskBarFocused, expanded: taskBarExpanded, selectedIndex: selectedTaskIndex, onExpand: handleTaskBarExpand, onCollapse: handleTaskBarCollapse, onKill: handleTaskKill, onExit: handleTaskBarExit, onNavigate: handleTaskNavigate }))] }));
|
|
490
738
|
}
|
|
491
739
|
//# sourceMappingURL=App.js.map
|