@chatpanel/events 0.82.0 → 0.82.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chatpanel/events",
3
- "version": "0.82.0",
3
+ "version": "0.82.2",
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) {
@@ -258,7 +259,8 @@ export async function runTeam({
258
259
  budgetAsked = true;
259
260
  const left = tasks.filter((x) => !tasksOut.some((y) => y.id === x.id)).length;
260
261
  const spent = budget.snapshot().spent;
261
- const a = await askPerson({ type: 'budget', text: `The team has used its budget (${Object.entries(spent).filter(([k]) => budget.cap[k] !== undefined).map(([k, v]) => `${k} ${v} of ${budget.cap[k]}`).join(', ')}) with ${left} task${left === 1 ? '' : 's'} left. Raise it by half, or stop here with what it has?`, options: ['Raise by half', 'Stop here'] });
262
+ const what = left ? `${left} task${left === 1 ? '' : 's'} and the merge left` : 'only the merge left';
263
+ const a = await askPerson({ type: 'budget', text: `The team has used its budget (${Object.entries(spent).filter(([k]) => budget.cap[k] !== undefined).map(([k, v]) => `${k} ${v} of ${budget.cap[k]}`).join(', ')}) with ${what}. Raise it by half, or stop here with what it has?`, options: ['Raise by half', 'Stop here'] });
262
264
  if (a && /raise|allow|yes|more|continue/i.test(a.text)) { budget.raise(1.5); overBudget = false; }
263
265
  }
264
266
  }
@@ -290,17 +292,18 @@ export async function runTeam({
290
292
  const judgeTools = withBoardTool(withRunCache(await toolsFor(judge), runCache, { role: judge.id }), boardToolProvider({ board, role: judge.id, taskId: 'merge', taskIds: null }));
291
293
  let res = null;
292
294
  const excl = new Set();
295
+ let judgeErr = '';
293
296
  for (let attempt = 1; attempt <= MAX_APPOINTMENTS; attempt++) {
294
297
  const mm = attempt === 1 ? m : modelFor(judge, excl);
295
298
  if (!mm?.model) break;
296
- if (attempt > 1) say('task.reappointed', { taskId: 'merge', role: judge.id, model: mm.model, after: [...excl] });
299
+ if (attempt > 1) say('task.reappointed', { taskId: 'merge', role: judge.id, model: mm.model, after: [...excl], error: judgeErr });
297
300
  say('task.model', { taskId: 'merge', role: judge.id, model: mm.model, attempt });
298
301
  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
302
  if (res?.usage) budget.charge(res.usage);
300
303
  if (res?.ok && String(res.text || '').trim()) break;
301
304
  const err = res?.ok ? 'the model returned no answer' : (res?.error || 'the model did not answer');
302
305
  if (stopped() || !isModelUnavailable(err)) break;
303
- excl.add(mm.model);
306
+ excl.add(mm.model); judgeErr = err;
304
307
  }
305
308
  const judged = res?.ok && String(res.text || '').trim();
306
309
  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'}` };