@yeaft/webchat-agent 1.0.217 → 1.0.219
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 +103 -90
- 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/controller.js +65 -3
- package/yeaft/work-center/plan-mutation.js +120 -0
- package/yeaft/work-center/projection.js +107 -20
- package/yeaft/work-center/runner.js +83 -9
- package/yeaft/work-center/service.js +3 -6
- package/yeaft/work-center/store.js +136 -14
|
@@ -158,6 +158,7 @@ function mapAction(row) {
|
|
|
158
158
|
contractRevision: row.contract_revision,
|
|
159
159
|
generation: Math.max(1, Number(row.generation) || 1),
|
|
160
160
|
specHash: row.spec_hash || '',
|
|
161
|
+
identityHistory: parseJson(row.identity_history, []),
|
|
161
162
|
resultRunId: row.result_run_id || null,
|
|
162
163
|
status: row.status,
|
|
163
164
|
attempt: row.attempt,
|
|
@@ -170,6 +171,19 @@ function mapAction(row) {
|
|
|
170
171
|
};
|
|
171
172
|
}
|
|
172
173
|
|
|
174
|
+
function actionIdentityHistory(action, generation = action?.generation, specHash = action?.specHash) {
|
|
175
|
+
const byGeneration = new Map();
|
|
176
|
+
for (const identity of Array.isArray(action?.identityHistory) ? action.identityHistory : []) {
|
|
177
|
+
const value = Math.max(1, Number(identity?.generation) || 1);
|
|
178
|
+
if (typeof identity?.specHash === 'string' && identity.specHash) {
|
|
179
|
+
byGeneration.set(value, { generation: value, specHash: identity.specHash });
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const value = Math.max(1, Number(generation) || 1);
|
|
183
|
+
if (typeof specHash === 'string' && specHash) byGeneration.set(value, { generation: value, specHash });
|
|
184
|
+
return [...byGeneration.values()].sort((left, right) => left.generation - right.generation).slice(-100);
|
|
185
|
+
}
|
|
186
|
+
|
|
173
187
|
function mapRun(row) {
|
|
174
188
|
if (!row) return null;
|
|
175
189
|
return {
|
|
@@ -324,6 +338,7 @@ export class WorkItemStore {
|
|
|
324
338
|
contract_revision INTEGER NOT NULL DEFAULT 1,
|
|
325
339
|
generation INTEGER NOT NULL DEFAULT 1,
|
|
326
340
|
spec_hash TEXT NOT NULL DEFAULT '',
|
|
341
|
+
identity_history TEXT NOT NULL DEFAULT '[]',
|
|
327
342
|
result_run_id TEXT,
|
|
328
343
|
status TEXT NOT NULL,
|
|
329
344
|
attempt INTEGER NOT NULL DEFAULT 0,
|
|
@@ -549,6 +564,16 @@ export class WorkItemStore {
|
|
|
549
564
|
if (!hasColumn(this.db, 'actions', 'spec_hash')) {
|
|
550
565
|
this.db.exec("ALTER TABLE actions ADD COLUMN spec_hash TEXT NOT NULL DEFAULT ''");
|
|
551
566
|
}
|
|
567
|
+
if (!hasColumn(this.db, 'actions', 'identity_history')) {
|
|
568
|
+
this.db.exec("ALTER TABLE actions ADD COLUMN identity_history TEXT NOT NULL DEFAULT '[]'");
|
|
569
|
+
const seedIdentity = this.db.prepare('UPDATE actions SET identity_history = ? WHERE id = ?');
|
|
570
|
+
for (const row of this.db.prepare('SELECT id, generation, spec_hash FROM actions').all()) {
|
|
571
|
+
seedIdentity.run(stringify(actionIdentityHistory({
|
|
572
|
+
generation: row.generation,
|
|
573
|
+
specHash: row.spec_hash,
|
|
574
|
+
})), row.id);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
552
577
|
if (!hasColumn(this.db, 'actions', 'result_run_id')) {
|
|
553
578
|
this.db.exec('ALTER TABLE actions ADD COLUMN result_run_id TEXT');
|
|
554
579
|
}
|
|
@@ -838,12 +863,13 @@ export class WorkItemStore {
|
|
|
838
863
|
updatedAt: now,
|
|
839
864
|
};
|
|
840
865
|
action.specHash = actionSpecHash(action);
|
|
866
|
+
action.identityHistory = actionIdentityHistory(action);
|
|
841
867
|
this.db.prepare(`INSERT INTO actions
|
|
842
868
|
(id, work_item_id, sequence, type, required_role, stage_id, assignment_policy, model_policy,
|
|
843
869
|
depends_on_stage_ids, workspace_mode, changes_requested_stage_id, workspace, instruction, brief, context, contract_revision,
|
|
844
|
-
generation, spec_hash, result_run_id, status, attempt, max_attempts, current_run_id, lease_epoch,
|
|
870
|
+
generation, spec_hash, identity_history, result_run_id, status, attempt, max_attempts, current_run_id, lease_epoch,
|
|
845
871
|
replaces_action_id, created_at, updated_at)
|
|
846
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, 0, ?, ?, ?)`).run(
|
|
872
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, 0, ?, ?, ?)`).run(
|
|
847
873
|
action.id,
|
|
848
874
|
workItemId,
|
|
849
875
|
action.sequence,
|
|
@@ -862,6 +888,7 @@ export class WorkItemStore {
|
|
|
862
888
|
action.contractRevision,
|
|
863
889
|
action.generation,
|
|
864
890
|
action.specHash,
|
|
891
|
+
stringify(action.identityHistory),
|
|
865
892
|
action.resultRunId,
|
|
866
893
|
action.status,
|
|
867
894
|
action.attempt,
|
|
@@ -926,10 +953,13 @@ export class WorkItemStore {
|
|
|
926
953
|
const nextAction = action.id === target.id && replacement
|
|
927
954
|
? { ...action, ...replacement, generation: action.generation + 1 }
|
|
928
955
|
: { ...action, generation: action.generation + 1 };
|
|
956
|
+
const nextSpecHash = actionSpecHash(nextAction);
|
|
929
957
|
this.db.prepare(`UPDATE actions SET status = 'ready', attempt = 0, current_run_id = NULL,
|
|
930
|
-
lease_epoch = ?, generation = generation + 1, spec_hash = ?, result_run_id = NULL,
|
|
958
|
+
lease_epoch = ?, generation = generation + 1, spec_hash = ?, identity_history = ?, result_run_id = NULL,
|
|
931
959
|
workspace = ?, updated_at = ? WHERE id = ?`).run(
|
|
932
|
-
nextEpoch.get(action.id),
|
|
960
|
+
nextEpoch.get(action.id), nextSpecHash,
|
|
961
|
+
stringify(actionIdentityHistory(action, nextAction.generation, nextSpecHash)),
|
|
962
|
+
stringify(workspace), now, action.id,
|
|
933
963
|
);
|
|
934
964
|
}
|
|
935
965
|
}
|
|
@@ -976,13 +1006,18 @@ export class WorkItemStore {
|
|
|
976
1006
|
const nextWorkspaceMode = workspaceMode || action.workspaceMode;
|
|
977
1007
|
const specChanged = nextWorkspaceMode !== action.workspaceMode;
|
|
978
1008
|
const nextAction = { ...action, workspaceMode: nextWorkspaceMode };
|
|
1009
|
+
const nextSpecHash = specChanged ? actionSpecHash(nextAction) : action.specHash;
|
|
979
1010
|
const changed = this.db.prepare(`UPDATE actions SET workspace = ?, workspace_mode = ?,
|
|
980
|
-
generation = generation + ?, spec_hash = ?,
|
|
1011
|
+
generation = generation + ?, spec_hash = ?, identity_history = ?,
|
|
1012
|
+
result_run_id = CASE WHEN ? = 1 THEN NULL ELSE result_run_id END,
|
|
981
1013
|
updated_at = ? WHERE id = ? AND generation = ?`).run(
|
|
982
1014
|
stringify(workspace),
|
|
983
1015
|
nextWorkspaceMode,
|
|
984
1016
|
specChanged ? 1 : 0,
|
|
985
|
-
|
|
1017
|
+
nextSpecHash,
|
|
1018
|
+
stringify(specChanged
|
|
1019
|
+
? actionIdentityHistory(action, action.generation + 1, nextSpecHash)
|
|
1020
|
+
: action.identityHistory),
|
|
986
1021
|
specChanged ? 1 : 0,
|
|
987
1022
|
this.now(),
|
|
988
1023
|
actionId,
|
|
@@ -1027,13 +1062,17 @@ export class WorkItemStore {
|
|
|
1027
1062
|
}
|
|
1028
1063
|
}
|
|
1029
1064
|
const changed = this.db.prepare(`UPDATE actions SET workspace = ?, workspace_mode = ?,
|
|
1030
|
-
generation = generation + ?, spec_hash = ?,
|
|
1065
|
+
generation = generation + ?, spec_hash = ?, identity_history = ?,
|
|
1066
|
+
result_run_id = CASE WHEN ? = 1 THEN NULL ELSE result_run_id END,
|
|
1031
1067
|
updated_at = ? WHERE id = ? AND status = 'running' AND current_run_id = ?
|
|
1032
1068
|
AND lease_epoch = ? AND generation = ?`).run(
|
|
1033
1069
|
stringify(workspace),
|
|
1034
1070
|
nextWorkspaceMode,
|
|
1035
1071
|
specChanged ? 1 : 0,
|
|
1036
1072
|
nextSpecHash,
|
|
1073
|
+
stringify(specChanged
|
|
1074
|
+
? actionIdentityHistory(action, nextGeneration, nextSpecHash)
|
|
1075
|
+
: action.identityHistory),
|
|
1037
1076
|
specChanged ? 1 : 0,
|
|
1038
1077
|
now,
|
|
1039
1078
|
actionId,
|
|
@@ -1067,11 +1106,13 @@ export class WorkItemStore {
|
|
|
1067
1106
|
for (const row of pendingRows) {
|
|
1068
1107
|
const pending = mapAction(row);
|
|
1069
1108
|
const fallback = { ...pending, workspaceMode: 'shared', workspace: null };
|
|
1109
|
+
const fallbackSpecHash = actionSpecHash(fallback);
|
|
1070
1110
|
const repaired = this.db.prepare(`UPDATE actions SET workspace = NULL, workspace_mode = 'shared',
|
|
1071
|
-
generation = generation + 1, spec_hash = ?, result_run_id = NULL, updated_at = ?
|
|
1111
|
+
generation = generation + 1, spec_hash = ?, identity_history = ?, result_run_id = NULL, updated_at = ?
|
|
1072
1112
|
WHERE id = ? AND status = 'ready' AND current_run_id IS NULL
|
|
1073
1113
|
AND generation = ? AND workspace_mode = ?`).run(
|
|
1074
|
-
|
|
1114
|
+
fallbackSpecHash,
|
|
1115
|
+
stringify(actionIdentityHistory(pending, pending.generation + 1, fallbackSpecHash)),
|
|
1075
1116
|
now,
|
|
1076
1117
|
pending.id,
|
|
1077
1118
|
pending.generation,
|
|
@@ -1406,12 +1447,18 @@ export class WorkItemStore {
|
|
|
1406
1447
|
for (const action of openActions) {
|
|
1407
1448
|
if (action.status === 'ready') {
|
|
1408
1449
|
const instruction = updateActionInstruction(updatedWorkItem, action);
|
|
1409
|
-
|
|
1410
|
-
|
|
1450
|
+
const nextGeneration = action.generation + 1;
|
|
1451
|
+
const nextSpecHash = actionSpecHash({ ...action, instruction, generation: nextGeneration });
|
|
1452
|
+
this.db.prepare(`UPDATE actions SET instruction = ?, generation = ?, spec_hash = ?,
|
|
1453
|
+
identity_history = ?, result_run_id = NULL, updated_at = ?
|
|
1454
|
+
WHERE id = ? AND status = 'ready' AND generation = ?`).run(
|
|
1411
1455
|
instruction,
|
|
1412
|
-
|
|
1456
|
+
nextGeneration,
|
|
1457
|
+
nextSpecHash,
|
|
1458
|
+
stringify(actionIdentityHistory(action, nextGeneration, nextSpecHash)),
|
|
1413
1459
|
now,
|
|
1414
1460
|
action.id,
|
|
1461
|
+
action.generation,
|
|
1415
1462
|
);
|
|
1416
1463
|
continue;
|
|
1417
1464
|
}
|
|
@@ -2094,6 +2141,15 @@ export class WorkItemStore {
|
|
|
2094
2141
|
throw new Error('Work Center terminal transition lost the current Action fence');
|
|
2095
2142
|
}
|
|
2096
2143
|
|
|
2144
|
+
if (transition.planConflict) {
|
|
2145
|
+
this.db.prepare(`INSERT INTO plan_conflicts
|
|
2146
|
+
(id, work_item_id, action_id, generation, kind, status, details, created_at, updated_at, resolved_at)
|
|
2147
|
+
VALUES (?, ?, ?, ?, ?, 'open', ?, ?, ?, NULL)`).run(
|
|
2148
|
+
randomUUID(), workItem.id, action.id, action.generation,
|
|
2149
|
+
transition.planConflict.kind || 'plan', stringify(transition.planConflict), now, now,
|
|
2150
|
+
);
|
|
2151
|
+
}
|
|
2152
|
+
|
|
2097
2153
|
let nextWorkItem = workItem;
|
|
2098
2154
|
if (transition.contractPatch) {
|
|
2099
2155
|
const patch = transition.contractPatch;
|
|
@@ -2175,10 +2231,68 @@ export class WorkItemStore {
|
|
|
2175
2231
|
nextWorkItem = this.getWorkItem(workItem.id);
|
|
2176
2232
|
nextAction = this.#insertAction(workItem.id, {
|
|
2177
2233
|
...barrier.action,
|
|
2234
|
+
context: [
|
|
2235
|
+
...(Array.isArray(barrier.action.context) ? barrier.action.context : []),
|
|
2236
|
+
{
|
|
2237
|
+
type: 'replan-barrier',
|
|
2238
|
+
proposalId: barrier.proposalId,
|
|
2239
|
+
basePlanRevision: nextWorkItem.planRevision,
|
|
2240
|
+
candidateActionIds: unfinished.map(candidate => candidate.id),
|
|
2241
|
+
},
|
|
2242
|
+
],
|
|
2178
2243
|
contractRevision: nextWorkItem.revision,
|
|
2179
2244
|
status: 'ready',
|
|
2180
2245
|
}, this.#nextSequence(workItem.id), now);
|
|
2181
2246
|
}
|
|
2247
|
+
if (transition.replanMutation) {
|
|
2248
|
+
for (const retained of transition.replanMutation.retain) {
|
|
2249
|
+
const prior = retained.action;
|
|
2250
|
+
const candidate = {
|
|
2251
|
+
...prior,
|
|
2252
|
+
...retained.nextAction,
|
|
2253
|
+
status: 'ready',
|
|
2254
|
+
generation: prior.generation + 1,
|
|
2255
|
+
attempt: 0,
|
|
2256
|
+
currentRunId: null,
|
|
2257
|
+
resultRunId: null,
|
|
2258
|
+
contractRevision: nextWorkItem.revision,
|
|
2259
|
+
};
|
|
2260
|
+
const candidateSpecHash = actionSpecHash(candidate);
|
|
2261
|
+
const changed = this.db.prepare(`UPDATE actions SET type = ?, required_role = ?, stage_id = ?,
|
|
2262
|
+
assignment_policy = ?, model_policy = ?, depends_on_stage_ids = ?, workspace_mode = ?,
|
|
2263
|
+
changes_requested_stage_id = ?, workspace = NULL, instruction = ?, brief = ?, context = ?,
|
|
2264
|
+
contract_revision = ?, generation = ?, spec_hash = ?, identity_history = ?, result_run_id = NULL, status = 'ready',
|
|
2265
|
+
attempt = 0, max_attempts = ?, current_run_id = NULL, lease_epoch = lease_epoch + 1,
|
|
2266
|
+
updated_at = ? WHERE id = ? AND work_item_id = ? AND status = 'superseded' AND generation = ?`).run(
|
|
2267
|
+
candidate.type, candidate.requiredRole || '', candidate.stageId,
|
|
2268
|
+
stringify(candidate.assignmentPolicy || null), stringify(candidate.modelPolicy || null),
|
|
2269
|
+
stringify(candidate.dependsOnStageIds || []), candidate.workspaceMode || 'shared',
|
|
2270
|
+
candidate.changesRequestedStageId || null, candidate.instruction || '', stringify(candidate.brief || null),
|
|
2271
|
+
stringify(candidate.context || []), candidate.contractRevision, candidate.generation,
|
|
2272
|
+
candidateSpecHash, stringify(actionIdentityHistory(prior, candidate.generation, candidateSpecHash)),
|
|
2273
|
+
candidate.maxAttempts || 2, now,
|
|
2274
|
+
prior.id, workItem.id, prior.generation,
|
|
2275
|
+
);
|
|
2276
|
+
if (Number(changed.changes) !== 1) throw new Error('Work Center retained Action lost its superseded identity fence');
|
|
2277
|
+
if (!nextAction) nextAction = this.getAction(prior.id);
|
|
2278
|
+
}
|
|
2279
|
+
for (const replacement of transition.replanMutation.replace) {
|
|
2280
|
+
const inserted = this.#insertAction(workItem.id, {
|
|
2281
|
+
...replacement.nextAction,
|
|
2282
|
+
contractRevision: nextWorkItem.revision,
|
|
2283
|
+
status: 'ready',
|
|
2284
|
+
}, this.#nextSequence(workItem.id), now);
|
|
2285
|
+
if (!nextAction) nextAction = inserted;
|
|
2286
|
+
}
|
|
2287
|
+
for (const added of transition.replanMutation.add) {
|
|
2288
|
+
const inserted = this.#insertAction(workItem.id, {
|
|
2289
|
+
...added,
|
|
2290
|
+
contractRevision: nextWorkItem.revision,
|
|
2291
|
+
status: 'ready',
|
|
2292
|
+
}, this.#nextSequence(workItem.id), now);
|
|
2293
|
+
if (!nextAction) nextAction = inserted;
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2182
2296
|
if (transition.graphResetStageId) {
|
|
2183
2297
|
nextAction = this.#resetGraphFromStage(
|
|
2184
2298
|
workItem.id,
|
|
@@ -2205,7 +2319,13 @@ export class WorkItemStore {
|
|
|
2205
2319
|
let workItemStatus = transition.workItemStatus;
|
|
2206
2320
|
let currentActionId = nextAction?.id ?? (transition.keepCurrentAction ? action.id : null);
|
|
2207
2321
|
let changedWorkItem;
|
|
2208
|
-
if (transition.
|
|
2322
|
+
if (transition.planConflict) {
|
|
2323
|
+
changedWorkItem = this.db.prepare(`UPDATE work_items SET status = ?, current_action_id = ?,
|
|
2324
|
+
current_run_id = NULL, ledger_revision = ledger_revision + ?, updated_at = ?
|
|
2325
|
+
WHERE id = ? AND status IN ('ready', 'running', 'waiting', 'needs_attention') AND revision = ?`).run(
|
|
2326
|
+
workItemStatus, currentActionId, ledgerIncrement, now, workItem.id, nextWorkItem.revision,
|
|
2327
|
+
);
|
|
2328
|
+
} else if (transition.graphAdvance) {
|
|
2209
2329
|
const graphState = this.#graphWorkItemState(workItem.id);
|
|
2210
2330
|
workItemStatus = graphState.status;
|
|
2211
2331
|
currentActionId = graphState.currentActionId;
|
|
@@ -2233,7 +2353,9 @@ export class WorkItemStore {
|
|
|
2233
2353
|
(work_item_id, proposal_id, base_plan_revision, plan_revision, kind, action_id, run_id, data, created_at)
|
|
2234
2354
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(
|
|
2235
2355
|
workItem.id, proposalId, workItem.planRevision, nextWorkItem.planRevision,
|
|
2236
|
-
transition.replanBarrier
|
|
2356
|
+
(transition.replanBarrier || transition.replanMutation)
|
|
2357
|
+
? 'replan'
|
|
2358
|
+
: (workItem.planRevision === 0 ? 'initial' : 'expand'),
|
|
2237
2359
|
action.id, runId, stringify(transition.eventData || {}), now,
|
|
2238
2360
|
);
|
|
2239
2361
|
} catch (error) {
|