@chatpanel/events 0.89.3 → 0.89.4
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/index.js +1 -1
- package/package.json +1 -1
- package/team-board.js +3 -1
- package/team-run.js +12 -2
- package/team-tool.js +13 -0
package/index.js
CHANGED
|
@@ -212,7 +212,7 @@ export { DEFAULT_MIN_CALLS, cardOverride, applyCard } from './model-candidates.j
|
|
|
212
212
|
export { SCM_KINDS, validateConnection, normalizeConnection, parseRemote, connectionFor, branchFor, worktreeDirFor, credentialEnv, describeConnection, blankConnection, connectionFromForm } from './scm-connection.js';
|
|
213
213
|
export { messagesFor, mergeTranscript, clipTranscript, clipMessage, newSteps, continuationNote, createControl, STEP_MAX_CHARS, TASK_TRANSCRIPT_MAX_CHARS } from './team-task.js';
|
|
214
214
|
export { runTeam, resumeTeam, dryRunTeam, isModelUnavailable, TeamRunError, RUN_STATUSES } from './team-run.js';
|
|
215
|
-
export { teamToolProvider, teamToolSpec, describeTeamForApproval, TEAM_TOOL_NAME } from './team-tool.js';
|
|
215
|
+
export { teamToolProvider, teamToolSpec, teamToolTimeoutMs, describeTeamForApproval, TEAM_TOOL_NAME } from './team-tool.js';
|
|
216
216
|
export { teamLine, teamLanes } from './team-trail.js';
|
|
217
217
|
export { mcpDispatchProvider, MCP_TOOL_NAME } from './mcp-dispatch.js';
|
|
218
218
|
export { createManifest, ManifestError, SOURCES } from './manifest.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chatpanel/events",
|
|
3
|
-
"version": "0.89.
|
|
3
|
+
"version": "0.89.4",
|
|
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-board.js
CHANGED
|
@@ -74,7 +74,9 @@ export function parseFindings(text, { role, taskId } = {}) {
|
|
|
74
74
|
// ── threads, posts, asks ────────────────────────────────────────────────────────────────
|
|
75
75
|
|
|
76
76
|
export const THREAD_KINDS = Object.freeze(['task', 'ask', 'discussion', 'proposal']);
|
|
77
|
-
|
|
77
|
+
// `failed`: the task behind the thread ended without an answer (every model on the roster
|
|
78
|
+
// tried, or a hard error) — not `resolved`, which read as "done" on the board.
|
|
79
|
+
export const THREAD_STATUSES = Object.freeze(['open', 'waiting', 'resolved', 'failed', 'approved', 'rejected']);
|
|
78
80
|
export const POST_KINDS = Object.freeze(['finding', 'note', 'question', 'answer', 'draft', 'decision']);
|
|
79
81
|
export const POST_STATUSES = Object.freeze(['open', 'proposed', 'approved', 'rejected']);
|
|
80
82
|
export const ASK_TYPES = Object.freeze(['info', 'budget', 'permission', 'direction']);
|
package/team-run.js
CHANGED
|
@@ -58,7 +58,11 @@ export function isModelUnavailable(error) {
|
|
|
58
58
|
// Also: a relayed agent that exited, a provider that closed the stream, and a turn that
|
|
59
59
|
// came back with nothing — the model did not answer, and the next one might. A refusal,
|
|
60
60
|
// a timeout the caller set, a bad request or a budget stop are not this.
|
|
61
|
-
|
|
61
|
+
// A server that is not there: Node says ECONNREFUSED, a browser says only "Failed to
|
|
62
|
+
// fetch" (the extension reports it as "network error") — a local model killed mid-run
|
|
63
|
+
// arrived as the latter and ended the task on its first attempt with Claude Code sitting
|
|
64
|
+
// idle on the roster.
|
|
65
|
+
return /model[_ ]not[_ ]found|not found|not deployed|inaccessible|does not exist|no such model|unknown model|unsupported model|not available|unavailable|no api key|not configured|"status":\s*(404|401|403|500|502|503)\b|\b(404|401|403|502|503)\b|exited \d+|returned no answer|did not answer|closed the connection|couldn't reach|could not reach|ECONNREFUSED|ECONNRESET|ENOTFOUND|EHOSTUNREACH|socket hang up|fetch failed|failed to fetch|load failed|network ?error|overloaded|capacity/i.test(m);
|
|
62
66
|
}
|
|
63
67
|
|
|
64
68
|
export function dryRunTeam(team, request, { appoint = null } = {}) {
|
|
@@ -355,7 +359,13 @@ export async function runTeam({
|
|
|
355
359
|
const findings = status === 'ok' ? parseFindings(text, { role: role.id, taskId: task.id }) : [];
|
|
356
360
|
if (findings.length) { board.add(findings); for (const f of findings) say('task.finding', { taskId: task.id, role: role.id, finding: f }); }
|
|
357
361
|
const thread = board.threadForTask(task.id);
|
|
358
|
-
|
|
362
|
+
// The thread says how the task ended. A failure is posted in it as well — a person reading
|
|
363
|
+
// the board sees "researcher failed: network error" where it happened, and what was tried.
|
|
364
|
+
if (thread && status === 'ok') board.setThreadStatus(thread.id, 'resolved');
|
|
365
|
+
else if (thread && status !== 'waiting') {
|
|
366
|
+
board.post({ threadId: thread.id, by: RUNNER, kind: 'note', text: `${role.id} ${status === 'over-budget' ? 'stopped at the budget' : 'failed'}${error ? `: ${String(error).slice(0, 300)}` : ''}${attempts.length > 1 ? ` (after ${attempts.length} models: ${attempts.map((a) => a.model).join(', ')})` : ''}.` });
|
|
367
|
+
board.setThreadStatus(thread.id, 'failed');
|
|
368
|
+
}
|
|
359
369
|
const row = { id: task.id, role: task.role, title: task.title, status, text, error, usage, ms: now() - t0, findings, transcript: clipTranscript(transcript), attempts, ...(routed ? { routed } : {}), ...(scm ? { scm } : {}), ...(askedAndWaiting ? { waitingOn: askedAndWaiting } : {}) };
|
|
360
370
|
tasksOut.push(row);
|
|
361
371
|
say(status === 'ok' ? 'task.done' : 'task.failed', { taskId: task.id, role: task.role, status, error, ms: row.ms, findings: findings.length, ...(askedAndWaiting ? { threadId: askedAndWaiting } : {}) });
|
package/team-tool.js
CHANGED
|
@@ -26,10 +26,23 @@ function catalogue(teams) {
|
|
|
26
26
|
return `Saved teams: ${list.map((t) => `${t.name} (${(t.roles || []).map((r) => r.id).join(', ')})${t.description ? ` — ${t.description}` : ''}`).join('; ')}.`;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* How long one call of the tool may take: the longest budget among the teams plus the merge,
|
|
31
|
+
* never under two minutes. A relay between a CLI agent and this tool (the bridge's MCP
|
|
32
|
+
* server) times a call by this; without it a 300 s team hit the relay's 120 s default,
|
|
33
|
+
* Claude Code was told "tool call timed out" and ran the team AGAIN while the first run was
|
|
34
|
+
* still working.
|
|
35
|
+
*/
|
|
36
|
+
export function teamToolTimeoutMs(teams) {
|
|
37
|
+
const longest = Math.max(0, ...(teams || []).map((t) => Number(t?.budget?.ms) || 0));
|
|
38
|
+
return Math.max(120_000, (longest || 10 * 60_000) + 60_000);
|
|
39
|
+
}
|
|
40
|
+
|
|
29
41
|
export function teamToolSpec(teams) {
|
|
30
42
|
return {
|
|
31
43
|
name: TEAM_TOOL_NAME,
|
|
32
44
|
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false },
|
|
45
|
+
timeoutMs: teamToolTimeoutMs(teams),
|
|
33
46
|
description:
|
|
34
47
|
`Saved agent teams — several roles working a request in parallel, merged into one answer. ${catalogue(teams)} `
|
|
35
48
|
+ 'Actions: {"action":"run","name":"<team>","request":"<what to do>"} runs one (streams; may take a while); '
|