@kenkaiiii/ggcoder 5.50.0 → 5.51.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/app-sidecar.js +65 -2
- package/dist/app-sidecar.js.map +1 -1
- package/dist/core/ask-user.d.ts +57 -0
- package/dist/core/ask-user.d.ts.map +1 -0
- package/dist/core/ask-user.js +36 -0
- package/dist/core/ask-user.js.map +1 -0
- package/dist/core/mcp/elicitation-bridge.d.ts.map +1 -1
- package/dist/core/mcp/elicitation-bridge.js +12 -28
- package/dist/core/mcp/elicitation-bridge.js.map +1 -1
- package/dist/core/parked-requests.d.ts +40 -0
- package/dist/core/parked-requests.d.ts.map +1 -0
- package/dist/core/parked-requests.js +34 -0
- package/dist/core/parked-requests.js.map +1 -0
- package/dist/core/prompt-commands.d.ts.map +1 -1
- package/dist/core/prompt-commands.js +13 -12
- package/dist/core/prompt-commands.js.map +1 -1
- package/dist/system-prompt.js +1 -1
- package/dist/system-prompt.js.map +1 -1
- package/dist/tools/ask-user.d.ts +35 -0
- package/dist/tools/ask-user.d.ts.map +1 -0
- package/dist/tools/ask-user.js +157 -0
- package/dist/tools/ask-user.js.map +1 -0
- package/dist/tools/prompt-hints.d.ts.map +1 -1
- package/dist/tools/prompt-hints.js +4 -0
- package/dist/tools/prompt-hints.js.map +1 -1
- package/dist/tools/tool-tiers.d.ts.map +1 -1
- package/dist/tools/tool-tiers.js +4 -0
- package/dist/tools/tool-tiers.js.map +1 -1
- package/package.json +4 -4
package/dist/app-sidecar.js
CHANGED
|
@@ -71,6 +71,8 @@ import { downscaleForPreview, shrinkToFit, validateVisionImage } from "./utils/i
|
|
|
71
71
|
import { startServeMode } from "./modes/serve-mode.js";
|
|
72
72
|
import { loadTelegramConfig, saveTelegramConfig, verifyBotToken } from "./core/telegram-config.js";
|
|
73
73
|
import { loadServers, addServer, removeServer, getServer, parseMcpAddCommand, MCPClientManager, McpOAuthStore, createElicitationBridge, } from "./core/mcp/index.js";
|
|
74
|
+
import { createAskUserBridge } from "./core/ask-user.js";
|
|
75
|
+
import { createAskUserTool } from "./tools/ask-user.js";
|
|
74
76
|
import { buildSnapshot, levelForXp, rankForLevel } from "./core/progress/ranks.js";
|
|
75
77
|
import { loadProgress, peekProgress, updateProgress } from "./core/progress/store.js";
|
|
76
78
|
import { awardPrompt, awardCommits } from "./core/progress/engine.js";
|
|
@@ -1297,6 +1299,16 @@ async function createSession(deps, opts) {
|
|
|
1297
1299
|
server: prompt.server,
|
|
1298
1300
|
}),
|
|
1299
1301
|
});
|
|
1302
|
+
// ── ask_user bridge ────────────────────────────────────────
|
|
1303
|
+
// The `ask_user` tool parks the turn on a human answer. Same shape as the
|
|
1304
|
+
// MCP bridge above: broadcast over SSE, resolved when the webview POSTs
|
|
1305
|
+
// /ask/:id. Registered ONLY here — a TUI/headless/subagent run has nobody to
|
|
1306
|
+
// answer, so the tool is absent there rather than hanging on a dead channel.
|
|
1307
|
+
const asks = createAskUserBridge({
|
|
1308
|
+
broadcast: (prompt) => broadcast("ask_user", prompt),
|
|
1309
|
+
onTimeout: (prompt) => log("WARN", "app-sidecar", "ask_user timed out", { id: prompt.id }),
|
|
1310
|
+
});
|
|
1311
|
+
const askUserTool = createAskUserTool(asks.park);
|
|
1300
1312
|
// The session file path to resume (passed by the daemon's POST /session);
|
|
1301
1313
|
// empty/unset starts a fresh session.
|
|
1302
1314
|
const resumeSessionPath = opts.sessionPath;
|
|
@@ -1322,7 +1334,11 @@ async function createSession(deps, opts) {
|
|
|
1322
1334
|
session = createChatAgent(chatAgent, {
|
|
1323
1335
|
...baseSessionOptions,
|
|
1324
1336
|
sessionsDir: paths.sessionsDir,
|
|
1325
|
-
additionalTools: [
|
|
1337
|
+
additionalTools: [
|
|
1338
|
+
askUserTool,
|
|
1339
|
+
...buildMemoryTools(memoryStore),
|
|
1340
|
+
...buildJiwaTools(jiwaStore),
|
|
1341
|
+
],
|
|
1326
1342
|
getSystemPromptTail: () => `${memoryStore.renderForPrompt()}\n\n${jiwaStore.renderForPrompt()}`,
|
|
1327
1343
|
onAgentChange: async (nextAgent) => {
|
|
1328
1344
|
chatAgent = nextAgent;
|
|
@@ -1339,6 +1355,7 @@ async function createSession(deps, opts) {
|
|
|
1339
1355
|
else {
|
|
1340
1356
|
session = new AgentSession({
|
|
1341
1357
|
...baseSessionOptions,
|
|
1358
|
+
additionalTools: [askUserTool],
|
|
1342
1359
|
// Plan mode belongs only to the coding agent.
|
|
1343
1360
|
onEnterPlan: async (reason) => {
|
|
1344
1361
|
deactivateApprovedPlan();
|
|
@@ -2152,8 +2169,9 @@ async function createSession(deps, opts) {
|
|
|
2152
2169
|
abort.abort();
|
|
2153
2170
|
// An MCP tool call parked on user input is not cancelled by the signal —
|
|
2154
2171
|
// the promise lives in the bridge. Release it, or the aborted turn's tool
|
|
2155
|
-
// call never returns.
|
|
2172
|
+
// call never returns. Same for a question parked on the user.
|
|
2156
2173
|
elicitations.cancelAll();
|
|
2174
|
+
asks.cancelAll();
|
|
2157
2175
|
// Stop a run-all sweep and every async child through AgentSession's signal.
|
|
2158
2176
|
taskRunAll = false;
|
|
2159
2177
|
autopilotCancelled = true;
|
|
@@ -4480,6 +4498,50 @@ async function createSession(deps, opts) {
|
|
|
4480
4498
|
});
|
|
4481
4499
|
return;
|
|
4482
4500
|
}
|
|
4501
|
+
// Answer (or dismiss) an `ask_user` question band. The turn is blocked on
|
|
4502
|
+
// this, so both paths must land: "answer" carries the picked values,
|
|
4503
|
+
// "cancel" releases the tool call with no answer.
|
|
4504
|
+
if (method === "POST" && url.startsWith("/ask/")) {
|
|
4505
|
+
const id = decodeURIComponent(url.slice("/ask/".length));
|
|
4506
|
+
void readBody(req, res).then((raw) => {
|
|
4507
|
+
if (raw === null)
|
|
4508
|
+
return;
|
|
4509
|
+
let result;
|
|
4510
|
+
try {
|
|
4511
|
+
const parsed = JSON.parse(raw);
|
|
4512
|
+
if (parsed.action !== "answer" && parsed.action !== "cancel") {
|
|
4513
|
+
json(res, 400, { error: "action must be answer or cancel" });
|
|
4514
|
+
return;
|
|
4515
|
+
}
|
|
4516
|
+
if (parsed.action === "cancel") {
|
|
4517
|
+
result = { action: "cancel" };
|
|
4518
|
+
}
|
|
4519
|
+
else {
|
|
4520
|
+
// Only strings and string arrays are answers; anything else is a
|
|
4521
|
+
// malformed client, not a value to hand the model.
|
|
4522
|
+
const answers = {};
|
|
4523
|
+
for (const [key, value] of Object.entries(parsed.answers ?? {})) {
|
|
4524
|
+
if (typeof value === "string")
|
|
4525
|
+
answers[key] = value;
|
|
4526
|
+
else if (Array.isArray(value) && value.every((v) => typeof v === "string")) {
|
|
4527
|
+
answers[key] = value;
|
|
4528
|
+
}
|
|
4529
|
+
}
|
|
4530
|
+
result = { action: "answer", answers };
|
|
4531
|
+
}
|
|
4532
|
+
}
|
|
4533
|
+
catch {
|
|
4534
|
+
json(res, 400, { error: "invalid JSON body" });
|
|
4535
|
+
return;
|
|
4536
|
+
}
|
|
4537
|
+
if (!asks.settle(id, result)) {
|
|
4538
|
+
json(res, 409, { error: "no question is awaiting an answer" });
|
|
4539
|
+
return;
|
|
4540
|
+
}
|
|
4541
|
+
json(res, 200, { ok: true });
|
|
4542
|
+
});
|
|
4543
|
+
return;
|
|
4544
|
+
}
|
|
4483
4545
|
if (method === "POST" && url === "/auth/logout") {
|
|
4484
4546
|
void readBody(req, res).then(async (raw) => {
|
|
4485
4547
|
if (raw === null)
|
|
@@ -4958,6 +5020,7 @@ async function createSession(deps, opts) {
|
|
|
4958
5020
|
}
|
|
4959
5021
|
async function dispose() {
|
|
4960
5022
|
elicitations.cancelAll();
|
|
5023
|
+
asks.cancelAll();
|
|
4961
5024
|
tasksPollStopped = true;
|
|
4962
5025
|
if (tasksPoll)
|
|
4963
5026
|
clearTimeout(tasksPoll);
|