pikiloom 0.4.42 → 0.4.44
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/dashboard/dist/assets/{AgentTab-B9z4W2mh.js → AgentTab-B8V2eV_D.js} +1 -1
- package/dashboard/dist/assets/{ConnectionModal-2bL7sFKk.js → ConnectionModal-BOVwXLJB.js} +1 -1
- package/dashboard/dist/assets/{DirBrowser-CA4k8E_A.js → DirBrowser-DbeAWYiL.js} +1 -1
- package/dashboard/dist/assets/{ExtensionsTab-CRjTmFRl.js → ExtensionsTab-BMS3PW9N.js} +1 -1
- package/dashboard/dist/assets/{IMAccessTab-DDb7rsHe.js → IMAccessTab-B1sRgJk3.js} +1 -1
- package/dashboard/dist/assets/{Modal-DDiBG4kb.js → Modal-DCwGz46r.js} +1 -1
- package/dashboard/dist/assets/{Modals-CsUQjpxn.js → Modals-Bh_0en5P.js} +1 -1
- package/dashboard/dist/assets/{Select-CG_7h_Tz.js → Select-DC6zguGC.js} +1 -1
- package/dashboard/dist/assets/{SessionPanel-B5964GUj.js → SessionPanel-DNlLd-PL.js} +1 -1
- package/dashboard/dist/assets/{SystemTab-D7r1PsC9.js → SystemTab-uFqZinIZ.js} +1 -1
- package/dashboard/dist/assets/{index-BbplxgnQ.js → index-CL5H13Cl.js} +2 -2
- package/dashboard/dist/assets/index-DooLxbPX.js +23 -0
- package/dashboard/dist/assets/{shared-Bv8WvQSo.js → shared-Byy2BNLq.js} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/dist/agent/accounts.js +2 -2
- package/dist/agent/drivers/claude.js +84 -38
- package/dist/agent/drivers/codex.js +30 -2
- package/dist/agent/kernel-bridge.js +27 -3
- package/dist/bot/commands.js +43 -4
- package/dist/bot/render-shared.js +29 -23
- package/dist/channels/dingtalk/bot.js +3 -0
- package/dist/channels/discord/bot.js +3 -0
- package/dist/channels/feishu/render.js +3 -7
- package/dist/channels/slack/bot.js +3 -0
- package/dist/channels/telegram/bot.js +2 -2
- package/dist/channels/telegram/render.js +3 -3
- package/dist/channels/wecom/bot.js +3 -0
- package/dist/channels/weixin/bot.js +3 -0
- package/dist/dashboard/routes/accounts.js +7 -0
- package/dist/dashboard/routes/agents.js +1 -1
- package/package.json +1 -1
- package/packages/kernel/dist/drivers/claude.d.ts +12 -1
- package/packages/kernel/dist/drivers/claude.js +243 -26
- package/packages/kernel/dist/drivers/codex.js +15 -3
- package/packages/kernel/dist/index.d.ts +1 -1
- package/packages/kernel/dist/index.js +1 -1
- package/dashboard/dist/assets/index-CULTTvtY.js +0 -23
|
@@ -109,6 +109,22 @@ function buildKernelDriver(kernel, opts) {
|
|
|
109
109
|
};
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
|
+
// Kernel plan steps key their text as { text }; pikiloom's StreamPlan and the entire dashboard
|
|
113
|
+
// pipeline (pikichannel adapter -> ws.ts -> PlanProgressCard) key it as { step }. Translate at
|
|
114
|
+
// this seam — the same place we already remap usage fields — so codex/claude task lists render
|
|
115
|
+
// their text. Without it the progress count ("0/4") shows but every row is blank (the card reads
|
|
116
|
+
// step.step, which is undefined on the kernel shape).
|
|
117
|
+
export function toPikiloomPlan(plan) {
|
|
118
|
+
if (!plan || !Array.isArray(plan.steps))
|
|
119
|
+
return null;
|
|
120
|
+
const steps = plan.steps
|
|
121
|
+
.map((st) => ({
|
|
122
|
+
step: typeof st?.text === 'string' ? st.text : typeof st?.step === 'string' ? st.step : '',
|
|
123
|
+
status: (st?.status === 'completed' ? 'completed' : st?.status === 'inProgress' ? 'inProgress' : 'pending'),
|
|
124
|
+
}))
|
|
125
|
+
.filter((st) => st.step.trim());
|
|
126
|
+
return steps.length ? { explanation: typeof plan.explanation === 'string' ? plan.explanation : null, steps } : null;
|
|
127
|
+
}
|
|
112
128
|
let _kernel = null;
|
|
113
129
|
export async function loadKernel() {
|
|
114
130
|
if (_kernel)
|
|
@@ -185,7 +201,7 @@ export async function kernelStream(opts) {
|
|
|
185
201
|
providerName: opts.byokProviderName ?? null,
|
|
186
202
|
};
|
|
187
203
|
try {
|
|
188
|
-
opts.onText(s.text || '', s.reasoning || '', s.activity || '', m, s.plan
|
|
204
|
+
opts.onText(s.text || '', s.reasoning || '', s.activity || '', m, toPikiloomPlan(s.plan));
|
|
189
205
|
}
|
|
190
206
|
catch { /* isolate */ }
|
|
191
207
|
};
|
|
@@ -227,9 +243,17 @@ export async function kernelStream(opts) {
|
|
|
227
243
|
const u = result.usage || snapshot.usage || {};
|
|
228
244
|
return {
|
|
229
245
|
ok: !!result.ok,
|
|
230
|
-
|
|
246
|
+
// Empty-text fallback (mirrors the legacy driver): a clean turn with no prose reads
|
|
247
|
+
// "(no textual response)", not "(no output)" (which the kernel path used to show for every
|
|
248
|
+
// textless turn — including a background-launch turn that intentionally ends without prose).
|
|
249
|
+
// A turn that settled while work keeps running in the background gets an explicit note.
|
|
250
|
+
message: (result.text || snapshot.text || '').trim()
|
|
251
|
+
|| finalError
|
|
252
|
+
|| (result.stopReason === 'background'
|
|
253
|
+
? 'Work is now running in the background — I’ll report back here once it finishes. (Send any message to check on it.)'
|
|
254
|
+
: result.ok ? '(no textual response)' : '(no output)'),
|
|
231
255
|
thinking: (result.reasoning || snapshot.reasoning || '').trim() || null,
|
|
232
|
-
plan: snapshot.plan
|
|
256
|
+
plan: toPikiloomPlan(snapshot.plan),
|
|
233
257
|
sessionId: finalSessionId,
|
|
234
258
|
workspacePath: null,
|
|
235
259
|
model: input.model ?? null,
|
package/dist/bot/commands.js
CHANGED
|
@@ -3,6 +3,8 @@ import fs from 'node:fs';
|
|
|
3
3
|
import { fmtTokens, fmtUptime, fmtBytes } from './bot.js';
|
|
4
4
|
import { getProjectSkillPaths, normalizeClaudeModelId, sessionListDisplayTitle, listAllMcpExtensions, listSkills as listAllSkills, } from '../agent/index.js';
|
|
5
5
|
import { getDriver } from '../agent/driver.js';
|
|
6
|
+
import { accountAgentSupported, listAccounts, getActiveAccountId, probeAccountUsage, getCachedAccountUsage, } from '../agent/accounts.js';
|
|
7
|
+
import { withTimeoutFallback } from '../core/utils.js';
|
|
6
8
|
import { effortOptionsFor } from '../core/config/runtime-config.js';
|
|
7
9
|
import { getActiveProfile, getProvider } from '../model/index.js';
|
|
8
10
|
import { buildWelcomeIntro, buildSkillCommandName, indexSkillsByCommand, SKILL_CMD_PREFIX } from './menu.js';
|
|
@@ -421,16 +423,53 @@ export async function getModelsListData(bot, chatId) {
|
|
|
421
423
|
effort: buildEffortData(bot, cs.agent, currentModel),
|
|
422
424
|
};
|
|
423
425
|
}
|
|
426
|
+
// On-demand usage probe per agent. Bounded so `/status` stays snappy: each live probe falls
|
|
427
|
+
// back to the driver's cached value (and each account to its last-probed value) on timeout.
|
|
428
|
+
const USAGE_PROBE_TIMEOUT_MS = 2_500;
|
|
429
|
+
// Mirror the dashboard's top-right usage view for IM `/status`: every installed agent's usage,
|
|
430
|
+
// and for account-capable agents each account's own quota with the active one marked. The plain
|
|
431
|
+
// per-agent `getUsageLive` only ever reads the keychain default login, so without the per-account
|
|
432
|
+
// probes `/status` would always report the default account's numbers, never the selected one.
|
|
433
|
+
export async function getUsageOverview(bot, chatId) {
|
|
434
|
+
const currentAgent = bot.chat(chatId).agent;
|
|
435
|
+
const installed = bot.fetchAgents().agents.filter(a => a.installed);
|
|
436
|
+
const agents = await Promise.all(installed.map(async (info) => {
|
|
437
|
+
const agent = info.agent;
|
|
438
|
+
const model = bot.modelForAgent(agent);
|
|
439
|
+
const driver = getDriver(agent);
|
|
440
|
+
const cached = driver.getUsage({ agent, model });
|
|
441
|
+
const usage = driver.getUsageLive
|
|
442
|
+
? await withTimeoutFallback(driver.getUsageLive({ agent, model }).catch(() => cached), USAGE_PROBE_TIMEOUT_MS, cached)
|
|
443
|
+
: cached;
|
|
444
|
+
const accounts = [];
|
|
445
|
+
if (accountAgentSupported(agent)) {
|
|
446
|
+
const recs = listAccounts(agent);
|
|
447
|
+
if (recs.length) {
|
|
448
|
+
const activeId = getActiveAccountId(agent);
|
|
449
|
+
const usages = await Promise.all(recs.map(rec => withTimeoutFallback(probeAccountUsage(agent, rec.id).catch(() => getCachedAccountUsage(agent, rec.id)), USAGE_PROBE_TIMEOUT_MS, getCachedAccountUsage(agent, rec.id))));
|
|
450
|
+
recs.forEach((rec, i) => accounts.push({
|
|
451
|
+
id: rec.id, label: rec.label, active: rec.id === activeId, usage: usages[i],
|
|
452
|
+
}));
|
|
453
|
+
accounts.push({ id: null, label: 'Default login', active: activeId === null, usage });
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
return { agent, label: agentDisplayLabel(agent), isCurrent: agent === currentAgent, usage, accounts };
|
|
457
|
+
}));
|
|
458
|
+
return { agents };
|
|
459
|
+
}
|
|
424
460
|
export async function getStatusDataAsync(bot, chatId) {
|
|
425
461
|
const d = bot.getStatusData(chatId);
|
|
426
|
-
const
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
462
|
+
const usageOverview = await getUsageOverview(bot, chatId);
|
|
463
|
+
// Surface the identity that is actually selected: the active account's quota when one is
|
|
464
|
+
// bound, else the agent's native/default-login usage (matches the dashboard ring).
|
|
465
|
+
const current = usageOverview.agents.find(a => a.isCurrent);
|
|
466
|
+
const activeAccount = current?.accounts.find(a => a.active);
|
|
467
|
+
const usage = (activeAccount?.usage?.ok ? activeAccount.usage : null) ?? current?.usage ?? d.usage;
|
|
430
468
|
return {
|
|
431
469
|
...d,
|
|
432
470
|
running: d.running ? { prompt: d.running.prompt, startedAt: d.running.startedAt } : null,
|
|
433
471
|
usage,
|
|
472
|
+
usageOverview,
|
|
434
473
|
git: readGitStatus(d.workdir),
|
|
435
474
|
};
|
|
436
475
|
}
|
|
@@ -93,35 +93,41 @@ export function trimActivityForPreview(text, maxChars = 900) {
|
|
|
93
93
|
return tail.join('\n');
|
|
94
94
|
return [ellipsis, ...tail].join('\n');
|
|
95
95
|
}
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
// Compact "5h 42% · 7d 18%" summary of a usage snapshot (matches the dashboard bars and the
|
|
97
|
+
// `/agents` account rows), or a short reason when no quota numbers are available.
|
|
98
|
+
export function formatUsageWindowsSummary(usage) {
|
|
99
|
+
if (!usage || !usage.ok)
|
|
100
|
+
return 'unavailable';
|
|
101
|
+
const parts = usage.windows
|
|
102
|
+
.filter(w => w.usedPercent != null)
|
|
103
|
+
.map(w => `${w.label} ${Math.round(w.usedPercent)}%`);
|
|
104
|
+
if (parts.length)
|
|
105
|
+
return parts.join(' · ');
|
|
106
|
+
return usage.status ? `status=${usage.status}` : 'no data';
|
|
98
107
|
}
|
|
99
|
-
|
|
108
|
+
// Multi-agent / multi-account usage block for `/status`, mirroring the dashboard's top-right
|
|
109
|
+
// view: each installed agent that has usage, and for account-capable agents every account's own
|
|
110
|
+
// quota with the active one marked (●). Returns [] when nothing has usage so callers can skip the
|
|
111
|
+
// section entirely. Leading blank + bold header follow the same shape callers already render.
|
|
112
|
+
export function buildUsageOverviewLines(overview) {
|
|
113
|
+
const shown = overview.agents.filter(a => (a.usage?.ok && a.usage.windows.length) || a.accounts.length);
|
|
114
|
+
if (!shown.length)
|
|
115
|
+
return [];
|
|
100
116
|
const lines = [
|
|
101
117
|
{ text: '', bold: false },
|
|
102
118
|
{ text: 'Provider Usage', bold: true },
|
|
103
119
|
];
|
|
104
|
-
|
|
105
|
-
lines.push({ text:
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
120
|
+
for (const agent of shown) {
|
|
121
|
+
lines.push({ text: `${agent.label}${agent.isCurrent ? ' (current)' : ''}`, bold: true });
|
|
122
|
+
if (agent.accounts.length) {
|
|
123
|
+
for (const account of agent.accounts) {
|
|
124
|
+
const mark = account.active ? '●' : '○';
|
|
125
|
+
lines.push({ text: ` ${mark} ${account.label}: ${formatUsageWindowsSummary(account.usage)}` });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
lines.push({ text: ` ${formatUsageWindowsSummary(agent.usage)}` });
|
|
112
130
|
}
|
|
113
|
-
}
|
|
114
|
-
if (!usage.windows.length) {
|
|
115
|
-
lines.push({ text: ` ${usage.status ? `status=${usage.status}` : 'No window data'}` });
|
|
116
|
-
return lines;
|
|
117
|
-
}
|
|
118
|
-
for (const window of usage.windows) {
|
|
119
|
-
const details = rawUsageLine([
|
|
120
|
-
window.usedPercent != null ? `${window.usedPercent}% used` : null,
|
|
121
|
-
window.status ? `status=${window.status}` : null,
|
|
122
|
-
window.resetAfterSeconds != null ? `resetAfterSeconds=${window.resetAfterSeconds}` : null,
|
|
123
|
-
]);
|
|
124
|
-
lines.push({ text: ` ${window.label}: ${details || 'No details'}` });
|
|
125
131
|
}
|
|
126
132
|
return lines;
|
|
127
133
|
}
|
|
@@ -7,6 +7,7 @@ import { shutdownAllDrivers } from '../../agent/driver.js';
|
|
|
7
7
|
import { expandTilde } from '../../core/platform.js';
|
|
8
8
|
import { registerProcessRuntime, requestProcessRestart, } from '../../core/process-control.js';
|
|
9
9
|
import { getStatusDataAsync, getHostDataSync, getAgentsListData, getSkillsListData, getModelsListData, getSessionsPageData, getSessionsDigestData, formatSessionsDigestText, getStartData, getWorkspacesData, } from '../../bot/commands.js';
|
|
10
|
+
import { buildUsageOverviewLines } from '../../bot/render-shared.js';
|
|
10
11
|
import { DingtalkChannel } from './channel.js';
|
|
11
12
|
import { getActiveUserConfig } from '../../core/config/user-config.js';
|
|
12
13
|
const SHUTDOWN_EXIT_CODE = {
|
|
@@ -209,6 +210,8 @@ export class DingtalkBot extends Bot {
|
|
|
209
210
|
];
|
|
210
211
|
if (d.running)
|
|
211
212
|
lines.push(`Running: ${fmtUptime(Date.now() - d.running.startedAt)}`);
|
|
213
|
+
for (const line of buildUsageOverviewLines(d.usageOverview))
|
|
214
|
+
lines.push(line.text);
|
|
212
215
|
await ctx.reply(lines.join('\n'));
|
|
213
216
|
}
|
|
214
217
|
async cmdHost(ctx) {
|
|
@@ -7,6 +7,7 @@ import { shutdownAllDrivers } from '../../agent/driver.js';
|
|
|
7
7
|
import { expandTilde } from '../../core/platform.js';
|
|
8
8
|
import { registerProcessRuntime, requestProcessRestart, } from '../../core/process-control.js';
|
|
9
9
|
import { getStatusDataAsync, getHostDataSync, getAgentsListData, getSkillsListData, getModelsListData, getSessionsPageData, getSessionsDigestData, formatSessionsDigestText, getStartData, getWorkspacesData, } from '../../bot/commands.js';
|
|
10
|
+
import { buildUsageOverviewLines } from '../../bot/render-shared.js';
|
|
10
11
|
import { DiscordChannel } from './channel.js';
|
|
11
12
|
import { getActiveUserConfig } from '../../core/config/user-config.js';
|
|
12
13
|
const SHUTDOWN_EXIT_CODE = {
|
|
@@ -201,6 +202,8 @@ export class DiscordBot extends Bot {
|
|
|
201
202
|
];
|
|
202
203
|
if (d.running)
|
|
203
204
|
lines.push(`Running: ${fmtUptime(Date.now() - d.running.startedAt)}`);
|
|
205
|
+
for (const line of buildUsageOverviewLines(d.usageOverview))
|
|
206
|
+
lines.push(line.text);
|
|
204
207
|
await ctx.reply(lines.join('\n'));
|
|
205
208
|
}
|
|
206
209
|
async cmdHost(ctx) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { encodeCommandAction } from '../../bot/command-ui.js';
|
|
2
2
|
import { fmtUptime, fmtTokens, fmtBytes, formatGitStatusLine } from '../../bot/bot.js';
|
|
3
3
|
import { summarizePromptForStatus } from '../../bot/commands.js';
|
|
4
|
-
import { footerStatusSymbol, formatFooterParts, trimActivityForPreview,
|
|
4
|
+
import { footerStatusSymbol, formatFooterParts, trimActivityForPreview, buildUsageOverviewLines, extractFinalReplyData, extractStreamPreviewData, } from '../../bot/render-shared.js';
|
|
5
5
|
export { dispatchImageBlocks } from '../../bot/render-shared.js';
|
|
6
6
|
import { currentHumanLoopQuestion, humanLoopAnsweredCount, isHumanLoopAwaitingText, isHumanLoopQuestionAnswered, summarizeHumanLoopAnswer, } from '../../bot/human-loop.js';
|
|
7
7
|
import path from 'node:path';
|
|
@@ -432,12 +432,8 @@ export function renderStatus(d) {
|
|
|
432
432
|
if (d.running) {
|
|
433
433
|
lines.push(`**Running:** ${fmtUptime(Date.now() - d.running.startedAt)} - ${summarizePromptForStatus(d.running.prompt)}`);
|
|
434
434
|
}
|
|
435
|
-
const
|
|
436
|
-
|
|
437
|
-
lines.push('');
|
|
438
|
-
for (const line of usageLines) {
|
|
439
|
-
lines.push(line.text);
|
|
440
|
-
}
|
|
435
|
+
for (const line of buildUsageOverviewLines(d.usageOverview)) {
|
|
436
|
+
lines.push(line.bold && line.text ? `**${line.text}**` : line.text);
|
|
441
437
|
}
|
|
442
438
|
lines.push('', '**Bot Usage**', ` Turns: ${d.stats.totalTurns}`);
|
|
443
439
|
if (d.stats.totalInputTokens || d.stats.totalOutputTokens) {
|
|
@@ -7,6 +7,7 @@ import { shutdownAllDrivers } from '../../agent/driver.js';
|
|
|
7
7
|
import { expandTilde } from '../../core/platform.js';
|
|
8
8
|
import { registerProcessRuntime, requestProcessRestart, } from '../../core/process-control.js';
|
|
9
9
|
import { getStatusDataAsync, getHostDataSync, getAgentsListData, getSkillsListData, getModelsListData, getSessionsPageData, getSessionsDigestData, formatSessionsDigestText, getStartData, getWorkspacesData, } from '../../bot/commands.js';
|
|
10
|
+
import { buildUsageOverviewLines } from '../../bot/render-shared.js';
|
|
10
11
|
import { SlackChannel } from './channel.js';
|
|
11
12
|
import { getActiveUserConfig } from '../../core/config/user-config.js';
|
|
12
13
|
const SHUTDOWN_EXIT_CODE = {
|
|
@@ -210,6 +211,8 @@ export class SlackBot extends Bot {
|
|
|
210
211
|
];
|
|
211
212
|
if (d.running)
|
|
212
213
|
lines.push(`Running: ${fmtUptime(Date.now() - d.running.startedAt)}`);
|
|
214
|
+
for (const line of buildUsageOverviewLines(d.usageOverview))
|
|
215
|
+
lines.push(line.text);
|
|
213
216
|
await ctx.reply(lines.join('\n'));
|
|
214
217
|
}
|
|
215
218
|
async cmdHost(ctx) {
|
|
@@ -12,7 +12,7 @@ import { buildAgentsCommandView, buildModelsCommandView, buildModeCommandView, b
|
|
|
12
12
|
import { buildSwitchWorkdirView, buildWorkspacesView, resolveRegisteredPath } from './directory.js';
|
|
13
13
|
import { LivePreview } from './live-preview.js';
|
|
14
14
|
import { registerProcessRuntime, buildRestartCommand, requestProcessRestart, } from '../../core/process-control.js';
|
|
15
|
-
import { buildInitialPreviewHtml, buildHumanLoopPromptHtml, buildAnsweredHumanLoopPromptHtml, buildStreamPreviewHtml, buildFinalReplyRender, dispatchImageBlocks, escapeHtml, formatMenuLines,
|
|
15
|
+
import { buildInitialPreviewHtml, buildHumanLoopPromptHtml, buildAnsweredHumanLoopPromptHtml, buildStreamPreviewHtml, buildFinalReplyRender, dispatchImageBlocks, escapeHtml, formatMenuLines, formatUsageOverviewLines, renderCommandNoticeHtml, renderCommandSelectionHtml, renderCommandSelectionKeyboard, renderSessionTurnHtml, truncateMiddle, unpackCallbackData, } from './render.js';
|
|
16
16
|
import { currentHumanLoopQuestion, humanLoopOptionSelected } from '../../bot/human-loop.js';
|
|
17
17
|
import { TelegramChannel } from './channel.js';
|
|
18
18
|
import { splitText, supportsChannelCapability } from '../base.js';
|
|
@@ -344,7 +344,7 @@ export class TelegramBot extends Bot {
|
|
|
344
344
|
if (d.running) {
|
|
345
345
|
lines.push(`<b>Running:</b> ${fmtUptime(Date.now() - d.running.startedAt)} - ${escapeHtml(summarizePromptForStatus(d.running.prompt))}`);
|
|
346
346
|
}
|
|
347
|
-
lines.push(...
|
|
347
|
+
lines.push(...formatUsageOverviewLines(d.usageOverview), '', '<b>Bot Usage</b>', ` Turns: ${d.stats.totalTurns}`);
|
|
348
348
|
if (d.stats.totalInputTokens || d.stats.totalOutputTokens) {
|
|
349
349
|
lines.push(` In: ${fmtTokens(d.stats.totalInputTokens)} Out: ${fmtTokens(d.stats.totalOutputTokens)}`);
|
|
350
350
|
if (d.stats.totalCachedTokens)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { encodeCommandAction } from '../../bot/command-ui.js';
|
|
2
2
|
import { currentHumanLoopQuestion, humanLoopAnsweredCount, isHumanLoopAwaitingText, isHumanLoopQuestionAnswered, summarizeHumanLoopAnswer, } from '../../bot/human-loop.js';
|
|
3
|
-
import { footerStatusSymbol, formatFooterParts, trimActivityForPreview,
|
|
3
|
+
import { footerStatusSymbol, formatFooterParts, trimActivityForPreview, buildUsageOverviewLines, extractFinalReplyData, extractStreamPreviewData, parseGfmTable, } from '../../bot/render-shared.js';
|
|
4
4
|
export { dispatchImageBlocks } from '../../bot/render-shared.js';
|
|
5
5
|
export function escapeHtml(t) {
|
|
6
6
|
return t.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
@@ -308,8 +308,8 @@ function formatFinalFooterHtml(status, agent, elapsedMs, contextPercent, decorat
|
|
|
308
308
|
const primary = escapeHtml(`${footerStatusSymbol(status)} ${parts.identity}`);
|
|
309
309
|
return `${primary}\n<i>${escapeHtml(parts.runtime)}</i>`;
|
|
310
310
|
}
|
|
311
|
-
export function
|
|
312
|
-
return
|
|
311
|
+
export function formatUsageOverviewLines(overview) {
|
|
312
|
+
return buildUsageOverviewLines(overview).map(line => line.bold ? `<b>${escapeHtml(line.text)}</b>` : escapeHtml(line.text));
|
|
313
313
|
}
|
|
314
314
|
export function buildInitialPreviewHtml(agent, modelOrWaiting, effortOrQueuePosition, waitingArg = false, queuePositionArg = 0) {
|
|
315
315
|
let model = null;
|
|
@@ -7,6 +7,7 @@ import { shutdownAllDrivers } from '../../agent/driver.js';
|
|
|
7
7
|
import { expandTilde } from '../../core/platform.js';
|
|
8
8
|
import { registerProcessRuntime, requestProcessRestart, } from '../../core/process-control.js';
|
|
9
9
|
import { getStatusDataAsync, getHostDataSync, getAgentsListData, getSkillsListData, getModelsListData, getSessionsPageData, getSessionsDigestData, formatSessionsDigestText, getStartData, getWorkspacesData, } from '../../bot/commands.js';
|
|
10
|
+
import { buildUsageOverviewLines } from '../../bot/render-shared.js';
|
|
10
11
|
import { WeComChannel } from './channel.js';
|
|
11
12
|
import { getActiveUserConfig } from '../../core/config/user-config.js';
|
|
12
13
|
const SHUTDOWN_EXIT_CODE = {
|
|
@@ -217,6 +218,8 @@ export class WeComBot extends Bot {
|
|
|
217
218
|
];
|
|
218
219
|
if (d.running)
|
|
219
220
|
lines.push(`Running: ${fmtUptime(Date.now() - d.running.startedAt)}`);
|
|
221
|
+
for (const line of buildUsageOverviewLines(d.usageOverview))
|
|
222
|
+
lines.push(line.text);
|
|
220
223
|
await ctx.reply(lines.join('\n'));
|
|
221
224
|
}
|
|
222
225
|
async cmdHost(ctx) {
|
|
@@ -9,6 +9,7 @@ import { shutdownAllDrivers } from '../../agent/driver.js';
|
|
|
9
9
|
import { expandTilde } from '../../core/platform.js';
|
|
10
10
|
import { registerProcessRuntime, requestProcessRestart, } from '../../core/process-control.js';
|
|
11
11
|
import { getStatusDataAsync, getHostDataSync, getModelsListData, getSessionsPageData, getSessionsDigestData, formatSessionsDigestText, getStartData, getWorkspacesData, handleGoalCommand, } from '../../bot/commands.js';
|
|
12
|
+
import { buildUsageOverviewLines } from '../../bot/render-shared.js';
|
|
12
13
|
import { WeixinChannel } from './channel.js';
|
|
13
14
|
import { getActiveUserConfig } from '../../core/config/user-config.js';
|
|
14
15
|
const SHUTDOWN_EXIT_CODE = {
|
|
@@ -254,6 +255,8 @@ export class WeixinBot extends Bot {
|
|
|
254
255
|
if (d.running) {
|
|
255
256
|
lines.push(`Running: ${fmtUptime(Date.now() - d.running.startedAt)}`);
|
|
256
257
|
}
|
|
258
|
+
for (const line of buildUsageOverviewLines(d.usageOverview))
|
|
259
|
+
lines.push(line.text);
|
|
257
260
|
await ctx.reply(lines.join('\n'));
|
|
258
261
|
}
|
|
259
262
|
async cmdHost(ctx) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
2
|
import { allDriverIds } from '../../agent/index.js';
|
|
3
3
|
import { accountAgentSupported, listAccounts, getAccount, addAccount, updateAccount, removeAccount, getActiveAccountId, setActiveAccount, probeAccountUsage, MAX_ACCOUNTS_PER_AGENT, } from '../../agent/accounts.js';
|
|
4
|
+
import { invalidateAgentStatus } from './agents.js';
|
|
4
5
|
const app = new Hono();
|
|
5
6
|
function agentError(agent) {
|
|
6
7
|
if (!allDriverIds().includes(agent))
|
|
@@ -104,6 +105,12 @@ app.post('/api/agents/:agent/active-account', async (c) => {
|
|
|
104
105
|
return c.json({ ok: false, error: 'accountId (string|null) is required' }, 400);
|
|
105
106
|
try {
|
|
106
107
|
setActiveAccount(agent, accountId);
|
|
108
|
+
// The identity that drives usage just changed: drop the cached agent-status (its native /
|
|
109
|
+
// default-login usage is now stale) and force-refresh the newly-active account's own usage,
|
|
110
|
+
// so the header reflects the latest numbers immediately instead of the previous account's.
|
|
111
|
+
if (accountId)
|
|
112
|
+
await probeAccountUsage(agent, accountId, { force: true });
|
|
113
|
+
await invalidateAgentStatus();
|
|
107
114
|
return c.json({ ok: true, agent, activeAccountId: accountId });
|
|
108
115
|
}
|
|
109
116
|
catch (e) {
|
|
@@ -238,7 +238,7 @@ function getCachedAgentStatus() {
|
|
|
238
238
|
}
|
|
239
239
|
return refreshStatusCache();
|
|
240
240
|
}
|
|
241
|
-
function invalidateAgentStatus(config, opts) {
|
|
241
|
+
export function invalidateAgentStatus(config, opts) {
|
|
242
242
|
statusCache.pending = null;
|
|
243
243
|
return refreshStatusCache(config, opts);
|
|
244
244
|
}
|
package/package.json
CHANGED
|
@@ -30,9 +30,20 @@ export declare function claudeUsageOf(s: ClaudeUsageState): UniversalUsage;
|
|
|
30
30
|
export declare function claudeContextWindowFromModel(model: unknown): number | null;
|
|
31
31
|
export declare function claudeEffectiveContextWindow(advertised: number | null): number | null;
|
|
32
32
|
export declare function handleClaudeEvent(ev: any, s: any, emit: (e: DriverEvent) => void): void;
|
|
33
|
-
export declare function
|
|
33
|
+
export declare function claudeBgHoldCapMs(): number;
|
|
34
|
+
export declare function isTerminalTaskStatus(status: unknown): boolean;
|
|
35
|
+
export declare function trackClaudeBackgroundTask(ev: any, s: any): void;
|
|
36
|
+
export declare function pendingClaudeBackgroundTasks(s: any): number;
|
|
37
|
+
export type ClaudeResultSettleDecision = 'settle' | 'hold';
|
|
38
|
+
export declare function decideClaudeResultSettle(input: {
|
|
39
|
+
hasError: boolean;
|
|
40
|
+
pendingBackground: number;
|
|
41
|
+
}): ClaudeResultSettleDecision;
|
|
42
|
+
export declare function claudeUserMessage(text: string, attachments?: string[]): string;
|
|
34
43
|
export declare function emitClaudeImages(blocks: any[], s: any, emit: (e: DriverEvent) => void): void;
|
|
35
44
|
export declare function todoWriteToPlan(input: any): UniversalPlan | null;
|
|
45
|
+
export declare function readClaudeTaskCreateId(ev: any, block: any): string | null;
|
|
46
|
+
export declare function rebuildClaudeTaskPlan(s: any): UniversalPlan | null;
|
|
36
47
|
export declare function shortToolValue(value: unknown, max?: number): string;
|
|
37
48
|
export declare function summarizeToolUse(name: string, input: any): string;
|
|
38
49
|
export declare function firstResultLine(content: any): string;
|