switchroom 0.19.0 → 0.19.2
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/agent-scheduler/index.js +29 -1
- package/dist/auth-broker/index.js +552 -48
- package/dist/cli/autoaccept-poll.js +29 -1
- package/dist/cli/drive-write-pretool.mjs +30 -2
- package/dist/cli/ms-365-write-pretool.mjs +30 -2
- package/dist/cli/switchroom.js +751 -36
- package/dist/host-control/main.js +3 -3
- package/dist/vault/approvals/kernel-server.js +2 -2
- package/dist/vault/broker/server.js +2 -2
- package/package.json +3 -2
- package/profiles/_base/start.sh.hbs +1 -0
- package/skills/switchroom-cli/SKILL.md +25 -0
- package/telegram-plugin/auth-snapshot-format.ts +39 -0
- package/telegram-plugin/dist/gateway/gateway.js +363 -25
- package/telegram-plugin/external-spend.ts +135 -0
- package/telegram-plugin/gateway/gateway.ts +83 -67
- package/telegram-plugin/gateway/model-command.ts +106 -0
- package/telegram-plugin/gateway/narrative-lane.ts +23 -9
- package/telegram-plugin/gateway/status-pin-store.ts +64 -4
- package/telegram-plugin/gateway/usage-mask.ts +29 -0
- package/telegram-plugin/hooks/subagent-tracker-pretool.mjs +19 -2
- package/telegram-plugin/quota-bar-format.ts +18 -0
- package/telegram-plugin/quota-check.ts +17 -2
- package/telegram-plugin/tests/activity-card-wiring.test.ts +47 -0
- package/telegram-plugin/tests/external-spend.test.ts +168 -0
- package/telegram-plugin/tests/gateway-session-model-relaunch.test.ts +57 -23
- package/telegram-plugin/tests/quota-bar-format.test.ts +43 -0
- package/telegram-plugin/tests/quota-check.test.ts +57 -0
- package/telegram-plugin/tests/status-pin-store.test.ts +198 -0
- package/telegram-plugin/tests/subagent-tracker-hooks.test.ts +50 -0
- package/telegram-plugin/tests/usage-footer-freshness.test.ts +141 -0
- package/telegram-plugin/tests/usage-mask.test.ts +35 -0
- package/telegram-plugin/tests/worker-feed-dispatch.test.ts +27 -0
- package/telegram-plugin/tests/worker-feed-pin-persistence.test.ts +131 -1
|
@@ -22057,6 +22057,7 @@ __export(exports_auth_snapshot_format, {
|
|
|
22057
22057
|
formatRelative: () => formatRelative,
|
|
22058
22058
|
formatAbsolute: () => formatAbsolute,
|
|
22059
22059
|
fmtPct: () => fmtPct,
|
|
22060
|
+
deriveUsageFooterFreshness: () => deriveUsageFooterFreshness,
|
|
22060
22061
|
classifyHealth: () => classifyHealth,
|
|
22061
22062
|
buildSnapshotsFromState: () => buildSnapshotsFromState,
|
|
22062
22063
|
buildSnapshotsFromCachedState: () => buildSnapshotsFromCachedState,
|
|
@@ -22467,6 +22468,13 @@ function zipProbeResults(labels, results) {
|
|
|
22467
22468
|
});
|
|
22468
22469
|
return staleCachedAtMs != null ? { quotas, staleCachedAtMs } : { quotas };
|
|
22469
22470
|
}
|
|
22471
|
+
function deriveUsageFooterFreshness(results, staleCachedAtMs, liveProbedAtMs) {
|
|
22472
|
+
if (staleCachedAtMs != null)
|
|
22473
|
+
return { staleCachedAtMs };
|
|
22474
|
+
if (results.some((r) => r.result.ok))
|
|
22475
|
+
return { liveProbedAtMs };
|
|
22476
|
+
return { probeFailed: true };
|
|
22477
|
+
}
|
|
22470
22478
|
function buildSnapshotsFromState(state, quotas) {
|
|
22471
22479
|
const out = [];
|
|
22472
22480
|
for (let i = 0;i < state.accounts.length; i++) {
|
|
@@ -22549,7 +22557,7 @@ function decodeResponse2(line) {
|
|
|
22549
22557
|
}
|
|
22550
22558
|
return ResponseSchema2.parse(parsed);
|
|
22551
22559
|
}
|
|
22552
|
-
var MAX_FRAME_BYTES2, PROTOCOL_VERSION = 1, ProviderNameSchema, GetCredentialsRequestSchema, ListStateRequestSchema, SetActiveRequestSchema, MarkExhaustedRequestSchema, MarkThrottledRequestSchema, RefreshAccountRequestSchema, AnthropicCredentialsSchema, GoogleCredentialsSchema, MicrosoftCredentialsSchema, ProviderCredentialsSchema, AddAccountRequestSchema, RmAccountRequestSchema, SetOverrideRequestSchema, ListGoogleAccountsRequestSchema, ListMicrosoftAccountsRequestSchema, ProbeQuotaRequestSchema, ClaimNotificationRequestSchema, RequestSchema2, GetCredentialsDataSchema, AccountStateSchema, AgentStateSchema, ConsumerStateSchema, ListStateDataSchema, SetActiveDataSchema, MarkExhaustedDataSchema, MarkThrottledDataSchema, RefreshAccountDataSchema, AddAccountDataSchema, RmAccountDataSchema, SetOverrideDataSchema, ClaimNotificationDataSchema, GoogleAccountStateSchema, ListGoogleAccountsDataSchema, MicrosoftAccountStateSchema, ListMicrosoftAccountsDataSchema, ErrorBodySchema, SuccessResponseSchema, ErrorResponseSchema2, ResponseSchema2;
|
|
22560
|
+
var MAX_FRAME_BYTES2, PROTOCOL_VERSION = 1, ProviderNameSchema, GetCredentialsRequestSchema, ListStateRequestSchema, SetActiveRequestSchema, MarkExhaustedRequestSchema, MarkThrottledRequestSchema, RefreshAccountRequestSchema, AnthropicCredentialsSchema, GoogleCredentialsSchema, MicrosoftCredentialsSchema, ProviderCredentialsSchema, AddAccountRequestSchema, RmAccountRequestSchema, SetOverrideRequestSchema, ListGoogleAccountsRequestSchema, ListMicrosoftAccountsRequestSchema, ProbeQuotaRequestSchema, ClaimNotificationRequestSchema, GetExternalSpendRequestSchema, RequestSchema2, GetCredentialsDataSchema, AccountStateSchema, AgentStateSchema, ConsumerStateSchema, ListStateDataSchema, SetActiveDataSchema, MarkExhaustedDataSchema, MarkThrottledDataSchema, RefreshAccountDataSchema, AddAccountDataSchema, RmAccountDataSchema, SetOverrideDataSchema, ClaimNotificationDataSchema, GetExternalSpendDataSchema, GoogleAccountStateSchema, ListGoogleAccountsDataSchema, MicrosoftAccountStateSchema, ListMicrosoftAccountsDataSchema, ErrorBodySchema, SuccessResponseSchema, ErrorResponseSchema2, ResponseSchema2;
|
|
22553
22561
|
var init_protocol2 = __esm(() => {
|
|
22554
22562
|
init_zod();
|
|
22555
22563
|
MAX_FRAME_BYTES2 = 64 * 1024;
|
|
@@ -22680,6 +22688,12 @@ var init_protocol2 = __esm(() => {
|
|
|
22680
22688
|
key: exports_external.string().min(1).max(512),
|
|
22681
22689
|
windowMs: exports_external.number().int().positive().max(86400000)
|
|
22682
22690
|
});
|
|
22691
|
+
GetExternalSpendRequestSchema = exports_external.object({
|
|
22692
|
+
v: exports_external.literal(PROTOCOL_VERSION),
|
|
22693
|
+
op: exports_external.literal("get-external-spend"),
|
|
22694
|
+
id: exports_external.string().min(1),
|
|
22695
|
+
forceLive: exports_external.boolean().optional()
|
|
22696
|
+
});
|
|
22683
22697
|
RequestSchema2 = exports_external.discriminatedUnion("op", [
|
|
22684
22698
|
GetCredentialsRequestSchema,
|
|
22685
22699
|
ListStateRequestSchema,
|
|
@@ -22693,7 +22707,8 @@ var init_protocol2 = __esm(() => {
|
|
|
22693
22707
|
ListGoogleAccountsRequestSchema,
|
|
22694
22708
|
ListMicrosoftAccountsRequestSchema,
|
|
22695
22709
|
ProbeQuotaRequestSchema,
|
|
22696
|
-
ClaimNotificationRequestSchema
|
|
22710
|
+
ClaimNotificationRequestSchema,
|
|
22711
|
+
GetExternalSpendRequestSchema
|
|
22697
22712
|
]);
|
|
22698
22713
|
GetCredentialsDataSchema = exports_external.object({
|
|
22699
22714
|
account: exports_external.string(),
|
|
@@ -22760,6 +22775,18 @@ var init_protocol2 = __esm(() => {
|
|
|
22760
22775
|
ClaimNotificationDataSchema = exports_external.object({
|
|
22761
22776
|
granted: exports_external.boolean()
|
|
22762
22777
|
});
|
|
22778
|
+
GetExternalSpendDataSchema = exports_external.object({
|
|
22779
|
+
available: exports_external.boolean(),
|
|
22780
|
+
day24hUsd: exports_external.number().optional(),
|
|
22781
|
+
day7dUsd: exports_external.number().optional(),
|
|
22782
|
+
top: exports_external.array(exports_external.object({
|
|
22783
|
+
label: exports_external.string(),
|
|
22784
|
+
usd: exports_external.number()
|
|
22785
|
+
})).optional(),
|
|
22786
|
+
capturedAtMs: exports_external.number().int().nonnegative().optional(),
|
|
22787
|
+
served: exports_external.enum(["live", "cache"]).optional(),
|
|
22788
|
+
reason: exports_external.string().optional()
|
|
22789
|
+
});
|
|
22763
22790
|
GoogleAccountStateSchema = exports_external.object({
|
|
22764
22791
|
account: exports_external.string(),
|
|
22765
22792
|
expiresAt: exports_external.number(),
|
|
@@ -22930,6 +22957,15 @@ class AuthBrokerClient {
|
|
|
22930
22957
|
}
|
|
22931
22958
|
return parsed;
|
|
22932
22959
|
}
|
|
22960
|
+
async getExternalSpend(forceLive) {
|
|
22961
|
+
const data = await this.send({
|
|
22962
|
+
v: PROTOCOL_VERSION,
|
|
22963
|
+
id: randomUUID(),
|
|
22964
|
+
op: "get-external-spend",
|
|
22965
|
+
...forceLive ? { forceLive: true } : {}
|
|
22966
|
+
});
|
|
22967
|
+
return data;
|
|
22968
|
+
}
|
|
22933
22969
|
async setActive(account) {
|
|
22934
22970
|
const data = await this.send({
|
|
22935
22971
|
v: PROTOCOL_VERSION,
|
|
@@ -29337,7 +29373,7 @@ var FLUSH_SUPPRESSION_WINDOW_MS = 2000;
|
|
|
29337
29373
|
var init_turn_flush_suppression = () => {};
|
|
29338
29374
|
|
|
29339
29375
|
// ../src/util/atomic.ts
|
|
29340
|
-
import { closeSync as closeSync6, constants as constants2, fsyncSync as fsyncSync2, openSync as openSync6, renameSync as renameSync11, rmSync as rmSync5, writeSync as writeSync4 } from "node:fs";
|
|
29376
|
+
import { closeSync as closeSync6, constants as constants2, fchmodSync, fchownSync, fsyncSync as fsyncSync2, openSync as openSync6, renameSync as renameSync11, rmSync as rmSync5, writeSync as writeSync4 } from "node:fs";
|
|
29341
29377
|
var TMP_OPEN_FLAGS;
|
|
29342
29378
|
var init_atomic = __esm(() => {
|
|
29343
29379
|
TMP_OPEN_FLAGS = constants2.O_WRONLY | constants2.O_CREAT | constants2.O_EXCL | (constants2.O_NOFOLLOW ?? 0);
|
|
@@ -36742,6 +36778,7 @@ __export(exports_auth_snapshot_format2, {
|
|
|
36742
36778
|
formatRelative: () => formatRelative2,
|
|
36743
36779
|
formatAbsolute: () => formatAbsolute2,
|
|
36744
36780
|
fmtPct: () => fmtPct2,
|
|
36781
|
+
deriveUsageFooterFreshness: () => deriveUsageFooterFreshness2,
|
|
36745
36782
|
classifyHealth: () => classifyHealth2,
|
|
36746
36783
|
buildSnapshotsFromState: () => buildSnapshotsFromState2,
|
|
36747
36784
|
buildSnapshotsFromCachedState: () => buildSnapshotsFromCachedState2,
|
|
@@ -37152,6 +37189,13 @@ function zipProbeResults2(labels, results) {
|
|
|
37152
37189
|
});
|
|
37153
37190
|
return staleCachedAtMs != null ? { quotas, staleCachedAtMs } : { quotas };
|
|
37154
37191
|
}
|
|
37192
|
+
function deriveUsageFooterFreshness2(results, staleCachedAtMs, liveProbedAtMs) {
|
|
37193
|
+
if (staleCachedAtMs != null)
|
|
37194
|
+
return { staleCachedAtMs };
|
|
37195
|
+
if (results.some((r) => r.result.ok))
|
|
37196
|
+
return { liveProbedAtMs };
|
|
37197
|
+
return { probeFailed: true };
|
|
37198
|
+
}
|
|
37155
37199
|
function buildSnapshotsFromState2(state7, quotas) {
|
|
37156
37200
|
const out = [];
|
|
37157
37201
|
for (let i = 0;i < state7.accounts.length; i++) {
|
|
@@ -37626,6 +37670,140 @@ var init_config_approval_handler = __esm(() => {
|
|
|
37626
37670
|
pending = new Map;
|
|
37627
37671
|
});
|
|
37628
37672
|
|
|
37673
|
+
// ../src/litellm/external-spend.ts
|
|
37674
|
+
function isExternalModel(model) {
|
|
37675
|
+
const m = model.trim().toLowerCase();
|
|
37676
|
+
if (!m)
|
|
37677
|
+
return false;
|
|
37678
|
+
if (m.startsWith("claude"))
|
|
37679
|
+
return false;
|
|
37680
|
+
if (m.includes("anthropic/claude"))
|
|
37681
|
+
return false;
|
|
37682
|
+
if (m.startsWith("openrouter/"))
|
|
37683
|
+
return true;
|
|
37684
|
+
if (m.startsWith("sr-"))
|
|
37685
|
+
return true;
|
|
37686
|
+
for (const needle of BARE_EXTERNAL_NEEDLES) {
|
|
37687
|
+
if (m.includes(needle))
|
|
37688
|
+
return true;
|
|
37689
|
+
}
|
|
37690
|
+
return false;
|
|
37691
|
+
}
|
|
37692
|
+
function shortModelLabel(model) {
|
|
37693
|
+
let m = model.trim();
|
|
37694
|
+
if (m.toLowerCase().startsWith("openrouter/")) {
|
|
37695
|
+
m = m.slice("openrouter/".length);
|
|
37696
|
+
}
|
|
37697
|
+
const parts = m.split("/").filter(Boolean);
|
|
37698
|
+
if (parts.length >= 2) {
|
|
37699
|
+
m = parts[parts.length - 1];
|
|
37700
|
+
}
|
|
37701
|
+
if (m.toLowerCase().startsWith("sr-")) {
|
|
37702
|
+
m = m.slice(3);
|
|
37703
|
+
}
|
|
37704
|
+
return m || model.trim();
|
|
37705
|
+
}
|
|
37706
|
+
function formatUsd(n) {
|
|
37707
|
+
if (!Number.isFinite(n) || n < 0)
|
|
37708
|
+
return "$0.00";
|
|
37709
|
+
return `$${n.toFixed(2)}`;
|
|
37710
|
+
}
|
|
37711
|
+
function utcDateString(d) {
|
|
37712
|
+
return d.toISOString().slice(0, 10);
|
|
37713
|
+
}
|
|
37714
|
+
function addUtcDays(dateStr, days) {
|
|
37715
|
+
const [y, m, d] = dateStr.split("-").map(Number);
|
|
37716
|
+
const dt = new Date(Date.UTC(y, m - 1, d));
|
|
37717
|
+
dt.setUTCDate(dt.getUTCDate() + days);
|
|
37718
|
+
return utcDateString(dt);
|
|
37719
|
+
}
|
|
37720
|
+
function rowDay(row) {
|
|
37721
|
+
const st = row.startTime;
|
|
37722
|
+
if (!st || typeof st !== "string")
|
|
37723
|
+
return null;
|
|
37724
|
+
return st.length >= 10 ? st.slice(0, 10) : null;
|
|
37725
|
+
}
|
|
37726
|
+
function externalModelsFromRow(row) {
|
|
37727
|
+
const out = {};
|
|
37728
|
+
const models = row.models ?? {};
|
|
37729
|
+
for (const [name, raw] of Object.entries(models)) {
|
|
37730
|
+
if (!isExternalModel(name))
|
|
37731
|
+
continue;
|
|
37732
|
+
const n = typeof raw === "number" ? raw : Number(raw);
|
|
37733
|
+
if (!Number.isFinite(n) || n === 0)
|
|
37734
|
+
continue;
|
|
37735
|
+
out[name] = (out[name] ?? 0) + n;
|
|
37736
|
+
}
|
|
37737
|
+
return out;
|
|
37738
|
+
}
|
|
37739
|
+
function summarizeExternalSpend(days, now = new Date) {
|
|
37740
|
+
const today = utcDateString(now);
|
|
37741
|
+
const start7 = addUtcDays(today, -6);
|
|
37742
|
+
let day24hUsd = 0;
|
|
37743
|
+
let day7dUsd = 0;
|
|
37744
|
+
const byModel = {};
|
|
37745
|
+
for (const row of days) {
|
|
37746
|
+
const day = rowDay(row);
|
|
37747
|
+
if (!day)
|
|
37748
|
+
continue;
|
|
37749
|
+
if (day < start7 || day > today)
|
|
37750
|
+
continue;
|
|
37751
|
+
const ext = externalModelsFromRow(row);
|
|
37752
|
+
let rowSum = 0;
|
|
37753
|
+
for (const [name, usd] of Object.entries(ext)) {
|
|
37754
|
+
rowSum += usd;
|
|
37755
|
+
byModel[name] = (byModel[name] ?? 0) + usd;
|
|
37756
|
+
}
|
|
37757
|
+
day7dUsd += rowSum;
|
|
37758
|
+
if (day === today)
|
|
37759
|
+
day24hUsd += rowSum;
|
|
37760
|
+
}
|
|
37761
|
+
const top = Object.entries(byModel).filter(([, usd]) => usd > 0).sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, EXTERNAL_SPEND_TOP_N).map(([name, usd]) => ({ label: shortModelLabel(name), usd }));
|
|
37762
|
+
return { day24hUsd, day7dUsd, top };
|
|
37763
|
+
}
|
|
37764
|
+
function normalizeSpendLogRows(body) {
|
|
37765
|
+
if (Array.isArray(body))
|
|
37766
|
+
return body;
|
|
37767
|
+
if (body && typeof body === "object") {
|
|
37768
|
+
const data = body.data;
|
|
37769
|
+
if (Array.isArray(data))
|
|
37770
|
+
return data;
|
|
37771
|
+
}
|
|
37772
|
+
return [];
|
|
37773
|
+
}
|
|
37774
|
+
var EXTERNAL_SPEND_TOP_N = 3, EXTERNAL_SPEND_CACHE_TTL_MS = 90000, BARE_EXTERNAL_NEEDLES;
|
|
37775
|
+
var init_external_spend = __esm(() => {
|
|
37776
|
+
BARE_EXTERNAL_NEEDLES = [
|
|
37777
|
+
"gpt-oss",
|
|
37778
|
+
"grok",
|
|
37779
|
+
"gemini",
|
|
37780
|
+
"deepseek",
|
|
37781
|
+
"kimi",
|
|
37782
|
+
"glm-",
|
|
37783
|
+
"qwen",
|
|
37784
|
+
"llama"
|
|
37785
|
+
];
|
|
37786
|
+
});
|
|
37787
|
+
|
|
37788
|
+
// external-spend.ts
|
|
37789
|
+
function formatExternalSpendBlock(summary) {
|
|
37790
|
+
if (summary == null)
|
|
37791
|
+
return [];
|
|
37792
|
+
const lines = [
|
|
37793
|
+
"- \uD83D\uDCB8 External",
|
|
37794
|
+
`- 24h \`${formatUsd(summary.day24hUsd)}\` \u00b7 7d \`${formatUsd(summary.day7dUsd)}\``
|
|
37795
|
+
];
|
|
37796
|
+
if (summary.top.length > 0) {
|
|
37797
|
+
const topParts = summary.top.map((t) => `\`${t.label} ${formatUsd(t.usd)}\``);
|
|
37798
|
+
lines.push(`- top ${topParts.join(" \u00b7 ")}`);
|
|
37799
|
+
}
|
|
37800
|
+
return lines;
|
|
37801
|
+
}
|
|
37802
|
+
var init_external_spend2 = __esm(() => {
|
|
37803
|
+
init_external_spend();
|
|
37804
|
+
init_external_spend();
|
|
37805
|
+
});
|
|
37806
|
+
|
|
37629
37807
|
// quota-bar-format.ts
|
|
37630
37808
|
var exports_quota_bar_format = {};
|
|
37631
37809
|
__export(exports_quota_bar_format, {
|
|
@@ -37747,6 +37925,9 @@ function renderUsageCard(snapshots, exhaustedByLabel, opts = {}) {
|
|
|
37747
37925
|
const bar = renderQuotaBarBlock(snapshots, exhaustedByLabel, { now, demo });
|
|
37748
37926
|
const lines = [bar];
|
|
37749
37927
|
lines.push(`_${recommendation(snapshots, now, demo)}_`);
|
|
37928
|
+
if (opts.externalSpend != null) {
|
|
37929
|
+
lines.push(...formatExternalSpendBlock(opts.externalSpend));
|
|
37930
|
+
}
|
|
37750
37931
|
if (opts.staleCachedAtMs != null) {
|
|
37751
37932
|
lines.push(`_\u26a0 cached ${formatAgeStamp3(opts.staleCachedAtMs, now)}_`);
|
|
37752
37933
|
} else if (opts.liveProbedAtMs != null) {
|
|
@@ -37764,10 +37945,85 @@ var init_quota_bar_format = __esm(() => {
|
|
|
37764
37945
|
init_auth_snapshot_format();
|
|
37765
37946
|
init_card_format();
|
|
37766
37947
|
init_demo_mask();
|
|
37948
|
+
init_external_spend2();
|
|
37767
37949
|
FIVE_HOUR_MS = 5 * 60 * 60 * 1000;
|
|
37768
37950
|
SEVEN_DAY_MS = 7 * 24 * 60 * 60 * 1000;
|
|
37769
37951
|
});
|
|
37770
37952
|
|
|
37953
|
+
// external-spend.ts
|
|
37954
|
+
var exports_external_spend = {};
|
|
37955
|
+
__export(exports_external_spend, {
|
|
37956
|
+
utcDateString: () => utcDateString,
|
|
37957
|
+
summarizeExternalSpend: () => summarizeExternalSpend,
|
|
37958
|
+
shortModelLabel: () => shortModelLabel,
|
|
37959
|
+
normalizeSpendLogRows: () => normalizeSpendLogRows,
|
|
37960
|
+
isExternalModel: () => isExternalModel,
|
|
37961
|
+
formatUsd: () => formatUsd,
|
|
37962
|
+
formatExternalSpendBlock: () => formatExternalSpendBlock2,
|
|
37963
|
+
fetchExternalSpendSummary: () => fetchExternalSpendSummary,
|
|
37964
|
+
clearExternalSpendCache: () => clearExternalSpendCache,
|
|
37965
|
+
addUtcDays: () => addUtcDays,
|
|
37966
|
+
EXTERNAL_SPEND_CACHE_TTL_MS: () => EXTERNAL_SPEND_CACHE_TTL_MS
|
|
37967
|
+
});
|
|
37968
|
+
function clearExternalSpendCache() {
|
|
37969
|
+
clientCache = null;
|
|
37970
|
+
}
|
|
37971
|
+
function formatExternalSpendBlock2(summary) {
|
|
37972
|
+
if (summary == null)
|
|
37973
|
+
return [];
|
|
37974
|
+
const lines = [
|
|
37975
|
+
"- \uD83D\uDCB8 External",
|
|
37976
|
+
`- 24h \`${formatUsd(summary.day24hUsd)}\` \u00b7 7d \`${formatUsd(summary.day7dUsd)}\``
|
|
37977
|
+
];
|
|
37978
|
+
if (summary.top.length > 0) {
|
|
37979
|
+
const topParts = summary.top.map((t) => `\`${t.label} ${formatUsd(t.usd)}\``);
|
|
37980
|
+
lines.push(`- top ${topParts.join(" \u00b7 ")}`);
|
|
37981
|
+
}
|
|
37982
|
+
return lines;
|
|
37983
|
+
}
|
|
37984
|
+
async function fetchExternalSpendSummary(nowOrDeps = {}) {
|
|
37985
|
+
const deps = nowOrDeps instanceof Date ? { now: nowOrDeps } : nowOrDeps;
|
|
37986
|
+
const ttl = deps.cacheTtlMs ?? CLIENT_CACHE_TTL_MS;
|
|
37987
|
+
if (!deps.bypassCache && clientCache && Date.now() - clientCache.atMs < ttl) {
|
|
37988
|
+
return clientCache.summary;
|
|
37989
|
+
}
|
|
37990
|
+
try {
|
|
37991
|
+
let data;
|
|
37992
|
+
if (deps.getExternalSpend) {
|
|
37993
|
+
data = await deps.getExternalSpend(deps.forceLive);
|
|
37994
|
+
} else {
|
|
37995
|
+
const { AuthBrokerClient: AuthBrokerClient3 } = await Promise.resolve().then(() => (init_client2(), exports_client));
|
|
37996
|
+
const client3 = new AuthBrokerClient3;
|
|
37997
|
+
try {
|
|
37998
|
+
data = await client3.getExternalSpend(deps.forceLive);
|
|
37999
|
+
} finally {
|
|
38000
|
+
try {
|
|
38001
|
+
await client3.close();
|
|
38002
|
+
} catch {}
|
|
38003
|
+
}
|
|
38004
|
+
}
|
|
38005
|
+
if (!data?.available)
|
|
38006
|
+
return null;
|
|
38007
|
+
if (typeof data.day24hUsd !== "number" || typeof data.day7dUsd !== "number" || !Array.isArray(data.top)) {
|
|
38008
|
+
return null;
|
|
38009
|
+
}
|
|
38010
|
+
const summary = {
|
|
38011
|
+
day24hUsd: data.day24hUsd,
|
|
38012
|
+
day7dUsd: data.day7dUsd,
|
|
38013
|
+
top: data.top.map((t) => ({ label: String(t.label), usd: Number(t.usd) }))
|
|
38014
|
+
};
|
|
38015
|
+
clientCache = { atMs: Date.now(), summary };
|
|
38016
|
+
return summary;
|
|
38017
|
+
} catch {
|
|
38018
|
+
return null;
|
|
38019
|
+
}
|
|
38020
|
+
}
|
|
38021
|
+
var CLIENT_CACHE_TTL_MS = 30000, clientCache = null;
|
|
38022
|
+
var init_external_spend3 = __esm(() => {
|
|
38023
|
+
init_external_spend();
|
|
38024
|
+
init_external_spend();
|
|
38025
|
+
});
|
|
38026
|
+
|
|
37771
38027
|
// ../src/vault/approvals/client.ts
|
|
37772
38028
|
function resolveKernelSocketPath2(opts) {
|
|
37773
38029
|
if (opts?.socket)
|
|
@@ -38411,6 +38667,16 @@ function buildStopReply(turnInFlight, queuedSessionCmds) {
|
|
|
38411
38667
|
`) };
|
|
38412
38668
|
}
|
|
38413
38669
|
|
|
38670
|
+
// gateway/usage-mask.ts
|
|
38671
|
+
function shouldMaskUsageLabels(chatType, groupAllowFrom) {
|
|
38672
|
+
if (chatType === "private")
|
|
38673
|
+
return false;
|
|
38674
|
+
if (chatType === "group" || chatType === "supergroup") {
|
|
38675
|
+
return (groupAllowFrom ?? []).length === 0;
|
|
38676
|
+
}
|
|
38677
|
+
return true;
|
|
38678
|
+
}
|
|
38679
|
+
|
|
38414
38680
|
// gateway/busy-ack.ts
|
|
38415
38681
|
var BUSY_ACK_STEP_AGE_THRESHOLD_MS = 12000;
|
|
38416
38682
|
function shouldPostBusyAck(input) {
|
|
@@ -42809,6 +43075,7 @@ function pinnedMessageIsOurs(tracked, chatId, pinnedMessageId) {
|
|
|
42809
43075
|
return false;
|
|
42810
43076
|
}
|
|
42811
43077
|
var storeLockTails = new Map;
|
|
43078
|
+
var pinReconcileTails = new Map;
|
|
42812
43079
|
|
|
42813
43080
|
// gateway/pinned-message-handler.ts
|
|
42814
43081
|
async function handlePinnedMessage(ctx, deps) {
|
|
@@ -69626,6 +69893,15 @@ class AuthBrokerClient2 {
|
|
|
69626
69893
|
}
|
|
69627
69894
|
return parsed;
|
|
69628
69895
|
}
|
|
69896
|
+
async getExternalSpend(forceLive) {
|
|
69897
|
+
const data = await this.send({
|
|
69898
|
+
v: PROTOCOL_VERSION,
|
|
69899
|
+
id: randomUUID4(),
|
|
69900
|
+
op: "get-external-spend",
|
|
69901
|
+
...forceLive ? { forceLive: true } : {}
|
|
69902
|
+
});
|
|
69903
|
+
return data;
|
|
69904
|
+
}
|
|
69629
69905
|
async setActive(account) {
|
|
69630
69906
|
const data = await this.send({
|
|
69631
69907
|
v: PROTOCOL_VERSION,
|
|
@@ -78479,8 +78755,10 @@ function formatQuotaBlock(q, now = new Date) {
|
|
|
78479
78755
|
const lines = [];
|
|
78480
78756
|
lines.push("**Claude plan quota**");
|
|
78481
78757
|
lines.push("");
|
|
78482
|
-
|
|
78483
|
-
|
|
78758
|
+
const fiveHour = q.fiveHourUtilPresent === false ? "no data" : `\`${Math.round(q.fiveHourUtilizationPct)}%\``;
|
|
78759
|
+
const sevenDay = q.sevenDayUtilPresent === false ? "no data" : `\`${Math.round(q.sevenDayUtilizationPct)}%\``;
|
|
78760
|
+
lines.push(`**5h window** ${fiveHour} \u00b7 \`${formatResetRelative2(q.fiveHourResetAt, now)}\``);
|
|
78761
|
+
lines.push(`**7d window** ${sevenDay} \u00b7 \`${formatResetRelative2(q.sevenDayResetAt, now)}\``);
|
|
78484
78762
|
if (q.representativeClaim) {
|
|
78485
78763
|
lines.push("");
|
|
78486
78764
|
lines.push(`_Binding window: ${q.representativeClaim.replace(/_/g, " ")}_`);
|
|
@@ -79172,6 +79450,37 @@ function classifyModelSwitchConfirmation(input) {
|
|
|
79172
79450
|
}
|
|
79173
79451
|
return { kind: "default", launched: revertedTo };
|
|
79174
79452
|
}
|
|
79453
|
+
function formatModelRelaunchDiagLog(input) {
|
|
79454
|
+
const { agent, launched, configured, confirmation, isApplyBoot } = input;
|
|
79455
|
+
const L = launched || "(none)";
|
|
79456
|
+
if (confirmation == null) {
|
|
79457
|
+
return "telegram gateway: gw /model relaunch applied agent=" + agent + " launched=" + L + " configured=" + configured + " override=" + (isApplyBoot ? "set" : "cleared") + `
|
|
79458
|
+
`;
|
|
79459
|
+
}
|
|
79460
|
+
if (confirmation.kind === "not-applied") {
|
|
79461
|
+
return "telegram gateway: gw /model relaunch NOT-APPLIED agent=" + agent + " target=" + confirmation.target + " launched=" + L + " configured=" + configured + " revertedTo=" + confirmation.revertedTo + `
|
|
79462
|
+
`;
|
|
79463
|
+
}
|
|
79464
|
+
if (confirmation.kind === "applied") {
|
|
79465
|
+
return "telegram gateway: gw /model relaunch applied agent=" + agent + " launched=" + L + " configured=" + configured + ` override=set outcome=applied
|
|
79466
|
+
`;
|
|
79467
|
+
}
|
|
79468
|
+
return "telegram gateway: gw /model relaunch applied agent=" + agent + " launched=" + L + " configured=" + configured + ` override=cleared outcome=default
|
|
79469
|
+
`;
|
|
79470
|
+
}
|
|
79471
|
+
function formatModelSwitchConfirmationBody(confirmation) {
|
|
79472
|
+
if (confirmation.kind === "applied") {
|
|
79473
|
+
return "\u2705 Now running `" + confirmation.launched + "` \u2014 session-only, reverts to the configured model on the next restart. Fresh session; memory and the handoff briefing carry the context.";
|
|
79474
|
+
}
|
|
79475
|
+
if (confirmation.kind === "not-applied") {
|
|
79476
|
+
return "\u26a0\ufe0f Your switch to `" + confirmation.target + "` didn't apply \u2014 the agent reverted to `" + confirmation.revertedTo + "` (the apply-boot didn't complete). Re-issue `/model " + confirmation.target + "` to try again.";
|
|
79477
|
+
}
|
|
79478
|
+
return "\u2705 Now running `" + confirmation.launched + "` (the configured default) \u2014 fresh session; memory and the handoff briefing carry the context.";
|
|
79479
|
+
}
|
|
79480
|
+
function formatModelRelaunchSuppressNotAppliedLog(input) {
|
|
79481
|
+
return "telegram gateway: gw /model relaunch NOT-APPLIED \u2014 suppressing not-applied confirmation (a .session-model-alert is present and will be relayed) agent=" + input.agent + " target=" + input.target + `
|
|
79482
|
+
`;
|
|
79483
|
+
}
|
|
79175
79484
|
function resolveStaleAwareBusy(input) {
|
|
79176
79485
|
const turnStale = input.currentTurnActive && input.turnAgeMs !== null && input.turnAgeMs > input.hardTtlMs;
|
|
79177
79486
|
const approvalLive = input.oldestPendingApprovalAgeMs !== null && input.oldestPendingApprovalAgeMs <= input.hardTtlMs;
|
|
@@ -80073,7 +80382,7 @@ var HINDSIGHT_HEALTHCHECK_PY = 'import urllib.request,sys; sys.exit(0 if urllib.
|
|
|
80073
80382
|
var HINDSIGHT_HEALTHCHECK_CMD = `python3 -c '${HINDSIGHT_HEALTHCHECK_PY}'`;
|
|
80074
80383
|
|
|
80075
80384
|
// ../src/memory/hindsight.ts
|
|
80076
|
-
var DEFAULT_RETAIN_MISSION = "Extract user preferences, ongoing projects, recurring commitments, " + "important context, and durable facts that should help across future " + "conversations. Skip one-off chatter and temporary task noise.";
|
|
80385
|
+
var DEFAULT_RETAIN_MISSION = "Extract user preferences, ongoing projects, recurring commitments, " + "important context, and durable facts that should help across future " + "conversations. Skip one-off chatter and temporary task noise, " + "including in-flight workflow/process narration (a sub-task started, " + "paused, or is still running) \u2014 only retain the outcome once a task " + "actually completes or a decision is made.";
|
|
80077
80386
|
var PROFILE_MEMORY_DEFAULTS = {
|
|
80078
80387
|
"health-coach": {
|
|
80079
80388
|
disposition: { skepticism: 2, literalism: 2, empathy: 5 },
|
|
@@ -84201,6 +84510,17 @@ function withStoreLock(path2, fn) {
|
|
|
84201
84510
|
}));
|
|
84202
84511
|
return run3;
|
|
84203
84512
|
}
|
|
84513
|
+
var pinReconcileTails2 = new Map;
|
|
84514
|
+
function withPinReconcileLock(pinKey, fn) {
|
|
84515
|
+
const prev = pinReconcileTails2.get(pinKey) ?? Promise.resolve();
|
|
84516
|
+
const run3 = prev.then(fn, fn);
|
|
84517
|
+
pinReconcileTails2.set(pinKey, run3.then(() => {
|
|
84518
|
+
return;
|
|
84519
|
+
}, () => {
|
|
84520
|
+
return;
|
|
84521
|
+
}));
|
|
84522
|
+
return run3;
|
|
84523
|
+
}
|
|
84204
84524
|
function applyStatusPinRow(path2, fs2, pinKey, row, log) {
|
|
84205
84525
|
const current = loadStatusPins(path2, fs2);
|
|
84206
84526
|
const others = current.filter((p) => p.pinKey !== pinKey);
|
|
@@ -84227,7 +84547,11 @@ function reconcileAndPersistStatusPin(args) {
|
|
|
84227
84547
|
return next2;
|
|
84228
84548
|
}
|
|
84229
84549
|
const next = await args.applyPin();
|
|
84230
|
-
|
|
84550
|
+
if (next == null) {
|
|
84551
|
+
applyStatusPinRow(path2, fs2, pinKey, null, log);
|
|
84552
|
+
} else {
|
|
84553
|
+
applyStatusPinRow(path2, fs2, pinKey, { pinKey, chatId, messageId: next.messageId }, log);
|
|
84554
|
+
}
|
|
84231
84555
|
return next;
|
|
84232
84556
|
});
|
|
84233
84557
|
}
|
|
@@ -92377,10 +92701,10 @@ function effectiveTurnAgeMs(markerAgeMs, turnStartedAt, now) {
|
|
|
92377
92701
|
}
|
|
92378
92702
|
|
|
92379
92703
|
// ../src/build-info.ts
|
|
92380
|
-
var VERSION = "0.19.
|
|
92381
|
-
var COMMIT_SHA = "
|
|
92382
|
-
var COMMIT_DATE = "2026-07-
|
|
92383
|
-
var LATEST_PR =
|
|
92704
|
+
var VERSION = "0.19.2";
|
|
92705
|
+
var COMMIT_SHA = "1fa69736";
|
|
92706
|
+
var COMMIT_DATE = "2026-07-19T09:11:44Z";
|
|
92707
|
+
var LATEST_PR = 3425;
|
|
92384
92708
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
92385
92709
|
|
|
92386
92710
|
// gateway/boot-version.ts
|
|
@@ -97645,7 +97969,7 @@ var midSessionCardReaper = isGatewayMain ? setInterval(() => {
|
|
|
97645
97969
|
midSessionCardReaper?.unref();
|
|
97646
97970
|
async function reconcileStatusPin(pinKey, chatId, desired) {
|
|
97647
97971
|
try {
|
|
97648
|
-
await reconcileStatusPinInner(pinKey, chatId, desired);
|
|
97972
|
+
await withPinReconcileLock(pinKey, () => reconcileStatusPinInner(pinKey, chatId, desired));
|
|
97649
97973
|
} catch (err) {
|
|
97650
97974
|
const msg = err instanceof Error ? err.message : String(err);
|
|
97651
97975
|
process.stderr.write(`telegram gateway: status-pin reconcile absorbed error (key=${pinKey} chat=${chatId}): ${msg}
|
|
@@ -100546,6 +100870,10 @@ function isAuthorizedSender(ctx) {
|
|
|
100546
100870
|
}
|
|
100547
100871
|
return false;
|
|
100548
100872
|
}
|
|
100873
|
+
function shouldMaskAccountLabels(ctx) {
|
|
100874
|
+
const groupAllowFrom = ctx.chat?.type === "group" || ctx.chat?.type === "supergroup" ? loadAccess().groups[String(ctx.chat.id)]?.allowFrom : undefined;
|
|
100875
|
+
return shouldMaskUsageLabels(ctx.chat?.type, groupAllowFrom);
|
|
100876
|
+
}
|
|
100549
100877
|
var __inboundRouterTestSeam = {
|
|
100550
100878
|
activeStatusReactions,
|
|
100551
100879
|
activeTurnStartedAt,
|
|
@@ -104403,7 +104731,7 @@ Send \`/auth ${parsed.provider} cancel\` to abort.`, { html: true });
|
|
|
104403
104731
|
bot2.command("usage", async (ctx) => {
|
|
104404
104732
|
if (!isAuthorizedSender(ctx))
|
|
104405
104733
|
return;
|
|
104406
|
-
const demo = hasDemoFlag(getCommandArgs(ctx));
|
|
104734
|
+
const demo = hasDemoFlag(getCommandArgs(ctx)) || shouldMaskAccountLabels(ctx);
|
|
104407
104735
|
const currentAgent = getMyAgentName();
|
|
104408
104736
|
try {
|
|
104409
104737
|
const client3 = await getAuthBrokerClient2(currentAgent);
|
|
@@ -104416,11 +104744,14 @@ Send \`/auth ${parsed.provider} cancel\` to abort.`, { html: true });
|
|
|
104416
104744
|
const { buildSnapshotsFromState: buildSnapshotsFromState4, buildSnapshotKeyboard: buildSnapshotKeyboard3 } = await Promise.resolve().then(() => (init_auth_snapshot_format2(), exports_auth_snapshot_format2));
|
|
104417
104745
|
const { renderUsageCard: renderUsageCard2 } = await Promise.resolve().then(() => (init_quota_bar_format(), exports_quota_bar_format));
|
|
104418
104746
|
const snapshots = buildSnapshotsFromState4(state7, quotas);
|
|
104747
|
+
const { fetchExternalSpendSummary: fetchExternalSpendSummary2 } = await Promise.resolve().then(() => (init_external_spend3(), exports_external_spend));
|
|
104748
|
+
const externalSpend = await fetchExternalSpendSummary2(renderNow).catch(() => null);
|
|
104419
104749
|
const exhaustedByLabel = new Map(state7.accounts.map((a) => [a.label, a.exhausted]));
|
|
104420
104750
|
const text5 = renderUsageCard2(snapshots, exhaustedByLabel, {
|
|
104421
104751
|
now: renderNow,
|
|
104422
104752
|
demo,
|
|
104423
|
-
|
|
104753
|
+
externalSpend,
|
|
104754
|
+
...deriveUsageFooterFreshness2(probeResp.results, staleCachedAtMs, renderNow.getTime())
|
|
104424
104755
|
});
|
|
104425
104756
|
let kbRows = buildSnapshotKeyboard3(snapshots, { now: new Date, demo });
|
|
104426
104757
|
if (ctx.chat?.type !== "private") {
|
|
@@ -105750,21 +106081,28 @@ async function startGateway() {
|
|
|
105750
106081
|
})();
|
|
105751
106082
|
const isApplyBoot = launched.length > 0 && launched !== configured;
|
|
105752
106083
|
sessionModelSource.setOverride(isApplyBoot ? launched : null);
|
|
105753
|
-
|
|
105754
|
-
|
|
105755
|
-
|
|
106084
|
+
const confirmation = modelSwitchReason != null ? classifyModelSwitchConfirmation({
|
|
106085
|
+
reason: modelSwitchReason,
|
|
106086
|
+
launched,
|
|
106087
|
+
configured
|
|
106088
|
+
}) : null;
|
|
106089
|
+
process.stderr.write(formatModelRelaunchDiagLog({
|
|
106090
|
+
agent: getMyAgentName(),
|
|
106091
|
+
launched,
|
|
106092
|
+
configured,
|
|
106093
|
+
confirmation,
|
|
106094
|
+
isApplyBoot
|
|
106095
|
+
}));
|
|
106096
|
+
if (confirmation != null && modelSwitchMarkerChat) {
|
|
105756
106097
|
const chat = modelSwitchMarkerChat;
|
|
105757
|
-
const confirmation = classifyModelSwitchConfirmation({
|
|
105758
|
-
reason: modelSwitchReason,
|
|
105759
|
-
launched,
|
|
105760
|
-
configured
|
|
105761
|
-
});
|
|
105762
106098
|
const hasSessionModelAlert = existsSync54(join59(smAgentDir, ".session-model-alert"));
|
|
105763
106099
|
if (confirmation.kind === "not-applied" && hasSessionModelAlert) {
|
|
105764
|
-
process.stderr.write(
|
|
105765
|
-
|
|
106100
|
+
process.stderr.write(formatModelRelaunchSuppressNotAppliedLog({
|
|
106101
|
+
agent: getMyAgentName(),
|
|
106102
|
+
target: confirmation.target
|
|
106103
|
+
}));
|
|
105766
106104
|
} else {
|
|
105767
|
-
const body =
|
|
106105
|
+
const body = formatModelSwitchConfirmationBody(confirmation);
|
|
105768
106106
|
lockedBot.api.sendMessage(chat.chatId, body, {
|
|
105769
106107
|
parse_mode: "Markdown",
|
|
105770
106108
|
...chat.threadId != null ? { message_thread_id: chat.threadId } : {}
|