@a1hvdy/cc-openclaw 0.17.0 → 0.18.1

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.
Files changed (73) hide show
  1. package/README.md +0 -14
  2. package/dist/src/channels/telegram/completion-summary.js +24 -2
  3. package/dist/src/channels/telegram/completion-summary.js.map +1 -1
  4. package/dist/src/channels/telegram/event-reducer.js +15 -3
  5. package/dist/src/channels/telegram/event-reducer.js.map +1 -1
  6. package/dist/src/channels/telegram/live-card.d.ts +90 -7
  7. package/dist/src/channels/telegram/live-card.js +286 -25
  8. package/dist/src/channels/telegram/live-card.js.map +1 -1
  9. package/dist/src/channels/telegram/tool-tracker.d.ts +16 -2
  10. package/dist/src/channels/telegram/tool-tracker.js +81 -18
  11. package/dist/src/channels/telegram/tool-tracker.js.map +1 -1
  12. package/dist/src/config/loader.js +2 -0
  13. package/dist/src/config/loader.js.map +1 -1
  14. package/dist/src/config/schema.d.ts +20 -1
  15. package/dist/src/config/schema.js +12 -1
  16. package/dist/src/config/schema.js.map +1 -1
  17. package/dist/src/constants.d.ts +13 -1
  18. package/dist/src/constants.js +13 -1
  19. package/dist/src/constants.js.map +1 -1
  20. package/dist/src/engines/index.d.ts +0 -2
  21. package/dist/src/engines/index.js +0 -3
  22. package/dist/src/engines/index.js.map +1 -1
  23. package/dist/src/engines/persistent-session.d.ts +0 -9
  24. package/dist/src/engines/persistent-session.js +0 -39
  25. package/dist/src/engines/persistent-session.js.map +1 -1
  26. package/dist/src/lib/config.d.ts +6 -0
  27. package/dist/src/lib/config.js +81 -0
  28. package/dist/src/lib/config.js.map +1 -1
  29. package/dist/src/lib/sysprompt-strip.d.ts +14 -0
  30. package/dist/src/lib/sysprompt-strip.js +79 -2
  31. package/dist/src/lib/sysprompt-strip.js.map +1 -1
  32. package/dist/src/lib/trajectory.d.ts +1 -10
  33. package/dist/src/lib/trajectory.js +6 -37
  34. package/dist/src/lib/trajectory.js.map +1 -1
  35. package/dist/src/lib/turn-trace.d.ts +34 -0
  36. package/dist/src/lib/turn-trace.js +75 -0
  37. package/dist/src/lib/turn-trace.js.map +1 -0
  38. package/dist/src/observability/event-bus.d.ts +0 -21
  39. package/dist/src/observability/event-bus.js.map +1 -1
  40. package/dist/src/openai-compat/insight-format.d.ts +36 -0
  41. package/dist/src/openai-compat/insight-format.js +140 -0
  42. package/dist/src/openai-compat/insight-format.js.map +1 -0
  43. package/dist/src/openai-compat/non-streaming-handler.js +38 -58
  44. package/dist/src/openai-compat/non-streaming-handler.js.map +1 -1
  45. package/dist/src/openai-compat/openai-compat.js +23 -0
  46. package/dist/src/openai-compat/openai-compat.js.map +1 -1
  47. package/dist/src/openai-compat/response-formatter.d.ts +6 -1
  48. package/dist/src/openai-compat/response-formatter.js +9 -2
  49. package/dist/src/openai-compat/response-formatter.js.map +1 -1
  50. package/dist/src/openai-compat/streaming-handler.js +35 -120
  51. package/dist/src/openai-compat/streaming-handler.js.map +1 -1
  52. package/dist/src/patches/cache-parity-registry.d.ts +0 -83
  53. package/dist/src/patches/cache-parity-registry.js +1 -151
  54. package/dist/src/patches/cache-parity-registry.js.map +1 -1
  55. package/dist/src/session/session-manager.d.ts +8 -4
  56. package/dist/src/session/session-manager.js +86 -76
  57. package/dist/src/session/session-manager.js.map +1 -1
  58. package/dist/src/session-bootstrap/cwd-patch.js +35 -0
  59. package/dist/src/session-bootstrap/cwd-patch.js.map +1 -1
  60. package/mcp-tools.json +1 -1
  61. package/package.json +1 -1
  62. package/dist/src/engines/heartbeat-guard.d.ts +0 -91
  63. package/dist/src/engines/heartbeat-guard.js +0 -120
  64. package/dist/src/engines/heartbeat-guard.js.map +0 -1
  65. package/dist/src/engines/subprocess-pool.d.ts +0 -78
  66. package/dist/src/engines/subprocess-pool.js +0 -200
  67. package/dist/src/engines/subprocess-pool.js.map +0 -1
  68. package/dist/src/lib/cost-rollup.d.ts +0 -36
  69. package/dist/src/lib/cost-rollup.js +0 -125
  70. package/dist/src/lib/cost-rollup.js.map +0 -1
  71. package/dist/src/lifecycle/safe-restart.d.ts +0 -99
  72. package/dist/src/lifecycle/safe-restart.js +0 -132
  73. package/dist/src/lifecycle/safe-restart.js.map +0 -1
