@kenkaiiii/ggcoder 5.6.1 → 5.6.3
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/app-sidecar.js +85 -20
- package/dist/app-sidecar.js.map +1 -1
- package/dist/core/agent-session.d.ts +34 -2
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +94 -15
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/autopilot-gate.d.ts +36 -22
- package/dist/core/autopilot-gate.d.ts.map +1 -1
- package/dist/core/autopilot-gate.js +100 -0
- package/dist/core/autopilot-gate.js.map +1 -1
- package/dist/core/autopilot-gate.test.js +112 -1
- package/dist/core/autopilot-gate.test.js.map +1 -1
- package/dist/core/autopilot-verdict.d.ts.map +1 -1
- package/dist/core/autopilot-verdict.js +41 -1
- package/dist/core/autopilot-verdict.js.map +1 -1
- package/dist/core/autopilot-verdict.test.js +16 -0
- package/dist/core/autopilot-verdict.test.js.map +1 -1
- package/dist/core/ken-context.d.ts +6 -2
- package/dist/core/ken-context.d.ts.map +1 -1
- package/dist/core/ken-context.js +0 -2
- package/dist/core/ken-context.js.map +1 -1
- package/dist/core/ken-context.test.js +1 -7
- package/dist/core/ken-context.test.js.map +1 -1
- package/dist/core/ken-prompt.d.ts +2 -15
- package/dist/core/ken-prompt.d.ts.map +1 -1
- package/dist/core/ken-prompt.js +39 -10
- package/dist/core/ken-prompt.js.map +1 -1
- package/dist/core/ken-prompt.test.js +37 -4
- package/dist/core/ken-prompt.test.js.map +1 -1
- package/dist/core/session-manager.d.ts +18 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +31 -0
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-manager.test.js +71 -1
- package/dist/core/session-manager.test.js.map +1 -1
- package/package.json +4 -4
package/dist/app-sidecar.js
CHANGED
|
@@ -23,10 +23,9 @@ import { AgentSession } from "./core/agent-session.js";
|
|
|
23
23
|
import { buildKenSystemPrompt, buildKenAutopilotSystemPrompt } from "./core/ken-prompt.js";
|
|
24
24
|
import { buildKenDigest, buildKenAutopilotContext } from "./core/ken-context.js";
|
|
25
25
|
import { parseAutopilotVerdict } from "./core/autopilot-verdict.js";
|
|
26
|
-
import { isWorkflowCommandText, countAssistantMessages, shouldStartAutopilotCycle, } from "./core/autopilot-gate.js";
|
|
26
|
+
import { isWorkflowCommandText, countAssistantMessages, shouldStartAutopilotCycle, extractTurnToolCalls, isMechanicalOnlyTurn, } from "./core/autopilot-gate.js";
|
|
27
27
|
import { driveAutopilotCycle } from "./core/autopilot-cycle.js";
|
|
28
28
|
import { validateKenModelPref, effectiveKenModel } from "./core/ken-model.js";
|
|
29
|
-
import { collectProjectContext } from "./system-prompt.js";
|
|
30
29
|
import { AuthStorage } from "./core/auth-storage.js";
|
|
31
30
|
import { MOONSHOT_OAUTH_KEY, XIAOMI_CREDITS_KEY } from "@kenkaiiii/gg-core";
|
|
32
31
|
import { loginAnthropic } from "./core/oauth/anthropic.js";
|
|
@@ -623,17 +622,18 @@ function lastAssistantText(messages) {
|
|
|
623
622
|
return "";
|
|
624
623
|
}
|
|
625
624
|
/**
|
|
626
|
-
* Assemble Ken's context digest for one `@Ken` question:
|
|
627
|
-
*
|
|
628
|
-
*
|
|
629
|
-
*
|
|
630
|
-
*
|
|
625
|
+
* Assemble Ken's context digest for one `@Ken` question: git/env + the build
|
|
626
|
+
* session's compaction summary + recent activity. Prepended to the user's
|
|
627
|
+
* question as Ken's prompt body each turn. Project docs (CLAUDE.md/AGENTS.md)
|
|
628
|
+
* are NOT here — they're folded into Ken's cached system prompt once per
|
|
629
|
+
* session instead (see ken-prompt.ts), so they hit the provider prompt cache
|
|
630
|
+
* instead of being re-sent uncached on every question. Workflow commands +
|
|
631
|
+
* autopilot-injected prompts are passed through so the digest labels them as
|
|
632
|
+
* what they are instead of user-authored asks.
|
|
631
633
|
*/
|
|
632
|
-
|
|
633
|
-
const projectContext = await collectProjectContext(cwd).catch(() => []);
|
|
634
|
+
function buildKenContext(buildSession, cwd, gitBranch, question, workflowCommands, injectedPrompts) {
|
|
634
635
|
return buildKenDigest({
|
|
635
636
|
question,
|
|
636
|
-
projectContext,
|
|
637
637
|
cwd,
|
|
638
638
|
gitBranch,
|
|
639
639
|
messages: buildSession.getMessages(),
|
|
@@ -912,11 +912,14 @@ async function createSession(deps, opts) {
|
|
|
912
912
|
provider: target.provider,
|
|
913
913
|
model: target.model,
|
|
914
914
|
cwd,
|
|
915
|
-
systemPrompt: buildKenSystemPrompt(),
|
|
915
|
+
systemPrompt: await buildKenSystemPrompt(cwd),
|
|
916
916
|
allowedTools: KEN_ALLOWED_TOOLS,
|
|
917
917
|
allowedMcpServers: KEN_ALLOWED_MCP_SERVERS,
|
|
918
918
|
transient: true,
|
|
919
919
|
signal: kenAbort.signal,
|
|
920
|
+
// Ken's bursty, spread-out turns (chat) outlast the default 5-min cache
|
|
921
|
+
// TTL regardless of the user's global speedProfile pick.
|
|
922
|
+
forceLongCacheRetention: true,
|
|
920
923
|
});
|
|
921
924
|
await ken.initialize();
|
|
922
925
|
// Bridge Ken's bus to the shared SSE fan-out with ken_-prefixed types so the
|
|
@@ -978,11 +981,14 @@ async function createSession(deps, opts) {
|
|
|
978
981
|
provider: target.provider,
|
|
979
982
|
model: target.model,
|
|
980
983
|
cwd,
|
|
981
|
-
systemPrompt: buildKenAutopilotSystemPrompt(),
|
|
984
|
+
systemPrompt: await buildKenAutopilotSystemPrompt(cwd),
|
|
982
985
|
allowedTools: KEN_ALLOWED_TOOLS,
|
|
983
986
|
allowedMcpServers: KEN_ALLOWED_MCP_SERVERS,
|
|
984
987
|
transient: true,
|
|
985
988
|
signal: kenAutoAbort.signal,
|
|
989
|
+
// Autopilot review rounds routinely span the injected GG Coder run
|
|
990
|
+
// (often >5 min) regardless of the user's global speedProfile pick.
|
|
991
|
+
forceLongCacheRetention: true,
|
|
986
992
|
});
|
|
987
993
|
await ken.initialize();
|
|
988
994
|
// Deliberately no bus bridge: the review is silent. Errors surface via the
|
|
@@ -1062,9 +1068,7 @@ async function createSession(deps, opts) {
|
|
|
1062
1068
|
broadcast("autopilot_review_start", {});
|
|
1063
1069
|
try {
|
|
1064
1070
|
const ken = await ensureKenAutoSession();
|
|
1065
|
-
const projectContext = await collectProjectContext(cwd).catch(() => []);
|
|
1066
1071
|
const digest = buildKenAutopilotContext({
|
|
1067
|
-
projectContext,
|
|
1068
1072
|
cwd,
|
|
1069
1073
|
gitBranch,
|
|
1070
1074
|
messages: session.getMessages(),
|
|
@@ -1121,9 +1125,25 @@ async function createSession(deps, opts) {
|
|
|
1121
1125
|
onInjected: (body, round) => {
|
|
1122
1126
|
injectedAutopilotPrompts.push(body);
|
|
1123
1127
|
broadcast("autopilot_prompted", { round, body });
|
|
1128
|
+
void session.persistAutopilotMarker("prompted", { body });
|
|
1124
1129
|
},
|
|
1125
1130
|
runPrompt: (body) => runAgent(body, () => session.prompt(body)),
|
|
1126
|
-
emit: (event) =>
|
|
1131
|
+
emit: (event) => {
|
|
1132
|
+
broadcast(event.type, event.data);
|
|
1133
|
+
// Persist the terminal verdict marker so a resumed session renders the
|
|
1134
|
+
// same Ken bubble the live run showed instead of dropping it or
|
|
1135
|
+
// falling back to the raw verdict text (e.g. ALL_CLEAR).
|
|
1136
|
+
if (event.type === "autopilot_done") {
|
|
1137
|
+
void session.persistAutopilotMarker("done");
|
|
1138
|
+
}
|
|
1139
|
+
else if (event.type === "autopilot_human") {
|
|
1140
|
+
void session.persistAutopilotMarker("human", { reason: event.data.reason });
|
|
1141
|
+
}
|
|
1142
|
+
else if (event.type === "autopilot_capped") {
|
|
1143
|
+
void session.persistAutopilotMarker("capped");
|
|
1144
|
+
}
|
|
1145
|
+
// autopilot_ignored renders nothing live, so nothing is persisted either.
|
|
1146
|
+
},
|
|
1127
1147
|
});
|
|
1128
1148
|
}
|
|
1129
1149
|
finally {
|
|
@@ -1157,6 +1177,7 @@ async function createSession(deps, opts) {
|
|
|
1157
1177
|
const workflowCommand = next.attachments.length === 0 &&
|
|
1158
1178
|
isWorkflowCommandText(next.text, await loadWorkflowCommandSpecs());
|
|
1159
1179
|
const assistantsBefore = countAssistantMessages(session.getMessages());
|
|
1180
|
+
const messagesBefore = session.getMessages().length;
|
|
1160
1181
|
await runAgent(next.text, async () => {
|
|
1161
1182
|
if (next.attachments.length > 0) {
|
|
1162
1183
|
await session.promptWithAttachments(next.text, next.attachments);
|
|
@@ -1171,6 +1192,11 @@ async function createSession(deps, opts) {
|
|
|
1171
1192
|
planMode: session.getPlanMode(),
|
|
1172
1193
|
workflowCommand,
|
|
1173
1194
|
assistantMessagesAdded: countAssistantMessages(session.getMessages()) - assistantsBefore,
|
|
1195
|
+
// Skip the review API call outright for turns that only started a
|
|
1196
|
+
// background process (dev server/watcher), ran a read-only lookup, or
|
|
1197
|
+
// committed/pushed — Ken's autopilot contract already IGNOREs these,
|
|
1198
|
+
// so there's no reason to pay for that verdict.
|
|
1199
|
+
mechanicalOnly: isMechanicalOnlyTurn(extractTurnToolCalls(session.getMessages(), messagesBefore)),
|
|
1174
1200
|
});
|
|
1175
1201
|
if (decision.start) {
|
|
1176
1202
|
await runAutopilotCycle(next.text);
|
|
@@ -1505,9 +1531,37 @@ async function createSession(deps, opts) {
|
|
|
1505
1531
|
history.push({ role: "assistant", text: turn.reply, ken: true });
|
|
1506
1532
|
}
|
|
1507
1533
|
};
|
|
1534
|
+
// Autopilot verdict markers to interleave, same anchor scheme as Ken
|
|
1535
|
+
// turns — each becomes a single assistant row the webview renders
|
|
1536
|
+
// exactly like the live `autopilot` item (never a raw verdict string).
|
|
1537
|
+
const autopilotByCount = new Map();
|
|
1538
|
+
for (const marker of session.getAutopilotMarkers()) {
|
|
1539
|
+
const list = autopilotByCount.get(marker.afterMessageCount) ?? [];
|
|
1540
|
+
list.push(marker);
|
|
1541
|
+
autopilotByCount.set(marker.afterMessageCount, list);
|
|
1542
|
+
}
|
|
1543
|
+
const flushAutopilot = (count) => {
|
|
1544
|
+
const markers = autopilotByCount.get(count);
|
|
1545
|
+
if (!markers)
|
|
1546
|
+
return;
|
|
1547
|
+
autopilotByCount.delete(count);
|
|
1548
|
+
for (const marker of markers) {
|
|
1549
|
+
history.push({
|
|
1550
|
+
role: "assistant",
|
|
1551
|
+
text: "",
|
|
1552
|
+
autopilot: {
|
|
1553
|
+
phase: marker.phase,
|
|
1554
|
+
...(marker.reason !== undefined ? { reason: marker.reason } : {}),
|
|
1555
|
+
...(marker.body !== undefined ? { body: marker.body } : {}),
|
|
1556
|
+
},
|
|
1557
|
+
});
|
|
1558
|
+
}
|
|
1559
|
+
};
|
|
1508
1560
|
let nonSystemCount = 0;
|
|
1509
|
-
// Turns recorded before any build message (anchor 0) render at
|
|
1561
|
+
// Turns/markers recorded before any build message (anchor 0) render at
|
|
1562
|
+
// the top.
|
|
1510
1563
|
flushKen(0);
|
|
1564
|
+
flushAutopilot(0);
|
|
1511
1565
|
for (const msg of messages) {
|
|
1512
1566
|
if (msg.role === "system")
|
|
1513
1567
|
continue;
|
|
@@ -1601,14 +1655,19 @@ async function createSession(deps, opts) {
|
|
|
1601
1655
|
});
|
|
1602
1656
|
}
|
|
1603
1657
|
}
|
|
1604
|
-
// Interleave any Ken turns recorded right after
|
|
1658
|
+
// Interleave any Ken turns / autopilot markers recorded right after
|
|
1659
|
+
// this message.
|
|
1605
1660
|
flushKen(nonSystemCount);
|
|
1661
|
+
flushAutopilot(nonSystemCount);
|
|
1606
1662
|
}
|
|
1607
|
-
// Flush remaining Ken turns whose anchor is at/after
|
|
1608
|
-
// (e.g.
|
|
1609
|
-
// count after compaction shrank the history) so none
|
|
1663
|
+
// Flush remaining Ken turns / autopilot markers whose anchor is at/after
|
|
1664
|
+
// the message count (e.g. recorded before any build message, or anchors
|
|
1665
|
+
// beyond the current count after compaction shrank the history) so none
|
|
1666
|
+
// are dropped.
|
|
1610
1667
|
for (const count of [...kenByCount.keys()].sort((a, b) => a - b))
|
|
1611
1668
|
flushKen(count);
|
|
1669
|
+
for (const count of [...autopilotByCount.keys()].sort((a, b) => a - b))
|
|
1670
|
+
flushAutopilot(count);
|
|
1612
1671
|
json(res, 200, { history });
|
|
1613
1672
|
})();
|
|
1614
1673
|
return;
|
|
@@ -1678,6 +1737,7 @@ async function createSession(deps, opts) {
|
|
|
1678
1737
|
// gate reads the post-run value.
|
|
1679
1738
|
const workflowCommand = attachments.length === 0 && isWorkflowCommandText(text, await loadWorkflowCommandSpecs());
|
|
1680
1739
|
const assistantsBefore = countAssistantMessages(session.getMessages());
|
|
1740
|
+
const messagesBefore = session.getMessages().length;
|
|
1681
1741
|
await runAgent(text, async () => {
|
|
1682
1742
|
if (attachments.length > 0) {
|
|
1683
1743
|
// Persist each attachment under .gg/uploads so files are inspectable
|
|
@@ -1708,6 +1768,11 @@ async function createSession(deps, opts) {
|
|
|
1708
1768
|
planMode: session.getPlanMode(),
|
|
1709
1769
|
workflowCommand,
|
|
1710
1770
|
assistantMessagesAdded: countAssistantMessages(session.getMessages()) - assistantsBefore,
|
|
1771
|
+
// Skip the review API call outright for turns that only started a
|
|
1772
|
+
// background process (dev server/watcher), ran a read-only lookup, or
|
|
1773
|
+
// committed/pushed — Ken's autopilot contract already IGNOREs these,
|
|
1774
|
+
// so there's no reason to pay for that verdict.
|
|
1775
|
+
mechanicalOnly: isMechanicalOnlyTurn(extractTurnToolCalls(session.getMessages(), messagesBefore)),
|
|
1711
1776
|
});
|
|
1712
1777
|
if (decision.start) {
|
|
1713
1778
|
await runAutopilotCycle(text);
|