@frumu/tandem-panel 0.4.8 → 0.4.10
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/README.md +23 -0
- package/bin/docker-token.js +54 -0
- package/dist/assets/{index-CCT37xUj.css → index-46K5pYDz.css} +1 -1
- package/dist/assets/index-EGEu-G8H.js +2460 -0
- package/dist/assets/{react-query-CeeFMKtE.js → react-query-wD0mx2Xi.js} +1 -1
- package/dist/assets/{vendor-UXzYZoAT.js → vendor-BB3fzNns.js} +2 -2
- package/dist/index.html +4 -4
- package/lib/setup/bootstrap.js +50 -0
- package/lib/setup/common.js +83 -0
- package/lib/setup/doctor.js +73 -0
- package/lib/setup/env.js +190 -0
- package/lib/setup/paths.js +65 -0
- package/lib/setup/services/common.js +45 -0
- package/lib/setup/services/launchd.js +109 -0
- package/lib/setup/services/systemd.js +104 -0
- package/package.json +11 -3
- package/server/routes/swarm.js +949 -0
- package/server/services/orchestratorService.js +147 -0
- package/dist/assets/index-BIn54WIy.js +0 -2460
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
export function mapOrchestratorPath(pathname) {
|
|
2
|
+
const path = String(pathname || "").trim();
|
|
3
|
+
if (path.startsWith("/api/orchestrator")) {
|
|
4
|
+
return `/api/swarm${path.slice("/api/orchestrator".length)}`;
|
|
5
|
+
}
|
|
6
|
+
return path;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function toNumber(value) {
|
|
10
|
+
const parsed = Number(value);
|
|
11
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function pickNumeric(...values) {
|
|
15
|
+
for (const value of values) {
|
|
16
|
+
const parsed = Number(value);
|
|
17
|
+
if (Number.isFinite(parsed) && parsed > 0) return parsed;
|
|
18
|
+
}
|
|
19
|
+
return 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const DERIVED_MAX_ITERATIONS = 500;
|
|
23
|
+
const DERIVED_MAX_TOKENS = 400000;
|
|
24
|
+
const DERIVED_MAX_WALL_TIME_SECS = 7 * 24 * 60 * 60;
|
|
25
|
+
const DERIVED_MAX_SUBAGENT_RUNS = 2000;
|
|
26
|
+
|
|
27
|
+
function hasExplicitBudgetLimits(run) {
|
|
28
|
+
return (
|
|
29
|
+
pickNumeric(
|
|
30
|
+
run?.budget?.max_iterations,
|
|
31
|
+
run?.config?.max_iterations,
|
|
32
|
+
run?.budget?.max_tokens,
|
|
33
|
+
run?.budget?.max_total_tokens,
|
|
34
|
+
run?.config?.max_total_tokens,
|
|
35
|
+
run?.budget?.max_wall_time_secs,
|
|
36
|
+
run?.config?.max_wall_time_secs,
|
|
37
|
+
run?.budget?.max_subagent_runs,
|
|
38
|
+
run?.config?.max_subagent_runs
|
|
39
|
+
) > 0
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function deriveRunBudget(run, events, tasks) {
|
|
44
|
+
const startedAtMs = toNumber(run?.started_at_ms);
|
|
45
|
+
const updatedAtMs = toNumber(run?.updated_at_ms || Date.now());
|
|
46
|
+
const wallTimeSecs =
|
|
47
|
+
startedAtMs > 0 && updatedAtMs >= startedAtMs
|
|
48
|
+
? Math.round((updatedAtMs - startedAtMs) / 1000)
|
|
49
|
+
: 0;
|
|
50
|
+
const iterationsUsed = Array.isArray(events)
|
|
51
|
+
? events.filter((row) =>
|
|
52
|
+
String(row?.type || "")
|
|
53
|
+
.toLowerCase()
|
|
54
|
+
.includes("task_")
|
|
55
|
+
).length
|
|
56
|
+
: 0;
|
|
57
|
+
const tokenEvents = Array.isArray(events) ? events : [];
|
|
58
|
+
let tokensUsed = 0;
|
|
59
|
+
for (const event of tokenEvents) {
|
|
60
|
+
const payload = event?.payload && typeof event.payload === "object" ? event.payload : {};
|
|
61
|
+
const total = pickNumeric(
|
|
62
|
+
payload?.total_tokens,
|
|
63
|
+
payload?.tokens_total,
|
|
64
|
+
payload?.token_count,
|
|
65
|
+
payload?.usage_total_tokens
|
|
66
|
+
);
|
|
67
|
+
if (total > 0) tokensUsed = Math.max(tokensUsed, total);
|
|
68
|
+
const prompt = toNumber(payload?.prompt_tokens || payload?.input_tokens);
|
|
69
|
+
const completion = toNumber(payload?.completion_tokens || payload?.output_tokens);
|
|
70
|
+
if (prompt + completion > tokensUsed) tokensUsed = prompt + completion;
|
|
71
|
+
}
|
|
72
|
+
const explicitBudget = hasExplicitBudgetLimits(run);
|
|
73
|
+
const maxIterations = pickNumeric(
|
|
74
|
+
run?.budget?.max_iterations,
|
|
75
|
+
run?.config?.max_iterations,
|
|
76
|
+
DERIVED_MAX_ITERATIONS
|
|
77
|
+
);
|
|
78
|
+
const maxTokens = pickNumeric(
|
|
79
|
+
run?.budget?.max_tokens,
|
|
80
|
+
run?.budget?.max_total_tokens,
|
|
81
|
+
run?.config?.max_total_tokens,
|
|
82
|
+
DERIVED_MAX_TOKENS
|
|
83
|
+
);
|
|
84
|
+
const maxWallTimeSecs = pickNumeric(
|
|
85
|
+
run?.budget?.max_wall_time_secs,
|
|
86
|
+
run?.config?.max_wall_time_secs,
|
|
87
|
+
DERIVED_MAX_WALL_TIME_SECS
|
|
88
|
+
);
|
|
89
|
+
const maxSubagentRuns = pickNumeric(
|
|
90
|
+
run?.budget?.max_subagent_runs,
|
|
91
|
+
run?.config?.max_subagent_runs,
|
|
92
|
+
Math.max(DERIVED_MAX_SUBAGENT_RUNS, tasks.length * 6)
|
|
93
|
+
);
|
|
94
|
+
const subagentRunsUsed = Array.isArray(events)
|
|
95
|
+
? events.filter((row) =>
|
|
96
|
+
String(row?.type || "")
|
|
97
|
+
.toLowerCase()
|
|
98
|
+
.includes("task_completed")
|
|
99
|
+
).length
|
|
100
|
+
: 0;
|
|
101
|
+
const measuredExceeded =
|
|
102
|
+
iterationsUsed >= maxIterations ||
|
|
103
|
+
tokensUsed >= maxTokens ||
|
|
104
|
+
wallTimeSecs >= maxWallTimeSecs ||
|
|
105
|
+
subagentRunsUsed >= maxSubagentRuns;
|
|
106
|
+
const exceeded = explicitBudget
|
|
107
|
+
? Boolean(run?.budget?.exceeded) || measuredExceeded
|
|
108
|
+
: Boolean(run?.budget?.exceeded);
|
|
109
|
+
const exceededReason = explicitBudget
|
|
110
|
+
? String(
|
|
111
|
+
run?.budget?.exceeded_reason || (exceeded ? "One or more execution limits exceeded." : "")
|
|
112
|
+
)
|
|
113
|
+
: "";
|
|
114
|
+
return {
|
|
115
|
+
max_iterations: maxIterations,
|
|
116
|
+
iterations_used: iterationsUsed,
|
|
117
|
+
max_tokens: maxTokens,
|
|
118
|
+
tokens_used: tokensUsed,
|
|
119
|
+
max_wall_time_secs: maxWallTimeSecs,
|
|
120
|
+
wall_time_secs: wallTimeSecs,
|
|
121
|
+
max_subagent_runs: maxSubagentRuns,
|
|
122
|
+
subagent_runs_used: subagentRunsUsed,
|
|
123
|
+
exceeded,
|
|
124
|
+
exceeded_reason: exceededReason,
|
|
125
|
+
limits_enforced: explicitBudget,
|
|
126
|
+
source: explicitBudget ? "run" : "derived",
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function inferStatusFromEvents(status, events) {
|
|
131
|
+
const normalized = String(status || "")
|
|
132
|
+
.trim()
|
|
133
|
+
.toLowerCase();
|
|
134
|
+
if (normalized && normalized !== "planning") return normalized;
|
|
135
|
+
const rows = Array.isArray(events) ? events : [];
|
|
136
|
+
let sawPlanReady = false;
|
|
137
|
+
let sawPlanApproved = false;
|
|
138
|
+
for (const row of rows) {
|
|
139
|
+
const type = String(row?.type || "")
|
|
140
|
+
.trim()
|
|
141
|
+
.toLowerCase();
|
|
142
|
+
if (type === "plan_ready_for_approval") sawPlanReady = true;
|
|
143
|
+
if (type === "plan_approved") sawPlanApproved = true;
|
|
144
|
+
}
|
|
145
|
+
if (sawPlanReady && !sawPlanApproved) return "awaiting_approval";
|
|
146
|
+
return normalized || "idle";
|
|
147
|
+
}
|