@zq-silk/yui 0.11.3 → 0.12.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.
Files changed (108) hide show
  1. package/ARCHITECTURE.md +23 -4
  2. package/README.md +44 -22
  3. package/dist/cli/commandCatalog.js +13 -10
  4. package/dist/cli/interactionPolicy.js +5 -6
  5. package/dist/cli/updateCommand.js +3 -1
  6. package/dist/cli/updateOrchestrator.js +173 -28
  7. package/dist/cli/updatePorts.js +137 -8
  8. package/dist/cli/upgradeCommand.js +19 -9
  9. package/dist/cli.js +156 -57
  10. package/dist/commands/configCommands.js +13 -46
  11. package/dist/commands/executionAuditCommands.js +3 -2
  12. package/dist/commands/jobCommands.js +4 -10
  13. package/dist/commands/taskCommands.js +234 -200
  14. package/dist/commands/taskCompletionGate.js +29 -54
  15. package/dist/commands/taskContextCommand.js +61 -13
  16. package/dist/commands/taskInputCommands.js +8 -5
  17. package/dist/commands/taskNextActionCommand.js +56 -6
  18. package/dist/commands/taskOverviewCommand.js +17 -31
  19. package/dist/commands/taskRoleRuntimeStatus.js +55 -7
  20. package/dist/commands/taskWorkspaceCommands.js +5 -2
  21. package/dist/config/configCatalog.js +3 -3
  22. package/dist/config/yuiConfig.js +3 -7
  23. package/dist/context/wakeNotification.js +20 -5
  24. package/dist/controller/agentRuntimeObserver.js +247 -51
  25. package/dist/controller/clientRuntime.js +39 -3
  26. package/dist/controller/controller.js +31 -27
  27. package/dist/controller/fileSchedulerStoreAdapter.js +390 -332
  28. package/dist/controller/runtime.js +58 -3
  29. package/dist/controller/runtimeEventInbox.js +17 -7
  30. package/dist/controller/runtimeEventProcessor.js +12 -19
  31. package/dist/controller/runtimeHookRunFence.js +19 -4
  32. package/dist/controller/runtimeObservationHook.js +45 -0
  33. package/dist/controller/structuredProviderObservation.js +20 -3
  34. package/dist/core/controllerClient.js +20 -2
  35. package/dist/core/controllerServer.js +1 -0
  36. package/dist/execution/resourceBroker.js +5 -4
  37. package/dist/executor/agentExecutor.js +52 -50
  38. package/dist/executor/effectiveLaunch.js +8 -48
  39. package/dist/executor/fileRoleLaunchPlanner.js +129 -45
  40. package/dist/executor/workspacePreflightClassification.js +23 -2
  41. package/dist/interaction/operatorPresentation.js +33 -89
  42. package/dist/lifecycle/exactRunTerminalization.js +69 -5
  43. package/dist/observability/executionAudit.js +5 -0
  44. package/dist/observability/orchestrationMetrics.js +8 -3
  45. package/dist/profile/agentProfile.js +1 -1
  46. package/dist/release/cliHomeReleaseFence.js +123 -0
  47. package/dist/release/runtimeRelease.js +20 -0
  48. package/dist/repository/taskWorkspacePreparer.js +176 -60
  49. package/dist/resources/sqliteResourceRegistry.js +1 -1
  50. package/dist/review/deltaRecheck.js +12 -51
  51. package/dist/review/reviewAcceptance.js +26 -0
  52. package/dist/review/reviewConfig.js +0 -31
  53. package/dist/review/reviewDecision.js +113 -0
  54. package/dist/review/reviewOutcomeClassifier.js +1 -1
  55. package/dist/review/reviewRound.js +1 -1
  56. package/dist/review/reviewerAvailability.js +69 -0
  57. package/dist/run/recoveryProjection.js +45 -6
  58. package/dist/runtime/agentDriverObservation.js +24 -10
  59. package/dist/runtime/agentHost.js +159 -85
  60. package/dist/runtime/builtinAgentDrivers.js +4 -3
  61. package/dist/runtime/builtinTranscriptObserver.js +301 -64
  62. package/dist/runtime/builtinTranscriptUsage.js +9 -7
  63. package/dist/runtime/conversationSwitch.js +277 -0
  64. package/dist/runtime/index.js +2 -1
  65. package/dist/runtime/launchBroker.js +12 -0
  66. package/dist/runtime/processExitOutbox.js +88 -0
  67. package/dist/runtime/providerRuntimeIdentity.js +29 -1
  68. package/dist/runtime/runtimeHealthPolicy.js +5 -5
  69. package/dist/runtime/runtimeObservation.js +28 -0
  70. package/dist/runtime/runtimeProjection.js +22 -32
  71. package/dist/runtime/sessionTokenMetrics.js +181 -0
  72. package/dist/runtime/structuredProviderHost.js +7 -1
  73. package/dist/runtime/tmuxAdapters.js +4 -1
  74. package/dist/scheduler/activeRoleRunDelivery.js +34 -199
  75. package/dist/scheduler/activeTaskProgress.js +7 -6
  76. package/dist/scheduler/leaderWakeupProcessor.js +42 -138
  77. package/dist/scheduler/operatorEvent.js +34 -0
  78. package/dist/scheduler/operatorInputNotificationProcessor.js +54 -94
  79. package/dist/scheduler/roleRunStall.js +53 -31
  80. package/dist/scheduler/taskExecutionProjection.js +97 -76
  81. package/dist/scheduler/taskObservabilityProjection.js +10 -11
  82. package/dist/storage/migration/productionRegistry.js +379 -0
  83. package/dist/storage/sqliteSchema.js +66 -23
  84. package/dist/storage/sqliteStore.js +46 -23
  85. package/dist/storage/storeRpc.js +0 -1
  86. package/dist/storage/taskStore.js +15 -30
  87. package/dist/storage/upgrade/homeClassification.js +52 -0
  88. package/dist/storage/upgrade/offlineUpgradeInventory.js +145 -7
  89. package/dist/storage/upgrade/recordVersions.js +3 -2
  90. package/dist/storage/upgrade/sqliteMigrationTarget.js +30 -8
  91. package/dist/storage/upgrade/sqliteRecordMigrationTarget.js +23 -11
  92. package/dist/storage/upgrade/sqliteStateMigration.js +66 -8
  93. package/dist/storage/upgrade/upgradeOrchestrator.js +333 -12
  94. package/dist/task/completionReadiness.js +10 -6
  95. package/dist/task/nextAction.js +82 -58
  96. package/dist/telemetry/sqliteTelemetryStore.js +1 -1
  97. package/dist/web/assets/client/components.js +13 -3
  98. package/dist/web/assets/client/i18n.js +6 -2
  99. package/dist/web/webSnapshot.js +7 -1
  100. package/i18n/README.zh-CN.md +2 -2
  101. package/package.json +1 -1
  102. package/skills/yui-leader/SKILL.md +60 -20
  103. package/skills/yui-operator/SKILL.md +13 -4
  104. package/skills/yui-reviewer/SKILL.md +35 -11
  105. package/dist/context/sessionContextBudget.js +0 -71
  106. package/dist/lifecycle/contextBudgetRollover.js +0 -81
  107. package/dist/lifecycle/taskRoleSessionReset.js +0 -126
  108. package/dist/scheduler/operatorNotification.js +0 -59
