@yeaft/webchat-agent 1.0.565 → 1.0.567
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/local-runtime/version.json +1 -1
- package/local-runtime/web/app.bundle.js +18 -17
- package/local-runtime/web/app.bundle.js.gz +0 -0
- package/local-runtime/web/index.html +2 -2
- package/local-runtime/web/style.bundle.css +1 -1
- package/local-runtime/web/style.bundle.css.gz +0 -0
- package/package.json +1 -1
- package/yeaft/work-center/bridge.js +1 -1
- package/yeaft/work-center/coordinator.js +14 -3
- package/yeaft/work-center/durable-model.js +8 -1
- package/yeaft/work-center/projection.js +1 -0
- package/yeaft/work-center/service.js +9 -0
- package/yeaft/work-center/store.js +18 -2
|
Binary file
|
package/package.json
CHANGED
|
@@ -28,7 +28,7 @@ const BROWSER_ACTION_DEBUG_OPS = new Set(['get_action_messages', 'get_action_req
|
|
|
28
28
|
// client-supplied value and only emits files resolved from owned upload ids.
|
|
29
29
|
const BROWSER_FILE_FIELDS = Object.freeze({
|
|
30
30
|
create: [
|
|
31
|
-
'title', 'goal', 'acceptanceCriteria', 'workItemType', 'workDir', 'deliveryTarget',
|
|
31
|
+
'title', 'titleSource', 'goal', 'acceptanceCriteria', 'workItemType', 'workDir', 'deliveryTarget', 'deliveryInstructions',
|
|
32
32
|
'reuseMemory', 'files', 'start',
|
|
33
33
|
],
|
|
34
34
|
post_work_item_message: [
|
|
@@ -243,7 +243,7 @@ Return exactly one JSON object and no surrounding prose:
|
|
|
243
243
|
}
|
|
244
244
|
|
|
245
245
|
Rules:
|
|
246
|
-
- When workItem.titleSource is coordinator_pending, include a concise title (prefer 6–12 words or a short Chinese phrase; at most
|
|
246
|
+
- When workItem.titleSource is coordinator_pending, include a concise title (prefer 6–12 words or a short Chinese phrase; at most 80 characters) in decision.title. This display label summarizes the original goal; it is not a contractPatch and must not rewrite or shorten the goal. Otherwise leave decision.title null. A missing or oversized display title is normalized by the runtime and must not change the substantive decision.
|
|
247
247
|
- answer: explain state only. Never use it for an automatic advance trigger.
|
|
248
248
|
- Never mutate goal, acceptanceCriteria, or deliveryTarget during automatic advance/recovery. decision.title is the only automatic title-generation path and is allowed only while titleSource is coordinator_pending; contractPatch (including a user-specified title) is allowed only for explicit user-originated refinement, never to make existing evidence pass. For an older WorkItem with no acceptance criteria, request_human to establish its completion condition before commissioning new work.
|
|
249
249
|
- create_actions: create 1..8 currently runnable Actions. Every Action needs type, objective, approach, expectedOutcome, capability, candidateVpIds, assignmentReason, sourceActionIds, workspaceMode, and optional maxAttempts/separateFromActionTypes. sourceActionIds are context/audit references, never scheduling dependencies. Do not include dependsOnActionIds, dependsOnStageIds, stages, or a graph.
|
|
@@ -292,11 +292,21 @@ function cleanText(value, limit, name) {
|
|
|
292
292
|
return text;
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
+
function conciseDisplayTitle(value) {
|
|
296
|
+
const text = String(value || '').trim().replace(/\s+/g, ' ');
|
|
297
|
+
if (!text) return '';
|
|
298
|
+
const words = text.split(' ');
|
|
299
|
+
const concise = words.length > 12 ? `${words.slice(0, 12).join(' ')}…` : text;
|
|
300
|
+
const characters = [...concise];
|
|
301
|
+
return characters.length > 80 ? `${characters.slice(0, 79).join('')}…` : concise;
|
|
302
|
+
}
|
|
303
|
+
|
|
295
304
|
function coordinatorDisplayTitle(value, detail) {
|
|
296
305
|
if (detail.titleSource !== 'coordinator_pending') return null;
|
|
297
306
|
const proposed = typeof value === 'string' ? value.trim() : '';
|
|
298
|
-
|
|
299
|
-
|
|
307
|
+
return conciseDisplayTitle(proposed)
|
|
308
|
+
|| conciseDisplayTitle(detail.goal || detail.title)
|
|
309
|
+
|| 'Work Item';
|
|
300
310
|
}
|
|
301
311
|
|
|
302
312
|
function requiresDeliveryBoundaryDecision(detail, actions) {
|
|
@@ -634,6 +644,7 @@ export function coordinatorSnapshot(detail) {
|
|
|
634
644
|
titleSource: detail.titleSource || 'explicit',
|
|
635
645
|
goal: truncateUtf8(detail.goal, 4 * 1024),
|
|
636
646
|
deliveryTarget: detail.deliveryTarget || null,
|
|
647
|
+
deliveryInstructions: truncateUtf8(detail.deliveryInstructions || '', 500) || null,
|
|
637
648
|
acceptanceCriteria,
|
|
638
649
|
workItemType: truncateUtf8(detail.workflowSnapshot?.workItemType, 256) || null,
|
|
639
650
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash, randomUUID } from 'node:crypto';
|
|
2
2
|
|
|
3
|
-
export const WORK_CENTER_SCHEMA_VERSION =
|
|
3
|
+
export const WORK_CENTER_SCHEMA_VERSION = 41;
|
|
4
4
|
|
|
5
5
|
const MIGRATIONS = [
|
|
6
6
|
['23-conversation-stream', migrateConversationStream],
|
|
@@ -21,6 +21,7 @@ const MIGRATIONS = [
|
|
|
21
21
|
['38-action-closure-and-outputs', migrateActionClosureAndOutputs],
|
|
22
22
|
['39-action-creation-source', migrateActionCreationSource],
|
|
23
23
|
['40-work-item-schedules', migrateWorkItemSchedules],
|
|
24
|
+
['41-delivery-instructions', migrateDeliveryInstructions],
|
|
24
25
|
];
|
|
25
26
|
|
|
26
27
|
const MIGRATION_ALIASES = new Map([
|
|
@@ -582,6 +583,12 @@ function migrateWorkItemSchedules(db) {
|
|
|
582
583
|
WHERE schedule_status = 'scheduled'`);
|
|
583
584
|
}
|
|
584
585
|
|
|
586
|
+
function migrateDeliveryInstructions(db) {
|
|
587
|
+
if (!hasColumn(db, 'work_items', 'delivery_instructions')) {
|
|
588
|
+
db.exec('ALTER TABLE work_items ADD COLUMN delivery_instructions TEXT');
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
585
592
|
function migrateActionCreationSource(db) {
|
|
586
593
|
if (!hasColumn(db, 'actions', 'creation_source')) {
|
|
587
594
|
db.exec("ALTER TABLE actions ADD COLUMN creation_source TEXT NOT NULL DEFAULT 'legacy'");
|
|
@@ -1097,6 +1097,7 @@ export function projectWorkItemDetail(detail, options = {}) {
|
|
|
1097
1097
|
schedule: detail.schedule || null,
|
|
1098
1098
|
deliveryTarget: ['response', 'workspace_files', 'pull_request', 'merge'].includes(detail.deliveryTarget)
|
|
1099
1099
|
? detail.deliveryTarget : null,
|
|
1100
|
+
deliveryInstructions: truncateUtf8(detail.deliveryInstructions || '', 2 * 1024),
|
|
1100
1101
|
waitingReason: sanitizeDiagnosticText(waitingReason(detail), MAX_ACTION_DIAGNOSTIC_CHARS),
|
|
1101
1102
|
failureReason: workItemFailureReason(detail),
|
|
1102
1103
|
|
|
@@ -35,6 +35,11 @@ function requiredString(value, name) {
|
|
|
35
35
|
return value.trim();
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
function optionalString(value, limit) {
|
|
39
|
+
if (typeof value !== 'string') return '';
|
|
40
|
+
return value.trim().slice(0, limit);
|
|
41
|
+
}
|
|
42
|
+
|
|
38
43
|
function requiredWorkDir(value) {
|
|
39
44
|
const workDir = requiredString(value, 'workDir');
|
|
40
45
|
let canonical;
|
|
@@ -164,6 +169,8 @@ export class WorkCenterService {
|
|
|
164
169
|
watcher: this.watcher.status(),
|
|
165
170
|
};
|
|
166
171
|
}
|
|
172
|
+
case 'list_delivery_instructions':
|
|
173
|
+
return { values: this.store.listRecentDeliveryInstructions(payload.limit) };
|
|
167
174
|
case 'get':
|
|
168
175
|
return this.#requiredItem(payload.id);
|
|
169
176
|
case 'get_action_messages': {
|
|
@@ -280,6 +287,8 @@ export class WorkCenterService {
|
|
|
280
287
|
deliveryTarget: requestContext.userOriginated === true
|
|
281
288
|
&& ['response', 'workspace_files', 'pull_request', 'merge'].includes(payload.deliveryTarget)
|
|
282
289
|
? payload.deliveryTarget : null,
|
|
290
|
+
deliveryInstructions: requestContext.userOriginated === true
|
|
291
|
+
? optionalString(payload.deliveryInstructions, 500) : '',
|
|
283
292
|
reuseMemory: payload.reuseMemory !== false,
|
|
284
293
|
origin: payload.origin && typeof payload.origin === 'object'
|
|
285
294
|
? {
|
|
@@ -112,6 +112,7 @@ function mapWorkItem(row) {
|
|
|
112
112
|
coordinationMode: row.coordination_mode || 'legacy',
|
|
113
113
|
finalResult: parseJson(row.final_result, null),
|
|
114
114
|
deliveryTarget: row.delivery_target || null,
|
|
115
|
+
deliveryInstructions: row.delivery_instructions || '',
|
|
115
116
|
schedule: row.schedule_status ? {
|
|
116
117
|
status: row.schedule_status,
|
|
117
118
|
scheduledFor: Number(row.scheduled_for) || null,
|
|
@@ -863,6 +864,7 @@ export class WorkItemStore {
|
|
|
863
864
|
coordination_mode TEXT NOT NULL DEFAULT 'legacy',
|
|
864
865
|
final_result TEXT,
|
|
865
866
|
delivery_target TEXT,
|
|
867
|
+
delivery_instructions TEXT,
|
|
866
868
|
schedule_status TEXT,
|
|
867
869
|
scheduled_for INTEGER,
|
|
868
870
|
schedule_triggered_at INTEGER,
|
|
@@ -1161,6 +1163,9 @@ export class WorkItemStore {
|
|
|
1161
1163
|
if (!hasColumn(this.db, 'work_items', 'delivery_target')) {
|
|
1162
1164
|
this.db.exec('ALTER TABLE work_items ADD COLUMN delivery_target TEXT');
|
|
1163
1165
|
}
|
|
1166
|
+
if (!hasColumn(this.db, 'work_items', 'delivery_instructions')) {
|
|
1167
|
+
this.db.exec('ALTER TABLE work_items ADD COLUMN delivery_instructions TEXT');
|
|
1168
|
+
}
|
|
1164
1169
|
if (!hasColumn(this.db, 'work_items', 'title_source')) {
|
|
1165
1170
|
// Old titles were explicit under the previous creation contract.
|
|
1166
1171
|
this.db.exec("ALTER TABLE work_items ADD COLUMN title_source TEXT NOT NULL DEFAULT 'explicit'");
|
|
@@ -2424,15 +2429,16 @@ export class WorkItemStore {
|
|
|
2424
2429
|
const id = input.id || randomUUID();
|
|
2425
2430
|
const workspaceKey = canonicalWorkspaceKey(input.workDir);
|
|
2426
2431
|
this.db.prepare(`INSERT INTO work_items
|
|
2427
|
-
(id, revision, execution_schema_version, ledger_revision, coordination_mode, final_result, delivery_target,
|
|
2432
|
+
(id, revision, execution_schema_version, ledger_revision, coordination_mode, final_result, delivery_target, delivery_instructions,
|
|
2428
2433
|
schedule_status, scheduled_for, schedule_triggered_at, title, title_source, requirement, goal, acceptance_criteria, workflow_template, workflow_snapshot, status,
|
|
2429
2434
|
current_action_id, current_run_id, work_dir, workspace_key, reuse_memory, origin, linked_session_ids,
|
|
2430
2435
|
session_context, attachments, created_at, updated_at)
|
|
2431
|
-
VALUES (?, 1, ?, 0, ?, NULL, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, NULL, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(
|
|
2436
|
+
VALUES (?, 1, ?, 0, ?, NULL, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, NULL, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(
|
|
2432
2437
|
id,
|
|
2433
2438
|
Number.isInteger(input.executionSchemaVersion) ? input.executionSchemaVersion : 2,
|
|
2434
2439
|
input.coordinationMode || 'legacy',
|
|
2435
2440
|
input.deliveryTarget || null,
|
|
2441
|
+
input.deliveryInstructions || null,
|
|
2436
2442
|
input.schedule?.status || null,
|
|
2437
2443
|
input.schedule?.scheduledFor || null,
|
|
2438
2444
|
input.title,
|
|
@@ -2463,6 +2469,16 @@ export class WorkItemStore {
|
|
|
2463
2469
|
});
|
|
2464
2470
|
}
|
|
2465
2471
|
|
|
2472
|
+
listRecentDeliveryInstructions(limit = 12) {
|
|
2473
|
+
const boundedLimit = Math.min(Math.max(Number(limit) || 12, 1), 24);
|
|
2474
|
+
return this.db.prepare(`SELECT delivery_instructions AS value, MAX(created_at) AS last_used_at
|
|
2475
|
+
FROM work_items
|
|
2476
|
+
WHERE delivery_instructions IS NOT NULL AND trim(delivery_instructions) != ''
|
|
2477
|
+
GROUP BY delivery_instructions
|
|
2478
|
+
ORDER BY last_used_at DESC, value ASC
|
|
2479
|
+
LIMIT ?`).all(boundedLimit).map(row => row.value);
|
|
2480
|
+
}
|
|
2481
|
+
|
|
2466
2482
|
#insertAction(workItemId, input, sequence, now = this.now(), options = {}) {
|
|
2467
2483
|
const workItem = this.getWorkItem(workItemId);
|
|
2468
2484
|
const stageId = input.stageId || input.type;
|