@teamclaws/teamclaw 2026.3.25 → 2026.3.26-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/README.md +6 -0
- package/cli.mjs +519 -28
- package/index.ts +31 -16
- package/openclaw.plugin.json +3 -3
- package/package.json +16 -4
- package/src/config.ts +2 -2
- package/src/controller/controller-capacity.ts +23 -0
- package/src/controller/controller-service.ts +27 -1
- package/src/controller/controller-tools.ts +251 -7
- package/src/controller/http-server.ts +976 -38
- package/src/controller/orchestration-manifest.ts +105 -0
- package/src/controller/prompt-injector.ts +42 -7
- package/src/controller/worker-provisioning.ts +171 -13
- package/src/git-collaboration.ts +2 -0
- package/src/interaction-contracts.ts +459 -0
- package/src/task-executor.ts +482 -33
- package/src/types.ts +96 -0
- package/src/ui/app.js +313 -8
- package/src/ui/style.css +152 -0
- package/src/worker/http-handler.ts +15 -7
- package/src/worker/prompt-injector.ts +2 -0
- package/src/worker/skill-installer.ts +13 -0
- package/src/worker/tools.ts +172 -3
- package/src/worker/worker-service.ts +9 -6
package/src/types.ts
CHANGED
|
@@ -106,8 +106,11 @@ export type TaskInfo = {
|
|
|
106
106
|
startedAt?: number;
|
|
107
107
|
completedAt?: number;
|
|
108
108
|
progress?: string;
|
|
109
|
+
progressContract?: WorkerProgressContract;
|
|
109
110
|
result?: string;
|
|
111
|
+
resultContract?: WorkerTaskResultContract;
|
|
110
112
|
error?: string;
|
|
113
|
+
lastHandoff?: TaskHandoffContract;
|
|
111
114
|
clarificationRequestId?: string;
|
|
112
115
|
execution?: TaskExecution;
|
|
113
116
|
};
|
|
@@ -130,11 +133,102 @@ export type TaskAssignmentPayload = {
|
|
|
130
133
|
description: string;
|
|
131
134
|
priority?: TaskPriority;
|
|
132
135
|
recommendedSkills?: string[];
|
|
136
|
+
executionSessionKey?: string;
|
|
137
|
+
executionIdempotencyKey?: string;
|
|
133
138
|
repo?: RepoSyncInfo;
|
|
134
139
|
};
|
|
135
140
|
|
|
136
141
|
export type ControllerRunSource = "human" | "task_follow_up";
|
|
137
142
|
|
|
143
|
+
export type WorkerTaskResultOutcome = "completed" | "blocked" | "failed";
|
|
144
|
+
|
|
145
|
+
export type WorkerTaskResultDeliverable = {
|
|
146
|
+
kind: "file" | "directory" | "command" | "artifact" | "note";
|
|
147
|
+
value: string;
|
|
148
|
+
summary?: string;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
export type WorkerTaskResultFollowUp = {
|
|
152
|
+
type: "review" | "handoff" | "clarification" | "downstream-task";
|
|
153
|
+
targetRole?: RoleId;
|
|
154
|
+
reason: string;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export type WorkerTaskResultContract = {
|
|
158
|
+
version: string;
|
|
159
|
+
outcome: WorkerTaskResultOutcome;
|
|
160
|
+
summary: string;
|
|
161
|
+
deliverables: WorkerTaskResultDeliverable[];
|
|
162
|
+
keyPoints: string[];
|
|
163
|
+
blockers: string[];
|
|
164
|
+
followUps: WorkerTaskResultFollowUp[];
|
|
165
|
+
questions: string[];
|
|
166
|
+
notes?: string;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
export type WorkerProgressContract = {
|
|
170
|
+
version: string;
|
|
171
|
+
summary: string;
|
|
172
|
+
status: "in_progress" | "review";
|
|
173
|
+
currentStep?: string;
|
|
174
|
+
nextStep?: string;
|
|
175
|
+
blockers: string[];
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
export type TaskHandoffContract = {
|
|
179
|
+
version: string;
|
|
180
|
+
summary: string;
|
|
181
|
+
reason: string;
|
|
182
|
+
targetRole?: RoleId;
|
|
183
|
+
expectedNextStep?: string;
|
|
184
|
+
artifacts: string[];
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
export type TeamMessageIntent =
|
|
188
|
+
| "question"
|
|
189
|
+
| "announcement"
|
|
190
|
+
| "handoff"
|
|
191
|
+
| "review-request"
|
|
192
|
+
| "review-response"
|
|
193
|
+
| "update"
|
|
194
|
+
| "coordination";
|
|
195
|
+
|
|
196
|
+
export type TeamMessageContract = {
|
|
197
|
+
version: string;
|
|
198
|
+
intent: TeamMessageIntent;
|
|
199
|
+
summary: string;
|
|
200
|
+
details?: string;
|
|
201
|
+
requestedAction?: string;
|
|
202
|
+
requestedRole?: RoleId;
|
|
203
|
+
needsResponse: boolean;
|
|
204
|
+
references: string[];
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export type ControllerManifestCreatedTask = {
|
|
208
|
+
title: string;
|
|
209
|
+
assignedRole?: RoleId;
|
|
210
|
+
expectedOutcome: string;
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
export type ControllerManifestDeferredTask = {
|
|
214
|
+
title: string;
|
|
215
|
+
assignedRole?: RoleId;
|
|
216
|
+
blockedBy: string;
|
|
217
|
+
whenReady: string;
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
export type ControllerOrchestrationManifest = {
|
|
221
|
+
version: string;
|
|
222
|
+
requirementSummary: string;
|
|
223
|
+
requiredRoles: RoleId[];
|
|
224
|
+
clarificationsNeeded: boolean;
|
|
225
|
+
clarificationQuestions: string[];
|
|
226
|
+
createdTasks: ControllerManifestCreatedTask[];
|
|
227
|
+
deferredTasks: ControllerManifestDeferredTask[];
|
|
228
|
+
handoffPlan?: string;
|
|
229
|
+
notes?: string;
|
|
230
|
+
};
|
|
231
|
+
|
|
138
232
|
export type ControllerRunInfo = {
|
|
139
233
|
id: string;
|
|
140
234
|
title: string;
|
|
@@ -147,6 +241,7 @@ export type ControllerRunInfo = {
|
|
|
147
241
|
reply?: string;
|
|
148
242
|
error?: string;
|
|
149
243
|
createdTaskIds: string[];
|
|
244
|
+
manifest?: ControllerOrchestrationManifest;
|
|
150
245
|
status: TaskExecutionStatus;
|
|
151
246
|
createdAt: number;
|
|
152
247
|
updatedAt: number;
|
|
@@ -216,6 +311,7 @@ export type TeamMessage = {
|
|
|
216
311
|
toRole?: RoleId;
|
|
217
312
|
type: "direct" | "broadcast" | "review-request";
|
|
218
313
|
content: string;
|
|
314
|
+
contract?: TeamMessageContract;
|
|
219
315
|
taskId?: string;
|
|
220
316
|
createdAt: number;
|
|
221
317
|
};
|
package/src/ui/app.js
CHANGED
|
@@ -292,6 +292,243 @@
|
|
|
292
292
|
return '<div class="task-detail-card markdown-body">' + renderMarkdownContent(content) + "</div>";
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
+
function normalizeTextValue(value) {
|
|
296
|
+
return String(value == null ? "" : value).replace(/\s+/g, " ").trim();
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function renderContractChips(items, className) {
|
|
300
|
+
const normalized = Array.isArray(items)
|
|
301
|
+
? items.map(function (item) { return normalizeTextValue(item); }).filter(Boolean)
|
|
302
|
+
: [];
|
|
303
|
+
if (normalized.length === 0) {
|
|
304
|
+
return "";
|
|
305
|
+
}
|
|
306
|
+
return '<div class="' + escapeHtml(className || "contract-chip-row") + '">' + normalized.map(function (item) {
|
|
307
|
+
return '<span class="contract-chip">' + escapeHtml(item) + "</span>";
|
|
308
|
+
}).join("") + "</div>";
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function renderContractList(items, formatter, className) {
|
|
312
|
+
const values = Array.isArray(items) ? items.filter(Boolean) : [];
|
|
313
|
+
if (values.length === 0) {
|
|
314
|
+
return "";
|
|
315
|
+
}
|
|
316
|
+
return '<ul class="' + escapeHtml(className || "contract-list") + '">' + values.map(function (item) {
|
|
317
|
+
return "<li>" + formatter(item) + "</li>";
|
|
318
|
+
}).join("") + "</ul>";
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function renderContractMetaRows(rows) {
|
|
322
|
+
const items = (rows || []).filter(function (row) {
|
|
323
|
+
return row && normalizeTextValue(row.label) && normalizeTextValue(row.value);
|
|
324
|
+
});
|
|
325
|
+
if (items.length === 0) {
|
|
326
|
+
return "";
|
|
327
|
+
}
|
|
328
|
+
return '<div class="contract-meta-grid">' + items.map(function (row) {
|
|
329
|
+
return (
|
|
330
|
+
'<div class="contract-meta-item">' +
|
|
331
|
+
' <div class="contract-meta-label">' + escapeHtml(row.label) + "</div>" +
|
|
332
|
+
' <div class="contract-meta-value">' + escapeHtml(row.value) + "</div>" +
|
|
333
|
+
"</div>"
|
|
334
|
+
);
|
|
335
|
+
}).join("") + "</div>";
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function renderContractSection(title, bodyHtml) {
|
|
339
|
+
if (!normalizeTextValue(bodyHtml)) {
|
|
340
|
+
return "";
|
|
341
|
+
}
|
|
342
|
+
return (
|
|
343
|
+
'<div class="contract-section">' +
|
|
344
|
+
' <div class="contract-section-title">' + escapeHtml(title) + "</div>" +
|
|
345
|
+
bodyHtml +
|
|
346
|
+
"</div>"
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function renderContractMarkdownBody(content) {
|
|
351
|
+
if (!normalizeTextValue(content)) {
|
|
352
|
+
return "";
|
|
353
|
+
}
|
|
354
|
+
return '<div class="contract-markdown markdown-body">' + renderMarkdownContent(content) + "</div>";
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function renderContractCard(options) {
|
|
358
|
+
const tone = options && options.tone ? " contract-card-" + options.tone : "";
|
|
359
|
+
const kicker = options && options.kicker ? '<div class="contract-card-kicker">' + escapeHtml(options.kicker) + "</div>" : "";
|
|
360
|
+
const title = options && options.title ? '<h4 class="contract-card-title">' + escapeHtml(options.title) + "</h4>" : "";
|
|
361
|
+
const meta = options && options.metaHtml ? options.metaHtml : "";
|
|
362
|
+
const sections = Array.isArray(options && options.sections)
|
|
363
|
+
? options.sections.filter(function (section) { return normalizeTextValue(section); }).join("")
|
|
364
|
+
: "";
|
|
365
|
+
const footer = options && options.footerHtml ? options.footerHtml : "";
|
|
366
|
+
|
|
367
|
+
if (!kicker && !title && !meta && !sections && !footer) {
|
|
368
|
+
return "";
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return (
|
|
372
|
+
'<div class="contract-card' + tone + '">' +
|
|
373
|
+
' <div class="contract-card-header">' +
|
|
374
|
+
kicker +
|
|
375
|
+
title +
|
|
376
|
+
meta +
|
|
377
|
+
" </div>" +
|
|
378
|
+
sections +
|
|
379
|
+
footer +
|
|
380
|
+
"</div>"
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function renderResultContractCard(contract) {
|
|
385
|
+
if (!contract || !normalizeTextValue(contract.summary)) {
|
|
386
|
+
return "";
|
|
387
|
+
}
|
|
388
|
+
const deliverables = Array.isArray(contract.deliverables) ? contract.deliverables : [];
|
|
389
|
+
const followUps = Array.isArray(contract.followUps) ? contract.followUps : [];
|
|
390
|
+
return renderContractCard({
|
|
391
|
+
tone: contract.outcome || "completed",
|
|
392
|
+
kicker: "Structured Result Contract",
|
|
393
|
+
title: contract.summary,
|
|
394
|
+
metaHtml: renderContractMetaRows([
|
|
395
|
+
{ label: "Outcome", value: humanizeStatus(contract.outcome || "completed") },
|
|
396
|
+
{ label: "Deliverables", value: String(deliverables.length) },
|
|
397
|
+
{ label: "Follow-ups", value: String(followUps.length) },
|
|
398
|
+
]),
|
|
399
|
+
sections: [
|
|
400
|
+
renderContractSection("Deliverables", renderContractList(deliverables, function (item) {
|
|
401
|
+
const prefix = escapeHtml(item.kind || "artifact") + ": " + escapeHtml(item.value || "");
|
|
402
|
+
return prefix + (item.summary ? ' <span class="contract-inline-note">— ' + escapeHtml(item.summary) + "</span>" : "");
|
|
403
|
+
})),
|
|
404
|
+
renderContractSection("Key Points", renderContractList(contract.keyPoints, function (item) {
|
|
405
|
+
return renderMarkdownInline(item);
|
|
406
|
+
})),
|
|
407
|
+
renderContractSection("Blockers", renderContractList(contract.blockers, function (item) {
|
|
408
|
+
return renderMarkdownInline(item);
|
|
409
|
+
})),
|
|
410
|
+
renderContractSection("Follow-ups", renderContractList(followUps, function (item) {
|
|
411
|
+
const prefix = escapeHtml(item.type || "follow-up") + (item.targetRole ? " (" + escapeHtml(item.targetRole) + ")" : "");
|
|
412
|
+
return prefix + ": " + renderMarkdownInline(item.reason || "");
|
|
413
|
+
})),
|
|
414
|
+
renderContractSection("Open Questions", renderContractList(contract.questions, function (item) {
|
|
415
|
+
return renderMarkdownInline(item);
|
|
416
|
+
})),
|
|
417
|
+
renderContractSection("Notes", renderContractMarkdownBody(contract.notes)),
|
|
418
|
+
],
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function renderProgressContractCard(contract) {
|
|
423
|
+
if (!contract || !normalizeTextValue(contract.summary)) {
|
|
424
|
+
return "";
|
|
425
|
+
}
|
|
426
|
+
return renderContractCard({
|
|
427
|
+
tone: contract.status || "in_progress",
|
|
428
|
+
kicker: "Structured Progress Contract",
|
|
429
|
+
title: contract.summary,
|
|
430
|
+
metaHtml: renderContractMetaRows([
|
|
431
|
+
{ label: "Status", value: humanizeStatus(contract.status || "in_progress") },
|
|
432
|
+
{ label: "Blockers", value: String((contract.blockers || []).length) },
|
|
433
|
+
]),
|
|
434
|
+
sections: [
|
|
435
|
+
renderContractSection("Current Step", renderContractMarkdownBody(contract.currentStep)),
|
|
436
|
+
renderContractSection("Next Step", renderContractMarkdownBody(contract.nextStep)),
|
|
437
|
+
renderContractSection("Blockers", renderContractList(contract.blockers, function (item) {
|
|
438
|
+
return renderMarkdownInline(item);
|
|
439
|
+
})),
|
|
440
|
+
],
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function renderHandoffContractCard(contract) {
|
|
445
|
+
if (!contract || !normalizeTextValue(contract.summary)) {
|
|
446
|
+
return "";
|
|
447
|
+
}
|
|
448
|
+
return renderContractCard({
|
|
449
|
+
tone: "handoff",
|
|
450
|
+
kicker: "Structured Handoff Contract",
|
|
451
|
+
title: contract.summary,
|
|
452
|
+
metaHtml: renderContractMetaRows([
|
|
453
|
+
{ label: "Target Role", value: contract.targetRole || "—" },
|
|
454
|
+
{ label: "Artifacts", value: String((contract.artifacts || []).length) },
|
|
455
|
+
]),
|
|
456
|
+
sections: [
|
|
457
|
+
renderContractSection("Reason", renderContractMarkdownBody(contract.reason)),
|
|
458
|
+
renderContractSection("Expected Next Step", renderContractMarkdownBody(contract.expectedNextStep)),
|
|
459
|
+
],
|
|
460
|
+
footerHtml: renderContractChips(contract.artifacts, "contract-chip-row contract-reference-row"),
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function renderTeamMessageContractCard(contract) {
|
|
465
|
+
if (!contract || !normalizeTextValue(contract.summary)) {
|
|
466
|
+
return "";
|
|
467
|
+
}
|
|
468
|
+
return renderContractCard({
|
|
469
|
+
tone: contract.intent || "update",
|
|
470
|
+
kicker: "Structured Message Contract",
|
|
471
|
+
title: contract.summary,
|
|
472
|
+
metaHtml: renderContractMetaRows([
|
|
473
|
+
{ label: "Intent", value: humanizeStatus(contract.intent || "update") },
|
|
474
|
+
{ label: "Needs Response", value: contract.needsResponse ? "Yes" : "No" },
|
|
475
|
+
{ label: "Requested Role", value: contract.requestedRole || "—" },
|
|
476
|
+
]),
|
|
477
|
+
sections: [
|
|
478
|
+
renderContractSection("Details", renderContractMarkdownBody(contract.details)),
|
|
479
|
+
renderContractSection("Requested Action", renderContractMarkdownBody(contract.requestedAction)),
|
|
480
|
+
],
|
|
481
|
+
footerHtml: renderContractChips(contract.references, "contract-chip-row contract-reference-row"),
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function renderControllerManifestCard(manifest) {
|
|
486
|
+
if (!manifest || !normalizeTextValue(manifest.requirementSummary)) {
|
|
487
|
+
return "";
|
|
488
|
+
}
|
|
489
|
+
const createdTasks = Array.isArray(manifest.createdTasks) ? manifest.createdTasks : [];
|
|
490
|
+
const deferredTasks = Array.isArray(manifest.deferredTasks) ? manifest.deferredTasks : [];
|
|
491
|
+
return renderContractCard({
|
|
492
|
+
tone: "manifest",
|
|
493
|
+
kicker: "Structured Manifest",
|
|
494
|
+
title: manifest.requirementSummary,
|
|
495
|
+
metaHtml: renderContractMetaRows([
|
|
496
|
+
{ label: "Required Roles", value: String((manifest.requiredRoles || []).length) },
|
|
497
|
+
{ label: "Created Tasks", value: String(createdTasks.length) },
|
|
498
|
+
{ label: "Deferred Tasks", value: String(deferredTasks.length) },
|
|
499
|
+
]),
|
|
500
|
+
sections: [
|
|
501
|
+
renderContractSection("Required Roles", renderContractChips(manifest.requiredRoles, "contract-chip-row contract-role-row")),
|
|
502
|
+
renderContractSection("Created Tasks", renderContractList(createdTasks, function (item) {
|
|
503
|
+
const roleLabel = item.assignedRole ? " (" + escapeHtml(item.assignedRole) + ")" : "";
|
|
504
|
+
return '<strong>' + escapeHtml(item.title || "Task") + roleLabel + "</strong>: " + renderMarkdownInline(item.expectedOutcome || "");
|
|
505
|
+
})),
|
|
506
|
+
renderContractSection("Deferred Tasks", renderContractList(deferredTasks, function (item) {
|
|
507
|
+
const roleLabel = item.assignedRole ? " (" + escapeHtml(item.assignedRole) + ")" : "";
|
|
508
|
+
return '<strong>' + escapeHtml(item.title || "Task") + roleLabel + "</strong>: " + renderMarkdownInline(item.blockedBy || "") + " — create when " + renderMarkdownInline(item.whenReady || "");
|
|
509
|
+
})),
|
|
510
|
+
renderContractSection("Clarifications", renderContractList(manifest.clarificationQuestions, function (item) {
|
|
511
|
+
return renderMarkdownInline(item);
|
|
512
|
+
})),
|
|
513
|
+
renderContractSection("Handoff Plan", renderContractMarkdownBody(manifest.handoffPlan)),
|
|
514
|
+
renderContractSection("Notes", renderContractMarkdownBody(manifest.notes)),
|
|
515
|
+
],
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
function buildMessageDisplayContent(message) {
|
|
520
|
+
const content = normalizeTextValue(message && message.content);
|
|
521
|
+
const contract = message && message.contract ? message.contract : null;
|
|
522
|
+
if (!contract || !normalizeTextValue(contract.summary)) {
|
|
523
|
+
return renderMarkdownContent(content);
|
|
524
|
+
}
|
|
525
|
+
const detailContent = normalizeTextValue(contract.details || "");
|
|
526
|
+
if (!content || content === normalizeTextValue(contract.summary) || content === detailContent) {
|
|
527
|
+
return "";
|
|
528
|
+
}
|
|
529
|
+
return renderMarkdownContent(message.content || "");
|
|
530
|
+
}
|
|
531
|
+
|
|
295
532
|
function findWorkspaceNodeByPath(nodes, relativePath) {
|
|
296
533
|
for (let index = 0; index < nodes.length; index += 1) {
|
|
297
534
|
const node = nodes[index];
|
|
@@ -735,6 +972,13 @@
|
|
|
735
972
|
const creatorBadge = task.createdBy
|
|
736
973
|
? '<span class="task-origin-badge">' + escapeHtml(task.createdBy) + "</span>"
|
|
737
974
|
: "";
|
|
975
|
+
const contractSummary = task.resultContract
|
|
976
|
+
? '<div class="task-contract-summary"><strong>Result:</strong> ' + escapeHtml(task.resultContract.summary || "") + "</div>"
|
|
977
|
+
: task.lastHandoff
|
|
978
|
+
? '<div class="task-contract-summary"><strong>Handoff:</strong> ' + escapeHtml(task.lastHandoff.summary || "") + "</div>"
|
|
979
|
+
: task.progressContract
|
|
980
|
+
? '<div class="task-contract-summary"><strong>Progress:</strong> ' + escapeHtml(task.progressContract.summary || "") + "</div>"
|
|
981
|
+
: "";
|
|
738
982
|
const note = task.progress
|
|
739
983
|
? '<div class="task-note">' + escapeHtml(task.progress).slice(0, 220) + "</div>"
|
|
740
984
|
: "";
|
|
@@ -750,6 +994,7 @@
|
|
|
750
994
|
' <div class="task-title-row"><div class="task-title">' + escapeHtml(task.title) + "</div>" + creatorBadge + "</div>" +
|
|
751
995
|
(task.description ? '<div class="task-desc">' + escapeHtml(task.description).slice(0, 220) + "</div>" : "") +
|
|
752
996
|
renderSkillPills(recommendedSkills, "skill-pills task-skill-pills") +
|
|
997
|
+
contractSummary +
|
|
753
998
|
note +
|
|
754
999
|
' <div class="task-meta">' +
|
|
755
1000
|
' <span class="task-status-badge ' + escapeHtml(status) + '">' + escapeHtml(humanizeStatus(status)) + "</span>" +
|
|
@@ -790,6 +1035,9 @@
|
|
|
790
1035
|
return '<button type="button" class="controller-run-task-link" data-open-task-id="' + escapeHtml(taskId) + '">' + escapeHtml(taskId) + "</button>";
|
|
791
1036
|
}).join("") + "</div>"
|
|
792
1037
|
: "";
|
|
1038
|
+
const manifestBlock = run.manifest
|
|
1039
|
+
? '<div class="controller-run-section"><div class="controller-run-section-title">Manifest</div>' + renderControllerManifestCard(run.manifest) + "</div>"
|
|
1040
|
+
: "";
|
|
793
1041
|
const replyBlock = run.reply
|
|
794
1042
|
? '<div class="controller-run-section"><div class="controller-run-section-title">Reply</div><div class="markdown-body">' + renderMarkdownContent(run.reply) + "</div></div>"
|
|
795
1043
|
: "";
|
|
@@ -822,6 +1070,7 @@
|
|
|
822
1070
|
' <span class="controller-run-status ' + escapeHtml(status) + '">' + escapeHtml(humanizeStatus(status)) + "</span>" +
|
|
823
1071
|
" </div>" +
|
|
824
1072
|
' <div class="controller-run-section"><div class="controller-run-section-title">Request</div><div class="markdown-body">' + renderMarkdownContent(run.request || "") + "</div></div>" +
|
|
1073
|
+
manifestBlock +
|
|
825
1074
|
replyBlock +
|
|
826
1075
|
errorBlock +
|
|
827
1076
|
(createdTaskButtons
|
|
@@ -978,14 +1227,44 @@
|
|
|
978
1227
|
(task.progress
|
|
979
1228
|
? '<div class="task-detail-section"><h3>Latest Progress</h3>' + renderMarkdownCard(task.progress) + "</div>"
|
|
980
1229
|
: "") +
|
|
1230
|
+
(task.progressContract
|
|
1231
|
+
? '<div class="task-detail-section"><h3>Structured Progress</h3>' + renderProgressContractCard(task.progressContract) + "</div>"
|
|
1232
|
+
: "") +
|
|
981
1233
|
(task.result
|
|
982
1234
|
? '<div class="task-detail-section"><h3>Result</h3>' + renderMarkdownCard(task.result) + "</div>"
|
|
983
1235
|
: "") +
|
|
1236
|
+
(task.resultContract
|
|
1237
|
+
? '<div class="task-detail-section"><h3>Structured Result</h3>' + renderResultContractCard(task.resultContract) + "</div>"
|
|
1238
|
+
: "") +
|
|
1239
|
+
(task.lastHandoff
|
|
1240
|
+
? '<div class="task-detail-section"><h3>Last Handoff</h3>' + renderHandoffContractCard(task.lastHandoff) + "</div>"
|
|
1241
|
+
: "") +
|
|
984
1242
|
(task.error
|
|
985
1243
|
? '<div class="task-detail-section"><h3>Error</h3>' + renderMarkdownCard(task.error) + "</div>"
|
|
986
1244
|
: "");
|
|
987
1245
|
}
|
|
988
1246
|
|
|
1247
|
+
function buildTimelineMessageBody(message) {
|
|
1248
|
+
const contractBlock = renderTeamMessageContractCard(message && message.contract);
|
|
1249
|
+
const rawContent = buildMessageDisplayContent(message);
|
|
1250
|
+
return (contractBlock || "") + (rawContent ? '<div class="timeline-raw-markdown markdown-body">' + rawContent + "</div>" : "");
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
function buildTimelineClarificationBody(item) {
|
|
1254
|
+
const answerBlock = item && item.answer
|
|
1255
|
+
? '<div class="timeline-contract-note"><strong>Answer:</strong> ' + renderMarkdownInline(item.answer) + "</div>"
|
|
1256
|
+
: "";
|
|
1257
|
+
const contextBlock = item && item.context
|
|
1258
|
+
? '<div class="timeline-contract-note"><strong>Context:</strong> ' + renderMarkdownInline(item.context) + "</div>"
|
|
1259
|
+
: "";
|
|
1260
|
+
return (
|
|
1261
|
+
'<div class="timeline-contract-note"><strong>Question:</strong> ' + renderMarkdownInline(item.question || "") + "</div>" +
|
|
1262
|
+
'<div class="timeline-contract-note"><strong>Blocking Reason:</strong> ' + renderMarkdownInline(item.blockingReason || "") + "</div>" +
|
|
1263
|
+
contextBlock +
|
|
1264
|
+
answerBlock
|
|
1265
|
+
);
|
|
1266
|
+
}
|
|
1267
|
+
|
|
989
1268
|
function buildTimelineEntries(task) {
|
|
990
1269
|
if (!task || !selectedTaskDetail) {
|
|
991
1270
|
return [];
|
|
@@ -997,7 +1276,7 @@
|
|
|
997
1276
|
createdAt: event.createdAt || 0,
|
|
998
1277
|
label: humanizeStatus(event.phase || event.type),
|
|
999
1278
|
meta: [event.source || "execution", event.workerId || event.role || event.stream].filter(Boolean).join(" • "),
|
|
1000
|
-
|
|
1279
|
+
bodyHtml: renderMarkdownContent(event.message || ""),
|
|
1001
1280
|
};
|
|
1002
1281
|
});
|
|
1003
1282
|
|
|
@@ -1005,13 +1284,30 @@
|
|
|
1005
1284
|
return {
|
|
1006
1285
|
kind: "message",
|
|
1007
1286
|
createdAt: message.createdAt || 0,
|
|
1008
|
-
label: humanizeStatus(message.type || "message"),
|
|
1009
|
-
meta: [
|
|
1010
|
-
|
|
1287
|
+
label: humanizeStatus((message.contract && message.contract.intent) || message.type || "message"),
|
|
1288
|
+
meta: [
|
|
1289
|
+
message.fromRole || message.from || "unknown",
|
|
1290
|
+
message.toRole ? ("to " + message.toRole) : null,
|
|
1291
|
+
message.contract && message.contract.needsResponse ? "response expected" : null,
|
|
1292
|
+
].filter(Boolean).join(" • "),
|
|
1293
|
+
bodyHtml: buildTimelineMessageBody(message),
|
|
1294
|
+
};
|
|
1295
|
+
});
|
|
1296
|
+
|
|
1297
|
+
const clarifications = (selectedTaskDetail.clarifications || []).map(function (item) {
|
|
1298
|
+
return {
|
|
1299
|
+
kind: "clarification",
|
|
1300
|
+
createdAt: item.updatedAt || item.createdAt || 0,
|
|
1301
|
+
label: item.status === "answered" ? "clarification answered" : "clarification requested",
|
|
1302
|
+
meta: [
|
|
1303
|
+
item.requestedByRole || "unknown role",
|
|
1304
|
+
item.requestedByWorkerId || item.requestedBy || null,
|
|
1305
|
+
].filter(Boolean).join(" • "),
|
|
1306
|
+
bodyHtml: buildTimelineClarificationBody(item),
|
|
1011
1307
|
};
|
|
1012
1308
|
});
|
|
1013
1309
|
|
|
1014
|
-
return executionEvents.concat(messages).sort(function (left, right) {
|
|
1310
|
+
return executionEvents.concat(messages).concat(clarifications).sort(function (left, right) {
|
|
1015
1311
|
return (left.createdAt || 0) - (right.createdAt || 0);
|
|
1016
1312
|
});
|
|
1017
1313
|
}
|
|
@@ -1040,7 +1336,7 @@
|
|
|
1040
1336
|
' <div class="timeline-entry-meta">' + escapeHtml(formatTime(entry.createdAt)) + "</div>" +
|
|
1041
1337
|
" </div>" +
|
|
1042
1338
|
(entry.meta ? '<div class="timeline-entry-meta">' + escapeHtml(entry.meta) + "</div>" : "") +
|
|
1043
|
-
' <div class="timeline-entry-body markdown-body">' + renderMarkdownContent(entry.body) + "</div>" +
|
|
1339
|
+
' <div class="timeline-entry-body markdown-body">' + (entry.bodyHtml || renderMarkdownContent(entry.body || "")) + "</div>" +
|
|
1044
1340
|
"</article>"
|
|
1045
1341
|
);
|
|
1046
1342
|
}).join("") +
|
|
@@ -1222,7 +1518,14 @@
|
|
|
1222
1518
|
|
|
1223
1519
|
container.innerHTML = recent.map(function (message) {
|
|
1224
1520
|
const from = message.fromRole || message.from || "unknown";
|
|
1225
|
-
const type = message.type || "direct";
|
|
1521
|
+
const type = (message.contract && message.contract.intent) || message.type || "direct";
|
|
1522
|
+
const contractBlock = renderTeamMessageContractCard(message.contract);
|
|
1523
|
+
const rawContent = buildMessageDisplayContent(message);
|
|
1524
|
+
const meta = [
|
|
1525
|
+
message.toRole ? ("to " + message.toRole) : null,
|
|
1526
|
+
message.taskId ? ("task " + message.taskId) : null,
|
|
1527
|
+
formatTime(message.createdAt),
|
|
1528
|
+
].filter(Boolean).join(" • ");
|
|
1226
1529
|
|
|
1227
1530
|
return (
|
|
1228
1531
|
'<div class="message-card">' +
|
|
@@ -1230,7 +1533,9 @@
|
|
|
1230
1533
|
' <span class="message-from">' + escapeHtml(from) + "</span>" +
|
|
1231
1534
|
' <span class="message-type ' + escapeHtml(type) + '">' + escapeHtml(humanizeStatus(type)) + "</span>" +
|
|
1232
1535
|
" </div>" +
|
|
1233
|
-
'
|
|
1536
|
+
(meta ? '<div class="message-meta">' + escapeHtml(meta) + "</div>" : "") +
|
|
1537
|
+
contractBlock +
|
|
1538
|
+
(rawContent ? '<div class="message-content markdown-body">' + rawContent + "</div>" : "") +
|
|
1234
1539
|
"</div>"
|
|
1235
1540
|
);
|
|
1236
1541
|
}).join("");
|