@@ -1,120 +0,0 @@
1
- /**
2
- * HeartbeatGuard — enforce `heartbeat.model` override at the engines layer.
3
- *
4
- * Context
5
- * -------
6
- * OpenClaw issues #9556, #13009, #14279 document a recurring bug: heartbeat-
7
- * triggered runs ignore the `heartbeat.model` field in the agent config and
8
- * fall through to the session's primary model (typically Opus), burning
9
- * expensive tokens on what should be a cheap Haiku ping.
10
- *
11
- * The existing `src/lib/heartbeat-workaround.ts` patches this at the SDK
12
- * request layer. This guard operates one level higher — at the engines /
13
- * agent-config layer — to:
14
- *
15
- * 1. Read `heartbeat.model` from the resolved agent config.
16
- * 2. If present, enforce it on any heartbeat invocation.
17
- * 3. If the upstream runtime ignores the override (bug still present),
18
- * REFUSE the heartbeat with a clear error that names the issue numbers.
19
- *
20
- * Usage
21
- * -----
22
- * ```ts
23
- * const guard = new HeartbeatGuard(agentConfig);
24
- * const result = guard.enforce(requestedModel);
25
- * if (!result.ok) throw result.error;
26
- * // use result.model for the heartbeat call
27
- * ```
28
- */
29
- // ─── Errors ───────────────────────────────────────────────────────────────────
30
- export class HeartbeatGuardError extends Error {
31
- /** The model the upstream runtime attempted to use. */
32
- requestedModel;
33
- /** The model the guard expected. */
34
- expectedModel;
35
- /** Upstream issue numbers that describe why this guard exists. */
36
- issueRefs = ['#9556', '#13009', '#14279'];
37
- constructor(requestedModel, expectedModel) {
38
- super(`HeartbeatGuard: upstream runtime used model "${requestedModel}" for a heartbeat turn ` +
39
- `but heartbeat.model is set to "${expectedModel}". ` +
40
- `This is a known upstream bug — see OpenClaw issues #9556, #13009, #14279. ` +
41
- `Refusing the heartbeat to prevent expensive model misrouting. ` +
42
- `Disable this guard with OPENCLAW_HEARTBEAT_GUARD_DISABLE=1 once upstream ships a fix.`);
43
- this.name = 'HeartbeatGuardError';
44
- this.requestedModel = requestedModel;
45
- this.expectedModel = expectedModel;
46
- }
47
- }
48
- // ─── Guard ────────────────────────────────────────────────────────────────────
49
- export class HeartbeatGuard {
50
- config;
51
- constructor(agentConfig) {
52
- this.config = agentConfig;
53
- }
54
- /**
55
- * Enforce the heartbeat model override.
56
- *
57
- * @param requestedModel - The model string the upstream runtime resolved for
58
- * this heartbeat invocation (i.e. whatever it actually passed to the SDK).
59
- *
60
- * @returns `{ ok: true, model }` — the model the caller MUST use.
61
- * `{ ok: false, error }` — the upstream ignored the override; refuse.
62
- *
63
- * When no `heartbeat.model` is configured this is a pass-through:
64
- * returns `{ ok: true, model: requestedModel }` unconditionally.
65
- */
66
- enforce(requestedModel) {
67
- if (isHeartbeatGuardDisabled()) {
68
- return { ok: true, model: requestedModel };
69
- }
70
- const expected = this.config.heartbeat?.model;
71
- if (!expected) {
72
- // No override configured — pass through.
73
- return { ok: true, model: requestedModel };
74
- }
75
- // Normalise: strip optional provider prefix (e.g. "cc-openclaw/claude-haiku-4-5").
76
- const normaliseModel = (m) => (m.includes('/') ? m.split('/').pop() : m);
77
- const normRequested = normaliseModel(requestedModel);
78
- const normExpected = normaliseModel(expected);
79
- if (normRequested === normExpected) {
80
- // Runtime honoured the override.
81
- return { ok: true, model: requestedModel };
82
- }
83
- // Override was ignored. Refuse.
84
- return {
85
- ok: false,
86
- error: new HeartbeatGuardError(requestedModel, expected),
87
- };
88
- }
89
- /**
90
- * Convenience: enforce and throw on refusal. Equivalent to:
91
- * const r = guard.enforce(model); if (!r.ok) throw r.error; return r.model;
92
- */
93
- enforceOrThrow(requestedModel) {
94
- const result = this.enforce(requestedModel);
95
- if (!result.ok)
96
- throw result.error;
97
- return result.model;
98
- }
99
- /**
100
- * Returns the configured heartbeat.model, or undefined if none is set.
101
- */
102
- get configuredModel() {
103
- return this.config.heartbeat?.model;
104
- }
105
- /**
106
- * True if heartbeats are explicitly disabled in the agent config.
107
- */
108
- get heartbeatsDisabled() {
109
- return this.config.heartbeat?.enabled === false;
110
- }
111
- }
112
- // ─── Env gate ─────────────────────────────────────────────────────────────────
113
- /**
114
- * Set OPENCLAW_HEARTBEAT_GUARD_DISABLE=1 to skip the guard entirely.
115
- * Use this ONLY after upstream ships a fix for #9556/#13009/#14279.
116
- */
117
- export function isHeartbeatGuardDisabled() {
118
- return process.env.OPENCLAW_HEARTBEAT_GUARD_DISABLE === '1';
119
- }
120
- //# sourceMappingURL=heartbeat-guard.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"heartbeat-guard.js","sourceRoot":"","sources":["../../../src/engines/heartbeat-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAqBH,iFAAiF;AAEjF,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC5C,uDAAuD;IAC9C,cAAc,CAAS;IAChC,oCAAoC;IAC3B,aAAa,CAAS;IAC/B,kEAAkE;IACzD,SAAS,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAU,CAAC;IAE5D,YAAY,cAAsB,EAAE,aAAqB;QACvD,KAAK,CACH,gDAAgD,cAAc,yBAAyB;YACrF,kCAAkC,aAAa,KAAK;YACpD,4EAA4E;YAC5E,gEAAgE;YAChE,uFAAuF,CAC1F,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAClC,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QACrC,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;IACrC,CAAC;CACF;AAED,iFAAiF;AAEjF,MAAM,OAAO,cAAc;IACR,MAAM,CAAuB;IAE9C,YAAY,WAAiC;QAC3C,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC;IAC5B,CAAC;IAED;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,cAAsB;QAC5B,IAAI,wBAAwB,EAAE,EAAE,CAAC;YAC/B,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC;QAC7C,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC;QAC9C,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,yCAAyC;YACzC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC;QAC7C,CAAC;QAED,mFAAmF;QACnF,MAAM,cAAc,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAClF,MAAM,aAAa,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC;QACrD,MAAM,YAAY,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;QAE9C,IAAI,aAAa,KAAK,YAAY,EAAE,CAAC;YACnC,iCAAiC;YACjC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC;QAC7C,CAAC;QAED,gCAAgC;QAChC,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,IAAI,mBAAmB,CAAC,cAAc,EAAE,QAAQ,CAAC;SACzD,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,cAAc,CAAC,cAAsB;QACnC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QAC5C,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,MAAM,MAAM,CAAC,KAAK,CAAC;QACnC,OAAO,MAAM,CAAC,KAAK,CAAC;IACtB,CAAC;IAED;;OAEG;IACH,IAAI,eAAe;QACjB,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC;IACtC,CAAC;IAED;;OAEG;IACH,IAAI,kBAAkB;QACpB,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,KAAK,KAAK,CAAC;IAClD,CAAC;CACF;AAED,iFAAiF;AAEjF;;;GAGG;AACH,MAAM,UAAU,wBAAwB;IACtC,OAAO,OAAO,CAAC,GAAG,CAAC,gCAAgC,KAAK,GAAG,CAAC;AAC9D,CAAC"}
@@ -1,78 +0,0 @@
1
- /**
2
- * SubprocessPool — warm claude CLI subprocess pool for conversation-boundary recycle.
3
- *
4
- * DARK-FLAGGED: only consulted when OPENCLAW_SUBPROCESS_POOL=1.
5
- * When the flag is off, this module is a no-op and all behaviour is
6
- * byte-identical to the pre-v0.16 code path.
7
- *
8
- * Goal: cut Telegram cold-turn wall-clock toward direct CLI baseline
9
- * (currently ~3× direct CLI) by keeping a pool of warm `claude` CLI
10
- * subprocesses ready to accept the first message of a new conversation,
11
- * amortising the ~800-1200ms spawn + init cost.
12
- *
13
- * Pool policy:
14
- * - Maintains `minIdle` warm sessions (default 1).
15
- * - On conversation start: borrow the head idle session; the pool
16
- * immediately spawns a replacement to maintain the idle floor.
17
- * - On conversation boundary (session.stop() / recycle()): return the
18
- * session to the pool — the session's subprocess is killed, a fresh
19
- * one is spawned and warmed, then placed back into the idle queue.
20
- * - Hard cap: `maxSize` total (idle + borrowed) sessions (default 4).
21
- * - Idle sessions are reaped after `idleTtlMs` (default 5 min) to
22
- * avoid orphaning warm processes during quiet periods.
23
- */
24
- import { EventEmitter } from 'node:events';
25
- import { PersistentClaudeSession } from './persistent-session.js';
26
- import type { SessionConfig } from '../types.js';
27
- export interface SubprocessPoolOptions {
28
- /** Minimum idle (pre-warmed) sessions to keep ready. Default 1. */
29
- minIdle?: number;
30
- /** Hard cap on total sessions (idle + borrowed). Default 4. */
31
- maxSize?: number;
32
- /** Idle TTL before a warm session is reaped (ms). Default 300_000 (5 min). */
33
- idleTtlMs?: number;
34
- /** Base config applied to every pool-spawned session. */
35
- baseConfig: SessionConfig;
36
- /** Override the claude binary path (test injection). */
37
- claudeBin?: string;
38
- }
39
- /**
40
- * Returns true only when the pool feature flag is explicitly enabled.
41
- * Default off — behaviour is byte-identical to pre-v0.16 when off.
42
- */
43
- export declare function isSubprocessPoolEnabled(): boolean;
44
- export declare class SubprocessPool extends EventEmitter {
45
- private readonly opts;
46
- private idle;
47
- private borrowed;
48
- private reaperTimer;
49
- private _destroyed;
50
- constructor(options: SubprocessPoolOptions);
51
- /**
52
- * Start the pool: pre-warm `minIdle` sessions and schedule the idle reaper.
53
- */
54
- start(): Promise<void>;
55
- /**
56
- * Borrow a warm session for a new conversation.
57
- * Returns null if pool is disabled or at capacity and no idle sessions exist.
58
- * Callers MUST call recycle(session) when the conversation ends.
59
- */
60
- borrow(): Promise<PersistentClaudeSession | null>;
61
- /**
62
- * Recycle a borrowed session back into the pool.
63
- * The session's subprocess is terminated; a fresh warmed session replaces it.
64
- */
65
- recycle(session: PersistentClaudeSession): Promise<void>;
66
- /**
67
- * Destroy the pool: kill all idle sessions and stop the reaper.
68
- */
69
- destroy(): void;
70
- get stats(): {
71
- idle: number;
72
- borrowed: number;
73
- maxSize: number;
74
- };
75
- private _fillIdle;
76
- private _spawnWarm;
77
- private _reapStale;
78
- }
@@ -1,200 +0,0 @@
1
- /**
2
- * SubprocessPool — warm claude CLI subprocess pool for conversation-boundary recycle.
3
- *
4
- * DARK-FLAGGED: only consulted when OPENCLAW_SUBPROCESS_POOL=1.
5
- * When the flag is off, this module is a no-op and all behaviour is
6
- * byte-identical to the pre-v0.16 code path.
7
- *
8
- * Goal: cut Telegram cold-turn wall-clock toward direct CLI baseline
9
- * (currently ~3× direct CLI) by keeping a pool of warm `claude` CLI
10
- * subprocesses ready to accept the first message of a new conversation,
11
- * amortising the ~800-1200ms spawn + init cost.
12
- *
13
- * Pool policy:
14
- * - Maintains `minIdle` warm sessions (default 1).
15
- * - On conversation start: borrow the head idle session; the pool
16
- * immediately spawns a replacement to maintain the idle floor.
17
- * - On conversation boundary (session.stop() / recycle()): return the
18
- * session to the pool — the session's subprocess is killed, a fresh
19
- * one is spawned and warmed, then placed back into the idle queue.
20
- * - Hard cap: `maxSize` total (idle + borrowed) sessions (default 4).
21
- * - Idle sessions are reaped after `idleTtlMs` (default 5 min) to
22
- * avoid orphaning warm processes during quiet periods.
23
- */
24
- import { EventEmitter } from 'node:events';
25
- import { PersistentClaudeSession } from './persistent-session.js';
26
- import { getClaudeBin } from '../lib/config.js';
27
- // ─── Env gate ────────────────────────────────────────────────────────────────
28
- /**
29
- * Returns true only when the pool feature flag is explicitly enabled.
30
- * Default off — behaviour is byte-identical to pre-v0.16 when off.
31
- */
32
- export function isSubprocessPoolEnabled() {
33
- return process.env.OPENCLAW_SUBPROCESS_POOL === '1';
34
- }
35
- // ─── SubprocessPool ──────────────────────────────────────────────────────────
36
- export class SubprocessPool extends EventEmitter {
37
- opts;
38
- idle = [];
39
- borrowed = 0;
40
- reaperTimer = null;
41
- _destroyed = false;
42
- constructor(options) {
43
- super();
44
- this.opts = {
45
- minIdle: options.minIdle ?? 1,
46
- maxSize: options.maxSize ?? 4,
47
- idleTtlMs: options.idleTtlMs ?? 300_000,
48
- baseConfig: options.baseConfig,
49
- claudeBin: options.claudeBin ?? getClaudeBin() ?? 'claude',
50
- };
51
- }
52
- // ─── Lifecycle ─────────────────────────────────────────────────────────────
53
- /**
54
- * Start the pool: pre-warm `minIdle` sessions and schedule the idle reaper.
55
- */
56
- async start() {
57
- if (this._destroyed)
58
- throw new Error('SubprocessPool: already destroyed');
59
- await this._fillIdle();
60
- this.reaperTimer = setInterval(() => this._reapStale(), 60_000);
61
- // Allow the Node process to exit even if the reaper is still pending.
62
- if (this.reaperTimer.unref)
63
- this.reaperTimer.unref();
64
- }
65
- /**
66
- * Borrow a warm session for a new conversation.
67
- * Returns null if pool is disabled or at capacity and no idle sessions exist.
68
- * Callers MUST call recycle(session) when the conversation ends.
69
- */
70
- async borrow() {
71
- if (this._destroyed)
72
- return null;
73
- if (!isSubprocessPoolEnabled())
74
- return null;
75
- if (this.idle.length > 0) {
76
- const entry = this.idle.shift();
77
- this.borrowed++;
78
- this.emit('borrow', { remaining: this.idle.length, borrowed: this.borrowed });
79
- // Spawn a replacement asynchronously to restore the idle floor.
80
- this._fillIdle().catch((err) => this.emit('error', err));
81
- return entry.session;
82
- }
83
- // No idle sessions: try to spawn one on-demand if under cap.
84
- const total = this.idle.length + this.borrowed;
85
- if (total < this.opts.maxSize) {
86
- const session = await this._spawnWarm();
87
- if (session) {
88
- this.borrowed++;
89
- this.emit('borrow', { remaining: 0, borrowed: this.borrowed });
90
- return session;
91
- }
92
- }
93
- this.emit('pool_exhausted', { borrowed: this.borrowed, maxSize: this.opts.maxSize });
94
- return null;
95
- }
96
- /**
97
- * Recycle a borrowed session back into the pool.
98
- * The session's subprocess is terminated; a fresh warmed session replaces it.
99
- */
100
- async recycle(session) {
101
- this.borrowed = Math.max(0, this.borrowed - 1);
102
- // Kill the in-use session — it has conversation state we do not want to
103
- // bleed into the next borrower.
104
- try {
105
- session.stop();
106
- }
107
- catch {
108
- // Ignore stop errors — process may already be gone.
109
- }
110
- this.emit('recycle', { idle: this.idle.length, borrowed: this.borrowed });
111
- // Restore idle floor without blocking the caller.
112
- this._fillIdle().catch((err) => this.emit('error', err));
113
- }
114
- /**
115
- * Destroy the pool: kill all idle sessions and stop the reaper.
116
- */
117
- destroy() {
118
- if (this._destroyed)
119
- return;
120
- this._destroyed = true;
121
- if (this.reaperTimer) {
122
- clearInterval(this.reaperTimer);
123
- this.reaperTimer = null;
124
- }
125
- for (const entry of this.idle) {
126
- try {
127
- entry.session.stop();
128
- }
129
- catch {
130
- /* ignore */
131
- }
132
- }
133
- this.idle = [];
134
- this.emit('destroyed');
135
- }
136
- // ─── Diagnostics ──────────────────────────────────────────────────────────
137
- get stats() {
138
- return { idle: this.idle.length, borrowed: this.borrowed, maxSize: this.opts.maxSize };
139
- }
140
- // ─── Private ──────────────────────────────────────────────────────────────
141
- async _fillIdle() {
142
- const needed = this.opts.minIdle - this.idle.length;
143
- const capacity = this.opts.maxSize - this.idle.length - this.borrowed;
144
- const toSpawn = Math.min(needed, capacity);
145
- if (toSpawn <= 0)
146
- return;
147
- await Promise.allSettled(Array.from({ length: toSpawn }, async () => {
148
- const session = await this._spawnWarm();
149
- if (session && !this._destroyed) {
150
- this.idle.push({ session, warmAt: Date.now() });
151
- this.emit('idle_ready', { idle: this.idle.length });
152
- }
153
- }));
154
- }
155
- async _spawnWarm() {
156
- try {
157
- const session = new PersistentClaudeSession({
158
- ...this.opts.baseConfig,
159
- // Pool sessions are pre-spawned without a specific task — keep
160
- // them lean: no custom session ID, no resume.
161
- claudeResumeId: undefined,
162
- resumeSessionId: undefined,
163
- customSessionId: undefined,
164
- }, this.opts.claudeBin);
165
- await session.start();
166
- return session;
167
- }
168
- catch (err) {
169
- this.emit('spawn_error', { error: err });
170
- return null;
171
- }
172
- }
173
- _reapStale() {
174
- if (this._destroyed)
175
- return;
176
- const now = Date.now();
177
- const stale = [];
178
- this.idle = this.idle.filter((entry) => {
179
- if (now - entry.warmAt > this.opts.idleTtlMs) {
180
- stale.push(entry);
181
- return false;
182
- }
183
- return true;
184
- });
185
- for (const entry of stale) {
186
- try {
187
- entry.session.stop();
188
- }
189
- catch {
190
- /* ignore */
191
- }
192
- }
193
- if (stale.length > 0) {
194
- this.emit('idle_reaped', { reaped: stale.length, remaining: this.idle.length });
195
- // Restore floor if reaping dropped below minIdle.
196
- this._fillIdle().catch((err) => this.emit('error', err));
197
- }
198
- }
199
- }
200
- //# sourceMappingURL=subprocess-pool.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"subprocess-pool.js","sourceRoot":"","sources":["../../../src/engines/subprocess-pool.ts"],"names":[],"mappings":"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"}
@@ -1,36 +0,0 @@
1
- /**
2
- * v0.16 task-012 — cost rollup.
3
- *
4
- * Aggregates per-turn entries from `cc-openclaw-cost.jsonl` (emitted by the
5
- * openai-compat handlers) into daily and ISO-week buckets, with per-model
6
- * pricing applied to compute USD cost. Pure function — accepts a file path
7
- * and returns a structured aggregate. Consumer is the `/status` command +
8
- * the workspace `metrics` skill.
9
- *
10
- * JSONL line shape (from streaming-handler.ts + non-streaming-handler.ts):
11
- * { ts, sessionId, turn, model, inputTokens, outputTokens, durationMs }
12
- *
13
- * `costUsd` is NOT in the JSONL — it's computed here from the `model` field
14
- * via the pricing table. Model values can be either full IDs
15
- * (`claude-opus-4-7`) or shorthand (`opus`, `sonnet`, `haiku`). Pricing per
16
- * 1M tokens, Anthropic public list pricing as of 2026-Q2. Unknown models
17
- * fall back to sonnet-rate so the aggregate is never NaN.
18
- */
19
- interface BucketAggregate {
20
- tokensIn: number;
21
- tokensOut: number;
22
- turns: number;
23
- costUsd: number;
24
- durationMsTotal: number;
25
- }
26
- export interface CostRollupResult {
27
- daily: Record<string, BucketAggregate>;
28
- weekly: Record<string, BucketAggregate>;
29
- totals: BucketAggregate;
30
- rowCount: number;
31
- skippedCount: number;
32
- }
33
- export declare function rollupCosts(jsonlPath: string): CostRollupResult;
34
- /** Compact one-line summary for /status output. */
35
- export declare function formatRollupLine(rollup: CostRollupResult, today: string): string;
36
- export {};
@@ -1,125 +0,0 @@
1
- /**
2
- * v0.16 task-012 — cost rollup.
3
- *
4
- * Aggregates per-turn entries from `cc-openclaw-cost.jsonl` (emitted by the
5
- * openai-compat handlers) into daily and ISO-week buckets, with per-model
6
- * pricing applied to compute USD cost. Pure function — accepts a file path
7
- * and returns a structured aggregate. Consumer is the `/status` command +
8
- * the workspace `metrics` skill.
9
- *
10
- * JSONL line shape (from streaming-handler.ts + non-streaming-handler.ts):
11
- * { ts, sessionId, turn, model, inputTokens, outputTokens, durationMs }
12
- *
13
- * `costUsd` is NOT in the JSONL — it's computed here from the `model` field
14
- * via the pricing table. Model values can be either full IDs
15
- * (`claude-opus-4-7`) or shorthand (`opus`, `sonnet`, `haiku`). Pricing per
16
- * 1M tokens, Anthropic public list pricing as of 2026-Q2. Unknown models
17
- * fall back to sonnet-rate so the aggregate is never NaN.
18
- */
19
- import * as fs from 'node:fs';
20
- const PRICING = {
21
- 'claude-opus-4-7': { inputPerM: 15, outputPerM: 75 },
22
- 'claude-opus-4-6': { inputPerM: 15, outputPerM: 75 },
23
- opus: { inputPerM: 15, outputPerM: 75 },
24
- 'claude-sonnet-4-6': { inputPerM: 3, outputPerM: 15 },
25
- 'claude-sonnet-4-5': { inputPerM: 3, outputPerM: 15 },
26
- sonnet: { inputPerM: 3, outputPerM: 15 },
27
- 'claude-haiku-4-5': { inputPerM: 0.8, outputPerM: 4 },
28
- 'claude-haiku-4-5-20251001': { inputPerM: 0.8, outputPerM: 4 },
29
- haiku: { inputPerM: 0.8, outputPerM: 4 },
30
- };
31
- const DEFAULT_PRICING = PRICING.sonnet;
32
- function resolvePricing(model) {
33
- if (PRICING[model])
34
- return PRICING[model];
35
- const lower = model.toLowerCase();
36
- for (const key of Object.keys(PRICING)) {
37
- if (lower.includes(key))
38
- return PRICING[key];
39
- }
40
- return DEFAULT_PRICING;
41
- }
42
- function computeCostUsd(row) {
43
- const p = resolvePricing(row.model);
44
- return (row.inputTokens / 1_000_000) * p.inputPerM + (row.outputTokens / 1_000_000) * p.outputPerM;
45
- }
46
- function isoDateKey(ts) {
47
- return ts.slice(0, 10);
48
- }
49
- /** ISO-8601 week key: `<YYYY>-W<WW>`. Week 1 contains the first Thursday. */
50
- function isoWeekKey(ts) {
51
- const d = new Date(ts);
52
- if (Number.isNaN(d.getTime()))
53
- return 'invalid';
54
- const target = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
55
- const day = target.getUTCDay() || 7;
56
- target.setUTCDate(target.getUTCDate() + 4 - day);
57
- const yearStart = new Date(Date.UTC(target.getUTCFullYear(), 0, 1));
58
- const weekNum = Math.ceil(((target.getTime() - yearStart.getTime()) / 86_400_000 + 1) / 7);
59
- return `${target.getUTCFullYear()}-W${String(weekNum).padStart(2, '0')}`;
60
- }
61
- function emptyBucket() {
62
- return { tokensIn: 0, tokensOut: 0, turns: 0, costUsd: 0, durationMsTotal: 0 };
63
- }
64
- function addToBucket(bucket, row, cost) {
65
- bucket.tokensIn += row.inputTokens;
66
- bucket.tokensOut += row.outputTokens;
67
- bucket.turns += 1;
68
- bucket.costUsd += cost;
69
- bucket.durationMsTotal += row.durationMs ?? 0;
70
- }
71
- export function rollupCosts(jsonlPath) {
72
- const result = {
73
- daily: {},
74
- weekly: {},
75
- totals: emptyBucket(),
76
- rowCount: 0,
77
- skippedCount: 0,
78
- };
79
- let raw;
80
- try {
81
- raw = fs.readFileSync(jsonlPath, 'utf8');
82
- }
83
- catch {
84
- return result;
85
- }
86
- for (const line of raw.split('\n')) {
87
- if (!line.trim())
88
- continue;
89
- let row;
90
- try {
91
- row = JSON.parse(line);
92
- }
93
- catch {
94
- result.skippedCount += 1;
95
- continue;
96
- }
97
- if (!row.ts || typeof row.inputTokens !== 'number' || typeof row.outputTokens !== 'number') {
98
- result.skippedCount += 1;
99
- continue;
100
- }
101
- const dayKey = isoDateKey(row.ts);
102
- const weekKey = isoWeekKey(row.ts);
103
- const cost = computeCostUsd(row);
104
- if (!result.daily[dayKey])
105
- result.daily[dayKey] = emptyBucket();
106
- if (!result.weekly[weekKey])
107
- result.weekly[weekKey] = emptyBucket();
108
- addToBucket(result.daily[dayKey], row, cost);
109
- addToBucket(result.weekly[weekKey], row, cost);
110
- addToBucket(result.totals, row, cost);
111
- result.rowCount += 1;
112
- }
113
- return result;
114
- }
115
- /** Compact one-line summary for /status output. */
116
- export function formatRollupLine(rollup, today) {
117
- const day = rollup.daily[today] ?? emptyBucket();
118
- const yearWeek = isoWeekKey(`${today}T00:00:00Z`);
119
- const week = rollup.weekly[yearWeek] ?? emptyBucket();
120
- return [
121
- `today $${day.costUsd.toFixed(4)} (${day.turns} turns, ${day.tokensIn + day.tokensOut} tok)`,
122
- `week $${week.costUsd.toFixed(4)} (${week.turns} turns, ${week.tokensIn + week.tokensOut} tok)`,
123
- ].join(' | ');
124
- }
125
- //# sourceMappingURL=cost-rollup.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cost-rollup.js","sourceRoot":"","sources":["../../../src/lib/cost-rollup.ts"],"names":[],"mappings":"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"}