zames_pro 2.82.53 → 2.82.54

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/CHANGELOG.md CHANGED
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.82.54] - 2026-10-23
11
+
12
+ ### Fixed
13
+
14
+ - **telemetry:** measure a rate-limit block once, at the lift
15
+ - **hooks:** load the config before firing the Stop hook
16
+ - **history:** match fragment types case-insensitively in every parser
17
+
10
18
  ## [2.82.53] - 2026-10-23
11
19
 
12
20
  ### Fixed
@@ -49,7 +49,11 @@ export function parseHistoryMessages(messages) {
49
49
  const want = role === 'assistant' ? 'RESPONSE' : 'REQUEST';
50
50
  let text = '';
51
51
  for (const fr of (raw && raw.fragments) || []) {
52
- if (!fr || fr.type !== want)
52
+ // The fragment TYPE is matched case-insensitively, like the role: a
53
+ // payload spelling it `response`/`request` (a proxy build, a JSON
54
+ // round-trip through a normalizer) skipped EVERY fragment and the
55
+ // restored dialogue came back empty although it carried the answer.
56
+ if (!fr || String(fr.type ?? '').toUpperCase() !== want)
53
57
  continue;
54
58
  if (typeof fr.content === 'string')
55
59
  text += fr.content;
package/dist/glm-chats.js CHANGED
@@ -213,7 +213,11 @@ export function parseGlmHistory(json) {
213
213
  else if (Array.isArray(m.fragments)) {
214
214
  const want = role === 'assistant' ? 'RESPONSE' : 'REQUEST';
215
215
  for (const fr of m.fragments) {
216
- if (fr && fr.type === want && typeof fr.content === 'string') {
216
+ // Case-insensitive, like the DeepSeek parser: a payload spelling the
217
+ // fragment type `response`/`request` used to contribute nothing.
218
+ if (fr &&
219
+ String(fr.type ?? '').toUpperCase() === want &&
220
+ typeof fr.content === 'string') {
217
221
  text += fr.content;
218
222
  }
219
223
  }
@@ -266,7 +266,11 @@ export function parseQwenHistory(json) {
266
266
  else if (Array.isArray(m.fragments)) {
267
267
  const want = role === 'assistant' ? 'RESPONSE' : 'REQUEST';
268
268
  for (const fr of m.fragments) {
269
- if (fr && fr.type === want && typeof fr.content === 'string') {
269
+ // Case-insensitive, like the DeepSeek parser: a payload spelling the
270
+ // fragment type `response`/`request` used to contribute nothing.
271
+ if (fr &&
272
+ String(fr.type ?? '').toUpperCase() === want &&
273
+ typeof fr.content === 'string') {
270
274
  text += fr.content;
271
275
  }
272
276
  }
package/dist/run-task.js CHANGED
@@ -573,8 +573,11 @@ export async function runTask(deps, browser, tools, taskText, workdir, opts, att
573
573
  // Stop hook (N32): the whole task (including drained queue messages) is
574
574
  // done. A cleanup/notification hook runs here. Best-effort.
575
575
  try {
576
- const { runLifecycleHooks } = await import('./hooks.js');
577
- const out = await runLifecycleHooks(undefined, 'Stop', workdir, {
576
+ // LOAD the config: `undefined` here made every Stop hook a no-op — the
577
+ // operator's `.zames/hooks.json` entry never ran, while the PreToolUse
578
+ // hooks from the SAME file worked (they are loaded separately).
579
+ const { runLifecycleHooks, loadHooks } = await import('./hooks.js');
580
+ const out = await runLifecycleHooks(loadHooks(workdir), 'Stop', workdir, {
578
581
  failure: failure ?? '',
579
582
  });
580
583
  if (out)
@@ -10,7 +10,7 @@
10
10
  // survives across tasks and a provider switch within a session (a new browser
11
11
  // object is created, but the operator's decision about the interval does not
12
12
  // silently reset mid-session — it is re-derived from this session's events).
13
- import { DEFAULT_THROTTLE, initialThrottleState, applySendEvent, nextWaitMs, withBlockDuration, } from './send-throttle.js';
13
+ import { DEFAULT_THROTTLE, initialThrottleState, applySendEvent, nextWaitMs, } from './send-throttle.js';
14
14
  import { appendSendEvent, } from './send-telemetry.js';
15
15
  /**
16
16
  * The runtime a provider keeps: the learned interval, the last send and the
@@ -72,7 +72,7 @@ export class SendRuntime {
72
72
  onOutcome(outcome, extra = {}) {
73
73
  if (!this.pending)
74
74
  return;
75
- let e = { ...this.pending, outcome };
75
+ const e = { ...this.pending, outcome };
76
76
  if (extra.errorText)
77
77
  e.errorText = String(extra.errorText).slice(0, 300);
78
78
  if (typeof extra.retryAfterMs === 'number') {
@@ -88,7 +88,14 @@ export class SendRuntime {
88
88
  this.state = { ...this.state, blocked: true, blockedAt: this.now() };
89
89
  }
90
90
  if (outcome === 'rate_limit') {
91
- e = withBlockDuration(e, this.state.blockedAt, this.now());
91
+ // The block START is only known AFTER the fold above (the adaptive path
92
+ // sets it there). The event itself carries NO duration: a rate-limit
93
+ // send is not the END of the block, so any value measured here is a
94
+ // lower bound that would then be averaged together with the real
95
+ // duration written by onBlockLifted — the same block counted TWICE.
96
+ if (!this.state.blockedAt) {
97
+ this.state = { ...this.state, blocked: true, blockedAt: this.now() };
98
+ }
92
99
  }
93
100
  if (this.opts.telemetry) {
94
101
  appendSendEvent(this.opts.logsDir, e);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zames_pro",
3
- "version": "2.82.53",
3
+ "version": "2.82.54",
4
4
  "description": "Terminal coding agent that drives a real browser to chat with DeepSeek, Qwen and other web LLMs — no API key required. Reads and edits files, runs commands, commits to git, like Claude Code / Codex CLI.",
5
5
  "type": "module",
6
6
  "bin": {