@chatpanel/events 0.82.0 → 0.82.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chatpanel/events",
3
- "version": "0.82.0",
3
+ "version": "0.82.1",
4
4
  "description": "The canonical ChatPanel event-log and capability contracts \u2014 typed durable facts, clock-free deterministic linearization, schema upcasting, and the invariants the replay harness asserts. Pure, dependency-free ESM shared by the ChatPanel extension, gateway and bridge.",
5
5
  "type": "module",
6
6
  "main": "index.js",
package/team-run.js CHANGED
@@ -213,10 +213,11 @@ export async function runTeam({
213
213
  // the next model on the roster is appointed and the task tried again, up to three
214
214
  // models. Anything else (a refusal, a timeout, a bad request) fails the task.
215
215
  const exclude = new Set();
216
+ let lastErr = '';
216
217
  for (let attempt = 1; ; attempt++) {
217
218
  const m = modelFor(role, exclude);
218
219
  if (!m?.model) throw new Error(exclude.size ? `no model left for role "${role.id}" after ${[...exclude].join(', ')}` : `no model for role "${role.id}"`);
219
- if (attempt > 1) say('task.reappointed', { taskId: task.id, role: role.id, model: m.model, after: [...exclude] });
220
+ if (attempt > 1) say('task.reappointed', { taskId: task.id, role: role.id, model: m.model, after: [...exclude], error: lastErr });
220
221
  // Who is doing this task, for a ledger that shows the lanes — said per attempt.
221
222
  say('task.model', { taskId: task.id, role: role.id, model: m.model, attempt });
222
223
  const res = await callModel({
@@ -235,7 +236,7 @@ export async function runTeam({
235
236
  if (res?.ok && String(res?.text || '').trim()) { text = String(res.text); break; }
236
237
  const err = res?.ok ? 'the model returned no answer' : (res?.error || 'the model did not answer');
237
238
  if (attempt >= MAX_APPOINTMENTS || stopped() || !isModelUnavailable(err)) throw new Error(err);
238
- exclude.add(m.model);
239
+ exclude.add(m.model); lastErr = err;
239
240
  }
240
241
  }
241
242
  } catch (e) {
@@ -290,17 +291,18 @@ export async function runTeam({
290
291
  const judgeTools = withBoardTool(withRunCache(await toolsFor(judge), runCache, { role: judge.id }), boardToolProvider({ board, role: judge.id, taskId: 'merge', taskIds: null }));
291
292
  let res = null;
292
293
  const excl = new Set();
294
+ let judgeErr = '';
293
295
  for (let attempt = 1; attempt <= MAX_APPOINTMENTS; attempt++) {
294
296
  const mm = attempt === 1 ? m : modelFor(judge, excl);
295
297
  if (!mm?.model) break;
296
- if (attempt > 1) say('task.reappointed', { taskId: 'merge', role: judge.id, model: mm.model, after: [...excl] });
298
+ if (attempt > 1) say('task.reappointed', { taskId: 'merge', role: judge.id, model: mm.model, after: [...excl], error: judgeErr });
297
299
  say('task.model', { taskId: 'merge', role: judge.id, model: mm.model, attempt });
298
300
  res = await callModel({ runId: id, taskId: 'merge', role: judge.id, model: mm.model, mode: 'model', system: judge.prompt, prompt, tools: judgeTools, signal, onDelta: (delta, full) => say('task.delta', { taskId: 'merge', role: judge.id, delta, text: full }) });
299
301
  if (res?.usage) budget.charge(res.usage);
300
302
  if (res?.ok && String(res.text || '').trim()) break;
301
303
  const err = res?.ok ? 'the model returned no answer' : (res?.error || 'the model did not answer');
302
304
  if (stopped() || !isModelUnavailable(err)) break;
303
- excl.add(mm.model);
305
+ excl.add(mm.model); judgeErr = err;
304
306
  }
305
307
  const judged = res?.ok && String(res.text || '').trim();
306
308
  say(judged ? 'task.done' : 'task.failed', { taskId: 'merge', role: judge.id, status: judged ? 'ok' : 'failed', error: judged ? null : (res?.error || 'the judge did not answer'), findings: 0 });
package/team-trail.js CHANGED
@@ -15,7 +15,7 @@ export function teamLine(ev) {
15
15
  case 'run.resumed': return { type: 'status', text: `team ${ev.team} resumed${(ev.carried || []).length ? ` (${ev.carried.length} task${ev.carried.length === 1 ? '' : 's'} carried over)` : ''}` };
16
16
  case 'board.post': return ev.post && ev.post.kind !== 'finding' ? { type: 'status', text: `${ev.post.by} ${ev.post.replyTo ? 'replied' : 'posted'} (${ev.post.kind}): ${String(ev.post.text || '').slice(0, 120)}` } : null;
17
17
  case 'board.decision': return { type: 'status', text: `${ev.by || 'someone'} ${ev.status} a post` };
18
- case 'task.reappointed': return { type: 'status', text: `${role} → ${ev.model} (${(ev.after || []).join(', ')} unavailable)` };
18
+ case 'task.reappointed': return { type: 'status', text: `${role} → ${ev.model} (${(ev.after || []).join(', ')} unavailable${ev.error ? `: ${String(ev.error).slice(0, 120)}` : ''})` };
19
19
  case 'task.tool': return { type: 'tool', name: ev.name, text: `${role} ran ${ev.name}${ev.text ? ` — ${ev.text}` : ''}` };
20
20
  case 'task.finding': return { type: 'status', text: `${role}: ${String(ev.finding?.text || '').slice(0, 140)}` };
21
21
  case 'task.done': return { type: 'status', text: `${role} done · ${ev.findings || 0} finding${ev.findings === 1 ? '' : 's'}` };