@@ -1,71 +0,0 @@
1
- import { resolveContextBudget } from "../config/yuiConfig.js";
2
- import { runtimeObservationFromTaskEvent } from "../runtime/runtimeObservation.js";
3
- export function evaluateSessionContextBudget(events, session, configured) {
4
- const budget = resolveContextBudget(configured);
5
- const peak = observedPeakInputTokens(events, session);
6
- const state = peak >= budget.hardTokens
7
- ? "hard"
8
- : peak >= budget.softTokens
9
- ? "soft"
10
- : "within";
11
- return Object.freeze({ state, peakTokens: peak, budget });
12
- }
13
- /**
14
- * Largest per-request input peak observed for one Session generation. Usage
15
- * observations carry cumulative session totals; consecutive deltas bound the
16
- * per-request input of the window between them. The first observation for a
17
- * generation is treated as one full request so a long-lived resumed Session
18
- * that was only sampled late still counts its inherited context.
19
- */
20
- export function observedPeakInputTokens(events, session) {
21
- let previous = 0;
22
- let peak = 0;
23
- for (const event of events) {
24
- const observation = runtimeObservationFromTaskEvent(event);
25
- if (observation === null)
26
- continue;
27
- if (!matchesSession(observation.fence, session))
28
- continue;
29
- const usage = usageTotal(observation.payload.usage);
30
- if (usage === null)
31
- continue;
32
- const delta = Math.max(0, usage - previous);
33
- if (delta > peak)
34
- peak = delta;
35
- previous = usage;
36
- }
37
- return peak;
38
- }
39
- function matchesSession(fence, session) {
40
- if (fence.taskId !== undefined && fence.taskId !== session.taskId)
41
- return false;
42
- if (fence.roleName !== session.roleName)
43
- return false;
44
- if (session.nativeSessionId !== undefined
45
- && fence.nativeSessionId !== undefined
46
- && fence.nativeSessionId !== session.nativeSessionId) {
47
- return false;
48
- }
49
- if (session.launchId !== undefined
50
- && fence.launchId !== undefined
51
- && fence.launchId !== session.launchId) {
52
- return false;
53
- }
54
- return true;
55
- }
56
- function usageTotal(usage) {
57
- if (typeof usage !== "object" || usage === null || Array.isArray(usage))
58
- return null;
59
- const record = usage;
60
- const inputTokens = integer(record.inputTokens);
61
- if (inputTokens === null)
62
- return null;
63
- // RuntimeUsageSnapshot.inputTokens is the normalized processed input total.
64
- // cachedInputTokens is an informational breakdown of that total, matching
65
- // runtimeProjection and the Driver documentation; adding it again would
66
- // fabricate context pressure and trigger premature Session rollover.
67
- return inputTokens;
68
- }
69
- function integer(value) {
70
- return Number.isSafeInteger(value) && value >= 0 ? value : null;
71
- }
@@ -1,81 +0,0 @@
1
- import { enqueueWork } from "../coordination/workMailboxQueue.js";
2
- import { validateRoleSessionSet } from "../executor/agentExecutor.js";
3
- import { createTaskEvent } from "../event/taskEvent.js";
4
- import { RUNTIME_CLEANUP_REQUIRED_REASON, runtimeLifecycleTarget } from "../runtime/lifecycleReservation.js";
5
- /**
6
- * Issue 04 (context token budget): retires one native Session generation that
7
- * crossed the hard context budget so the next Leader wake starts a fresh
8
- * generation. This is a controlled rollover, not a failure: the durable Task
9
- * records are the checkpoint, the bounded context snapshot re-establishes
10
- * working context for the new generation, and the retired Session is kept in
11
- * history as `stopped` with an auditable event. The Controller separately
12
- * owns verified process cleanup through the runtime cleanup lane.
13
- */
14
- export const CONTEXT_BUDGET_ROLLOVER_REASON = "context-budget-hard-limit";
15
- export function rolloverTaskRoleSessionForContextBudget(store, taskId, roleName, evidence, now) {
16
- const task = store.getTask(taskId);
17
- if (task === null)
18
- throw new Error(`Task not found: ${taskId}.`);
19
- if (task.status !== "active") {
20
- throw new Error(`Task is not active: ${task.id}/${task.status}.`);
21
- }
22
- const role = store.getRole(task.id, roleName);
23
- if (role === null)
24
- throw new Error(`Role not found: ${task.id}/${roleName}.`);
25
- const set = store.getTaskRoleSessionSet(task.id, role.name);
26
- const current = set?.sessions[set.activeAgentId];
27
- if (set === null || set === undefined || current === undefined) {
28
- // No live generation to retire; the caller can launch fresh directly.
29
- return null;
30
- }
31
- const timestamp = now.toISOString();
32
- const reason = `${CONTEXT_BUDGET_ROLLOVER_REASON} (peak ${evidence.peakTokens} >= hard ${evidence.hardTokens} tokens)`;
33
- enqueueWork(store, runtimeLifecycleTarget({ scope: "task", taskId: task.id, roleName: role.name }), RUNTIME_CLEANUP_REQUIRED_REASON, now, [{ type: "task", id: task.id }]);
34
- const retired = retireStoppedTaskRoleSession(set, timestamp);
35
- store.saveTaskRoleSessionSet(retired);
36
- const eventId = store.nextEventId(task.id);
37
- store.saveEvent(task.id, createTaskEvent(eventId, task.id, "runtime.role-session-reset", {
38
- roleName: role.name,
39
- reason,
40
- peakTokens: String(evidence.peakTokens),
41
- hardTokens: String(evidence.hardTokens),
42
- ...(current.nativeSessionId === undefined
43
- ? {}
44
- : { nativeSessionId: current.nativeSessionId }),
45
- ...(current.launchId === undefined ? {} : { launchId: current.launchId })
46
- }, now));
47
- return Object.freeze({
48
- taskId: task.id,
49
- roleName: role.name,
50
- eventId,
51
- ...(current.nativeSessionId === undefined
52
- ? {}
53
- : { retiredNativeSessionId: current.nativeSessionId }),
54
- ...(current.launchId === undefined ? {} : { retiredLaunchId: current.launchId })
55
- });
56
- }
57
- /**
58
- * Retires the current generation to history as `stopped` (not `broken`:
59
- * a budget rollover is not a Session failure) and clears the Turn fence so
60
- * the next launch is a fresh generation.
61
- */
62
- function retireStoppedTaskRoleSession(set, timestamp) {
63
- validateRoleSessionSet(set);
64
- const current = set.sessions[set.activeAgentId];
65
- const sessions = { ...set.sessions };
66
- delete sessions[set.activeAgentId];
67
- const history = current === undefined
68
- ? set.history
69
- : [
70
- ...(set.history ?? []),
71
- { ...current, status: "stopped", updatedAt: timestamp }
72
- ];
73
- return validateRoleSessionSet({
74
- ...set,
75
- sessions,
76
- ...(history === undefined ? {} : { history }),
77
- inFlight: null,
78
- providerBinding: null,
79
- updatedAt: timestamp
80
- });
81
- }
@@ -1,126 +0,0 @@
1
- import { enqueueWork } from "../coordination/workMailboxQueue.js";
2
- import { resetTaskRoleSession } from "../executor/agentExecutor.js";
3
- import { createTaskEvent } from "../event/taskEvent.js";
4
- import { createTaskMessage } from "../message/message.js";
5
- import { updateRoleStatus } from "../role/role.js";
6
- import { createLeaderRecoveryNotification } from "../scheduler/operatorNotification.js";
7
- import { recordLeaderFailure } from "../scheduler/leaderFailure.js";
8
- import { RUNTIME_CLEANUP_REQUIRED_REASON, runtimeLifecycleTarget } from "../runtime/lifecycleReservation.js";
9
- import { formatAgentRunReceiptId } from "../task/taskRecordReference.js";
10
- import { updateWorkItemStatus, workItemOwnsUnresolvedExecutionLane } from "../workItem/workItem.js";
11
- import { terminalizeExactTaskRun } from "./exactRunTerminalization.js";
12
- /**
13
- * Resets the current native generation using Yui's own persisted identities.
14
- * The caller supplies intent only; the Controller verifies process cleanup.
15
- */
16
- export function resetTaskRoleSessionGeneration(store, taskId, roleName, reason, now) {
17
- const task = store.getTask(requiredIdentity(taskId, "Task id"));
18
- if (task === null)
19
- throw new Error(`Task not found: ${taskId}.`);
20
- if (task.status !== "active")
21
- throw new Error(`Task is not active: ${task.id}/${task.status}.`);
22
- const normalizedRole = requiredIdentity(roleName, "Role name");
23
- const role = store.getRole(task.id, normalizedRole);
24
- if (role === null)
25
- throw new Error(`Role not found: ${task.id}/${normalizedRole}.`);
26
- const summary = `Reset native Session: ${requiredText(reason, "Reset reason")}`;
27
- let sessions = store.getTaskRoleSessionSet(task.id, role.name);
28
- const current = sessions?.sessions[sessions.activeAgentId];
29
- const activeRun = store.getActiveAgentRun(task.id, role.name);
30
- if (activeRun !== null) {
31
- const receiptId = sessions?.inFlight?.runId === activeRun.id
32
- ? sessions.inFlight.receiptId
33
- : formatAgentRunReceiptId(task.id, activeRun.id);
34
- const terminal = terminalizeExactTaskRun(store, {
35
- taskId: task.id,
36
- roleName: role.name,
37
- agentId: activeRun.effective.agentId,
38
- runId: activeRun.id,
39
- receiptId,
40
- ...(current === undefined ? {} : {
41
- nativeSessionId: current.nativeSessionId,
42
- ...(current.launchId === undefined ? {} : { launchId: current.launchId })
43
- }),
44
- outcome: { status: "failed", summary }
45
- }, now);
46
- if (terminal.disposition !== "applied" || terminal.run === null) {
47
- throw new Error(`Task Role reset lost its exact Run fence: ${terminal.reason ?? "obsolete"}.`);
48
- }
49
- if (activeRun.purpose === "execution" && activeRun.workItemId !== undefined) {
50
- const item = store.getWorkItem(task.id, activeRun.workItemId);
51
- if (item !== null
52
- && !["completed", "failed", "retired"].includes(item.status)
53
- && !workItemOwnsUnresolvedExecutionLane(item, activeRun.executionGroupId, activeRun.executionLaneId)) {
54
- store.saveWorkItem(task.id, updateWorkItemStatus(item, "failed", now, summary));
55
- }
56
- }
57
- }
58
- enqueueWork(store, runtimeLifecycleTarget({
59
- scope: "task",
60
- taskId: task.id,
61
- roleName: role.name
62
- }), RUNTIME_CLEANUP_REQUIRED_REASON, now, [{ type: "task", id: task.id }]);
63
- sessions = store.getTaskRoleSessionSet(task.id, role.name);
64
- if (sessions !== null)
65
- store.saveTaskRoleSessionSet(resetTaskRoleSession(sessions, now));
66
- const updatedRole = store.getRole(task.id, role.name);
67
- store.saveRole(task.id, updateRoleStatus(updatedRole, role.name === "leader" ? "failed" : "idle", now));
68
- const message = createTaskMessage(store.nextMessageId(task.id), task.id, summary, "system", { type: "system" }, now, activeRun === null ? {} : {
69
- runId: activeRun.id,
70
- ...(activeRun.workItemId === undefined ? {} : { workItemId: activeRun.workItemId })
71
- });
72
- store.saveMessage(task.id, message);
73
- store.saveEvent(task.id, createTaskEvent(store.nextEventId(task.id), task.id, "runtime.role-session-reset", {
74
- roleName: role.name,
75
- reason: summary,
76
- ...(activeRun === null ? {} : { runId: activeRun.id }),
77
- ...(current?.nativeSessionId === undefined
78
- ? {}
79
- : { nativeSessionId: current.nativeSessionId })
80
- }, now));
81
- if (role.name === "leader") {
82
- const nativeSessionId = current?.nativeSessionId ?? `reset-${task.id}`;
83
- store.saveLeaderFailure(recordLeaderFailure(task.id, nativeSessionId, summary, now, store.getLeaderFailure(task.id)));
84
- store.saveOperatorNotification(createLeaderRecoveryNotification(task.id, summary, now, store.getOperatorNotification(task.id)));
85
- enqueueWork(store, { kind: "operator" }, "leader-run-failed", now, [
86
- { type: "task", id: task.id },
87
- { type: "message", taskId: task.id, id: message.id },
88
- ...(activeRun === null ? [] : [{
89
- type: "run",
90
- taskId: task.id,
91
- id: activeRun.id
92
- }])
93
- ]);
94
- }
95
- else {
96
- enqueueWork(store, { kind: "role", taskId: task.id, roleName: "leader" }, "role-run-failed", now, [
97
- { type: "message", taskId: task.id, id: message.id },
98
- ...(activeRun === null ? [] : [{
99
- type: "run",
100
- taskId: task.id,
101
- id: activeRun.id
102
- }])
103
- ]);
104
- }
105
- return {
106
- taskId: task.id,
107
- roleName: role.name,
108
- run: activeRun === null ? null : store.getAgentRun(task.id, activeRun.id),
109
- ...(current === undefined ? {} : { nativeSessionId: current.nativeSessionId })
110
- };
111
- }
112
- function requiredIdentity(value, label) {
113
- const normalized = requiredText(value, label);
114
- if (["__proto__", "prototype", "constructor", ".", ".."].includes(normalized)
115
- || /[\/\\\0]/u.test(normalized))
116
- throw new Error(`${label} is invalid.`);
117
- return normalized;
118
- }
119
- function requiredText(value, label) {
120
- if (typeof value !== "string" || value.includes("\0"))
121
- throw new Error(`${label} is invalid.`);
122
- const normalized = value.trim();
123
- if (normalized.length === 0)
124
- throw new Error(`${label} is required.`);
125
- return normalized;
126
- }
@@ -1,59 +0,0 @@
1
- export const CURRENT_OPERATOR_NOTIFICATION_SCHEMA_VERSION = 1;
2
- export function createLeaderRecoveryNotification(taskId, message, now, existing) {
3
- const timestamp = now.toISOString();
4
- return {
5
- schemaVersion: CURRENT_OPERATOR_NOTIFICATION_SCHEMA_VERSION,
6
- taskId: requiredText(taskId, "Task id"),
7
- type: "leader-recovery-failed",
8
- message: requiredText(message, "Operator notification message"),
9
- createdAt: existing?.type === "leader-recovery-failed"
10
- ? existing.createdAt
11
- : timestamp,
12
- updatedAt: timestamp
13
- };
14
- }
15
- export function createTaskTerminalNotification(taskId, status, by, summary, now) {
16
- const timestamp = now.toISOString();
17
- return {
18
- schemaVersion: CURRENT_OPERATOR_NOTIFICATION_SCHEMA_VERSION,
19
- taskId: requiredText(taskId, "Task id"),
20
- type: "task-terminal",
21
- status,
22
- by,
23
- summary: requiredText(summary, "Task terminal summary"),
24
- createdAt: timestamp,
25
- updatedAt: timestamp
26
- };
27
- }
28
- export function createLeaderStallNotification(taskId, runId, progressAt, evidenceKey, now, existing) {
29
- const timestamp = now.toISOString();
30
- const previous = existing?.type === "leader-stalled"
31
- && existing.runId === runId
32
- && existing.progressAt === progressAt
33
- ? existing
34
- : undefined;
35
- return {
36
- schemaVersion: CURRENT_OPERATOR_NOTIFICATION_SCHEMA_VERSION,
37
- taskId: requiredText(taskId, "Task id"),
38
- type: "leader-stalled",
39
- message: requiredText([
40
- `Leader Run ${runId} is truly stalled for Task ${taskId}.`,
41
- `lastProgressAt=${progressAt}`,
42
- `classification=truly-stalled`,
43
- `evidence=${evidenceKey}`,
44
- "Inspect the Task context and decide whether to continue, reset, retry, change Agent, or request user input; Controller performed no automatic action."
45
- ].join(" "), "Operator notification message"),
46
- runId: requiredText(runId, "Leader Run id"),
47
- progressAt: requiredText(progressAt, "Leader progress timestamp"),
48
- classification: "truly-stalled",
49
- evidenceKey: requiredText(evidenceKey, "Leader stall evidence"),
50
- createdAt: previous?.createdAt ?? timestamp,
51
- updatedAt: timestamp
52
- };
53
- }
54
- function requiredText(value, label) {
55
- const normalized = value.trim();
56
- if (normalized.length === 0)
57
- throw new Error(`${label} is required.`);
58
- return normalized;
59
- }