@zq-silk/yui 0.13.7 → 0.13.9
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/ARCHITECTURE.md +40 -4
- package/README.md +23 -4
- package/dist/cli/commandCatalog.js +21 -2
- package/dist/cli/updatePorts.js +4 -4
- package/dist/cli.js +43 -14
- package/dist/commands/agentCommands.js +1 -1
- package/dist/commands/configCommands.js +1 -86
- package/dist/commands/executionAuditCommands.js +17 -16
- package/dist/commands/globalRoleCommands.js +4 -4
- package/dist/commands/sessionCommands.js +2 -6
- package/dist/commands/taskActor.js +1 -2
- package/dist/commands/taskCommands.js +93 -21
- package/dist/commands/taskContextCommand.js +1 -1
- package/dist/commands/taskExecutionCommands.js +0 -5
- package/dist/commands/taskOverviewCommand.js +5 -1
- package/dist/commands/taskRoleRuntimeStatus.js +3 -16
- package/dist/config/configCatalog.js +1 -6
- package/dist/config/yuiConfig.js +0 -79
- package/dist/context/sessionBootstrapManifest.js +26 -23
- package/dist/controller/clientRuntime.js +40 -3
- package/dist/controller/controller.js +29 -54
- package/dist/controller/fileSchedulerStoreAdapter.js +372 -1117
- package/dist/controller/runtime.js +12 -5
- package/dist/controller/runtimeHookRunFence.js +3 -9
- package/dist/controller/runtimeLaunchCoordinator.js +44 -67
- package/dist/controller/structuredProviderObservation.js +18 -5
- package/dist/coordination/workMailbox.js +4 -4
- package/dist/execution/executionHealth.js +1 -1
- package/dist/executor/agentExecutor.js +103 -93
- package/dist/executor/executorRegistry.js +8 -20
- package/dist/executor/fileRoleLaunchPlanner.js +26 -93
- package/dist/executor/turnCompletion.js +5 -5
- package/dist/lifecycle/exactRunTerminalization.js +2 -4
- package/dist/observability/executionAudit.js +40 -94
- package/dist/operator/operatorSessionHistory.js +7 -5
- package/dist/output/rolePresentation.js +0 -1
- package/dist/repository/taskWorkspacePreparer.js +0 -1
- package/dist/role/role.js +13 -21
- package/dist/run/agentRun.js +4 -54
- package/dist/runtime/agentDriver.js +2 -0
- package/dist/runtime/agentError.js +114 -0
- package/dist/runtime/agentHost.js +55 -82
- package/dist/runtime/builtinAgentDrivers.js +21 -9
- package/dist/runtime/builtinAgentErrorMappers.js +150 -0
- package/dist/runtime/exactControlPlane.js +6 -12
- package/dist/runtime/index.js +1 -2
- package/dist/runtime/launchBroker.js +5 -19
- package/dist/runtime/lifecycleReservation.js +20 -4
- package/dist/runtime/providerRuntimeIdentity.js +11 -19
- package/dist/runtime/runtimeBinding.js +0 -27
- package/dist/runtime/runtimeObservation.js +7 -16
- package/dist/runtime/runtimeSessionCandidate.js +3 -10
- package/dist/runtime/sessionLaunchRequest.js +1 -2
- package/dist/runtime/sessionReconciliation.js +2 -2
- package/dist/runtime/structuredProviderHost.js +44 -79
- package/dist/runtime/taskRuntimeIsolation.js +0 -7
- package/dist/runtime/tmuxAdapters.js +6 -49
- package/dist/scheduler/activeRoleRunDelivery.js +220 -178
- package/dist/scheduler/activeTaskProgress.js +1 -4
- package/dist/scheduler/leaderWakeupProcessor.js +123 -88
- package/dist/scheduler/roleRunLiveness.js +4 -1
- package/dist/scheduler/roleRunStall.js +10 -14
- package/dist/scheduler/wakeReason.js +4 -0
- package/dist/storage/migration/productionRegistry.js +475 -0
- package/dist/storage/sqliteSchema.js +54 -2
- package/dist/storage/sqliteStore.js +11 -44
- package/dist/storage/taskStore.js +8 -36
- package/dist/web/webSnapshot.js +3 -0
- package/i18n/README.zh-CN.md +11 -3
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +30 -8
- package/skills/yui-operator/SKILL.md +14 -6
- package/skills/yui-runtime/SKILL.md +11 -8
- package/dist/lifecycle/providerErrorClass.js +0 -152
- package/dist/run/providerRetry.js +0 -226
- package/dist/run/providerRetryConfig.js +0 -27
- package/dist/runtime/providerErrorCodes.js +0 -278
- package/dist/runtime/providerRecoveryDecision.js +0 -55
|
@@ -1150,7 +1150,7 @@ export class SqliteTaskStore {
|
|
|
1150
1150
|
? ""
|
|
1151
1151
|
: ` WHERE ${predicates.join(" AND ")}`;
|
|
1152
1152
|
const rows = this.#db.prepare(`SELECT scope, task_id, role_name, agent_id, adapter_id,
|
|
1153
|
-
native_session_id, launch_id,
|
|
1153
|
+
native_session_id, launch_id, session_updated_at,
|
|
1154
1154
|
cleanup_required
|
|
1155
1155
|
FROM runtime_session_candidates${where}`).all(...parameters);
|
|
1156
1156
|
const candidates = rows.map((row) => ({
|
|
@@ -1161,7 +1161,6 @@ export class SqliteTaskStore {
|
|
|
1161
1161
|
adapterId: row.adapter_id,
|
|
1162
1162
|
nativeSessionId: row.native_session_id,
|
|
1163
1163
|
...(row.launch_id === null ? {} : { launchId: row.launch_id }),
|
|
1164
|
-
status: row.status,
|
|
1165
1164
|
sessionUpdatedAt: row.session_updated_at,
|
|
1166
1165
|
cleanupRequired: row.cleanup_required === 1
|
|
1167
1166
|
})).sort(compareRuntimeSessionCandidates);
|
|
@@ -1217,14 +1216,14 @@ export class SqliteTaskStore {
|
|
|
1217
1216
|
json_extract(active_session, '$.adapterId') AS adapter_id,
|
|
1218
1217
|
json_extract(active_session, '$.nativeSessionId') AS native_session_id,
|
|
1219
1218
|
json_extract(active_session, '$.launchId') AS launch_id,
|
|
1220
|
-
|
|
1219
|
+
CASE
|
|
1220
|
+
WHEN json_extract(active_session, '$.status') = 'active'
|
|
1221
|
+
THEN 1 ELSE 0
|
|
1222
|
+
END AS is_active,
|
|
1221
1223
|
json_extract(active_session, '$.updatedAt') AS session_updated_at,
|
|
1222
1224
|
CASE
|
|
1223
|
-
WHEN json_extract(active_session, '$.status')
|
|
1224
|
-
AND (
|
|
1225
|
-
json_extract(active_session, '$.status') = 'running'
|
|
1226
|
-
OR json_type(active_session, '$.launchId') = 'text'
|
|
1227
|
-
)
|
|
1225
|
+
WHEN json_extract(active_session, '$.status') = 'active'
|
|
1226
|
+
AND json_type(active_session, '$.launchId') = 'text'
|
|
1228
1227
|
THEN 1 ELSE 0
|
|
1229
1228
|
END AS cleanup_required
|
|
1230
1229
|
FROM active`).get(...source.parameters);
|
|
@@ -1245,7 +1244,7 @@ export class SqliteTaskStore {
|
|
|
1245
1244
|
&& row.adapter_id === candidate.adapterId
|
|
1246
1245
|
&& row.native_session_id === candidate.nativeSessionId
|
|
1247
1246
|
&& (row.launch_id ?? undefined) === candidate.launchId
|
|
1248
|
-
&& row.
|
|
1247
|
+
&& row.is_active === 1
|
|
1249
1248
|
&& row.session_updated_at === candidate.sessionUpdatedAt
|
|
1250
1249
|
&& row.cleanup_required === (candidate.cleanupRequired ? 1 : 0);
|
|
1251
1250
|
}
|
|
@@ -1277,16 +1276,15 @@ export class SqliteTaskStore {
|
|
|
1277
1276
|
const taskId = candidate.owner.scope === "task" ? candidate.owner.taskId : "";
|
|
1278
1277
|
this.#db.prepare(`INSERT INTO runtime_session_candidates (
|
|
1279
1278
|
scope, task_id, role_name, agent_id, adapter_id, native_session_id,
|
|
1280
|
-
launch_id,
|
|
1281
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?,
|
|
1279
|
+
launch_id, session_updated_at, cleanup_required
|
|
1280
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1282
1281
|
ON CONFLICT(scope, task_id, role_name) DO UPDATE SET
|
|
1283
1282
|
agent_id = excluded.agent_id,
|
|
1284
1283
|
adapter_id = excluded.adapter_id,
|
|
1285
1284
|
native_session_id = excluded.native_session_id,
|
|
1286
1285
|
launch_id = excluded.launch_id,
|
|
1287
|
-
status = excluded.status,
|
|
1288
1286
|
session_updated_at = excluded.session_updated_at,
|
|
1289
|
-
cleanup_required = excluded.cleanup_required`).run(candidate.owner.scope, taskId, candidate.owner.roleName, candidate.agentId, candidate.adapterId, candidate.nativeSessionId, candidate.launchId ?? null, candidate.
|
|
1287
|
+
cleanup_required = excluded.cleanup_required`).run(candidate.owner.scope, taskId, candidate.owner.roleName, candidate.agentId, candidate.adapterId, candidate.nativeSessionId, candidate.launchId ?? null, candidate.sessionUpdatedAt, candidate.cleanupRequired ? 1 : 0);
|
|
1290
1288
|
}
|
|
1291
1289
|
#deleteRuntimeSessionCandidate(owner) {
|
|
1292
1290
|
this.#db.prepare(`DELETE FROM runtime_session_candidates
|
|
@@ -1585,37 +1583,6 @@ export class SqliteTaskStore {
|
|
|
1585
1583
|
payload = excluded.payload, updated_at = excluded.updated_at`).run(run.taskId, run.id, run.roleName, run.status, this.#json(run), this.#now());
|
|
1586
1584
|
});
|
|
1587
1585
|
}
|
|
1588
|
-
/**
|
|
1589
|
-
* Issue 04: SQLite-native pending retry query. A single indexed scan
|
|
1590
|
-
* replaces the adapter's per-Task in-memory sweep, so Controller deadline
|
|
1591
|
-
* arming no longer materializes every Task and Run in JavaScript.
|
|
1592
|
-
*/
|
|
1593
|
-
listPendingProviderRetries(taskIds) {
|
|
1594
|
-
const selectedTaskIds = taskIds === undefined
|
|
1595
|
-
? undefined
|
|
1596
|
-
: [...new Set(taskIds)].sort(numericCompare);
|
|
1597
|
-
if (selectedTaskIds?.length === 0)
|
|
1598
|
-
return [];
|
|
1599
|
-
const taskPredicate = selectedTaskIds === undefined
|
|
1600
|
-
? ""
|
|
1601
|
-
: ` AND tc.task_id IN (${selectedTaskIds.map(() => "?").join(", ")})`;
|
|
1602
|
-
const rows = this.#db.prepare(`SELECT DISTINCT ar.task_id AS taskId, ar.run_id AS runId, ar.role_name AS roleName,
|
|
1603
|
-
json_extract(ar.payload, '$.providerRetry.state') AS state,
|
|
1604
|
-
CASE json_extract(ar.payload, '$.providerRetry.state')
|
|
1605
|
-
WHEN 'scheduled' THEN json_extract(ar.payload, '$.providerRetry.nextAttemptAt')
|
|
1606
|
-
ELSE json_extract(ar.payload, '$.providerRetry.episodeDeadlineAt')
|
|
1607
|
-
END AS dueAt
|
|
1608
|
-
FROM tasks_catalog tc INDEXED BY idx_tasks_active
|
|
1609
|
-
JOIN active_runs ap ON ap.task_id = tc.task_id
|
|
1610
|
-
JOIN agent_runs ar ON ar.task_id = ap.task_id AND ar.run_id = ap.run_id
|
|
1611
|
-
WHERE tc.is_active = 1
|
|
1612
|
-
AND ar.status = 'active'
|
|
1613
|
-
AND json_extract(ar.payload, '$.providerRetry.state') IN
|
|
1614
|
-
('scheduled', 'dispatching', 'awaiting-progress')${taskPredicate}`).all(...(selectedTaskIds ?? []));
|
|
1615
|
-
return rows.sort((left, right) => (numericCompare(left.taskId, right.taskId)
|
|
1616
|
-
|| numericCompare(left.roleName, right.roleName)
|
|
1617
|
-
|| numericCompare(left.runId, right.runId)));
|
|
1618
|
-
}
|
|
1619
1586
|
// -- review rounds ----------------------------------------------------------
|
|
1620
1587
|
nextReviewRoundId(taskId) { return this.#nextTaskRecordId(taskId, "reviewRound"); }
|
|
1621
1588
|
getReviewRound(taskId, reviewRoundId) {
|
|
@@ -6,7 +6,7 @@ import { validateConfiguredAgent } from "../agent/agent.js";
|
|
|
6
6
|
import { validateCapabilityGrant } from "../grant/capabilityGrant.js";
|
|
7
7
|
import { validateReleaseWorkflow } from "../release/releaseWorkflow.js";
|
|
8
8
|
import { publicationExternalKey, validatePublicationReference } from "../task/publicationReference.js";
|
|
9
|
-
import { reconciliationIntervalMilliseconds, resolveAgentLaunchInactivityTimeoutSeconds, resolveControllerTaskConcurrency, resolveContextBudget, resolveDeliveryTimeoutSeconds, resolveLeaderNextActionMode, resolveLeaderSemanticBudgetTurns,
|
|
9
|
+
import { reconciliationIntervalMilliseconds, resolveAgentLaunchInactivityTimeoutSeconds, resolveControllerTaskConcurrency, resolveContextBudget, resolveDeliveryTimeoutSeconds, resolveLeaderNextActionMode, resolveLeaderSemanticBudgetTurns, resolveResourcesGcAutoQuarantine, resolveResourcesGcMode, resolveResourcesQuarantineTtlHours, resolveRuntimeHealth, resolveTelemetryEnabled, resolveTelemetryRunCap, resolveTelemetryTerminalKeep, resolveTmuxBin, resolveTmuxHistoryLimit } from "../config/yuiConfig.js";
|
|
10
10
|
import { resolveTimeZone } from "../output/timePresentation.js";
|
|
11
11
|
import { mailboxBatches, consumePendingBatch, mailboxHasWork, mailboxTargetKey, pendingLane, validateWorkMailbox } from "../coordination/workMailbox.js";
|
|
12
12
|
import { validateContextSnapshot } from "../context/contextSnapshot.js";
|
|
@@ -15,7 +15,6 @@ import { validateInputRequest } from "../input/inputRequest.js";
|
|
|
15
15
|
import { validateRoleSessionSet } from "../executor/agentExecutor.js";
|
|
16
16
|
import { validateTaskMessage } from "../message/message.js";
|
|
17
17
|
import { agentRunDeliveryReceiptId, validateAgentRun } from "../run/agentRun.js";
|
|
18
|
-
import { providerRetryWakeAt } from "../run/providerRetry.js";
|
|
19
18
|
import { compareRuntimeSessionCandidates, projectRuntimeSessionCandidate } from "../runtime/runtimeSessionCandidate.js";
|
|
20
19
|
import { FileSessionOwnerRegistry } from "../runtime/sessionOwnerRegistry.js";
|
|
21
20
|
import { validateReviewConfig } from "../review/reviewConfig.js";
|
|
@@ -45,7 +44,7 @@ import { CURRENT_AGGREGATE_SCHEMA_VERSION, requireCompatibleStorageSchema, requi
|
|
|
45
44
|
export const STORAGE_STATE_FILE = "state.json";
|
|
46
45
|
/** The root StorageState schema is the persisted aggregate document version. */
|
|
47
46
|
export const CURRENT_STORAGE_STATE_SCHEMA_VERSION = CURRENT_AGGREGATE_SCHEMA_VERSION;
|
|
48
|
-
export const CURRENT_CONFIG_SCHEMA_VERSION =
|
|
47
|
+
export const CURRENT_CONFIG_SCHEMA_VERSION = 4;
|
|
49
48
|
export const CURRENT_HOME_IDENTITY_SCHEMA_VERSION = 1;
|
|
50
49
|
export const CURRENT_ACTIVE_RUN_POINTER_SCHEMA_VERSION = 3;
|
|
51
50
|
/**
|
|
@@ -60,11 +59,11 @@ export const CURRENT_CONFIGURED_AGENT_SCHEMA_VERSION = 2;
|
|
|
60
59
|
export const CURRENT_PROJECT_SCHEMA_VERSION = 5;
|
|
61
60
|
export const CURRENT_AGENT_PROFILE_SCHEMA_VERSION = 2;
|
|
62
61
|
export const CURRENT_GLOBAL_ROLE_SCHEMA_VERSION = 3;
|
|
63
|
-
export const CURRENT_GLOBAL_ROLE_SESSION_SET_SCHEMA_VERSION =
|
|
62
|
+
export const CURRENT_GLOBAL_ROLE_SESSION_SET_SCHEMA_VERSION = 4;
|
|
64
63
|
export const CURRENT_TASK_SCHEMA_VERSION = 6;
|
|
65
64
|
export const CURRENT_TASK_BRIEF_SCHEMA_VERSION = 2;
|
|
66
65
|
export const CURRENT_CONTEXT_SNAPSHOT_SCHEMA_VERSION = 1;
|
|
67
|
-
export const CURRENT_TASK_ROLE_SCHEMA_VERSION =
|
|
66
|
+
export const CURRENT_TASK_ROLE_SCHEMA_VERSION = 4;
|
|
68
67
|
export const CURRENT_MANAGED_WORKSPACE_SCHEMA_VERSION = 2;
|
|
69
68
|
export const CURRENT_WORK_ITEM_SCHEMA_VERSION = 12;
|
|
70
69
|
export const CURRENT_REVIEW_ROUND_SCHEMA_VERSION = 6;
|
|
@@ -77,9 +76,9 @@ export const CURRENT_MILESTONE_SCHEMA_VERSION = 2;
|
|
|
77
76
|
export const CURRENT_EVENT_SCHEMA_VERSION = 2;
|
|
78
77
|
export const CURRENT_CAPABILITY_GRANT_SCHEMA_VERSION = 1;
|
|
79
78
|
export const CURRENT_RELEASE_WORKFLOW_SCHEMA_VERSION = 1;
|
|
80
|
-
export const CURRENT_WORK_MAILBOX_SCHEMA_VERSION =
|
|
79
|
+
export const CURRENT_WORK_MAILBOX_SCHEMA_VERSION = 3;
|
|
81
80
|
export const CURRENT_PUBLICATION_REFERENCE_SCHEMA_VERSION = 1;
|
|
82
|
-
export const CURRENT_ROLE_AGENT_SESSION_SCHEMA_VERSION =
|
|
81
|
+
export const CURRENT_ROLE_AGENT_SESSION_SCHEMA_VERSION = 4;
|
|
83
82
|
export const CURRENT_PENDING_WAKEUP_SCHEMA_VERSION = 1;
|
|
84
83
|
const STORAGE_LOCK_DIRECTORY = ".state.lock";
|
|
85
84
|
const LOCK_TIMEOUT_MS = 5_000;
|
|
@@ -118,13 +117,13 @@ export const CURRENT_STORED_TASK_SCHEMA_VERSION = 18;
|
|
|
118
117
|
* Keep these named at the storage boundary so the upgrade record-axis map can
|
|
119
118
|
* assert it is classifying the same bytes the store reads and writes.
|
|
120
119
|
*/
|
|
121
|
-
export const CURRENT_TASK_ROLE_SESSION_SET_SCHEMA_VERSION =
|
|
120
|
+
export const CURRENT_TASK_ROLE_SESSION_SET_SCHEMA_VERSION = 8;
|
|
122
121
|
/**
|
|
123
122
|
* v7 combines optional Issue 04 retry/receipt fields and Issue 05 Leader
|
|
124
123
|
* actionability fields. All are optional, so the v6→v7 migration is a
|
|
125
124
|
* version-only rewrite.
|
|
126
125
|
*/
|
|
127
|
-
export const CURRENT_AGENT_RUN_SCHEMA_VERSION =
|
|
126
|
+
export const CURRENT_AGENT_RUN_SCHEMA_VERSION = 10;
|
|
128
127
|
export const CURRENT_INTEGRATION_QUEUE_SCHEMA_VERSION = 1;
|
|
129
128
|
export class FileTaskStore {
|
|
130
129
|
rootDir;
|
|
@@ -991,29 +990,6 @@ export class FileTaskStore {
|
|
|
991
990
|
}
|
|
992
991
|
getAgentRun(taskId, id) { return optional(this.#state().tasks[taskId]?.agentRuns[id]); }
|
|
993
992
|
listAgentRuns(taskId) { return values(this.#requireTask(taskId).agentRuns, "id"); }
|
|
994
|
-
listPendingProviderRetries(taskIds) {
|
|
995
|
-
// The legacy File store can answer the empty case without a scan fallback.
|
|
996
|
-
// If durable retry state exists, the db-only capability must fail closed
|
|
997
|
-
// instead of silently losing the Controller's wake deadline.
|
|
998
|
-
const tasks = taskIds === undefined
|
|
999
|
-
? this.listTasks()
|
|
1000
|
-
: [...new Set(taskIds)].sort(numericCompare).flatMap((taskId) => {
|
|
1001
|
-
const task = this.getTask(taskId);
|
|
1002
|
-
return task === null ? [] : [task];
|
|
1003
|
-
});
|
|
1004
|
-
for (const task of tasks) {
|
|
1005
|
-
if (task.status !== "active")
|
|
1006
|
-
continue;
|
|
1007
|
-
for (const run of this.listAgentRuns(task.id)) {
|
|
1008
|
-
if (run.status === "active"
|
|
1009
|
-
&& run.providerRetry !== undefined
|
|
1010
|
-
&& providerRetryWakeAt(run.providerRetry) !== null) {
|
|
1011
|
-
throw new StorageRecordError("Provider retry in place requires the SQLite backend; run `yui update` to migrate this Home.");
|
|
1012
|
-
}
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
return [];
|
|
1016
|
-
}
|
|
1017
993
|
saveAgentRun(run) {
|
|
1018
994
|
const stored = identified(run, CURRENT_AGENT_RUN_SCHEMA_VERSION, "id", run.id, "Agent run");
|
|
1019
995
|
validateAgentRun(stored);
|
|
@@ -2498,10 +2474,6 @@ export function validateYuiConfig(config) {
|
|
|
2498
2474
|
resolveResourcesGcMode(config.resourcesGcMode);
|
|
2499
2475
|
resolveResourcesGcAutoQuarantine(config.resourcesGcAutoQuarantine);
|
|
2500
2476
|
resolveResourcesQuarantineTtlHours(config.resourcesQuarantineTtlHours);
|
|
2501
|
-
resolveProviderRetryMode(config.providerRetryMode);
|
|
2502
|
-
resolveProviderRetryAdapters(config.providerRetryAdapters);
|
|
2503
|
-
resolveProviderRetryDelaysSeconds(config.providerRetryDelaysSeconds);
|
|
2504
|
-
resolveProviderRetryMaxWindowSeconds(config.providerRetryMaxWindowSeconds);
|
|
2505
2477
|
resolveRuntimeHealth(config.runtimeHealth);
|
|
2506
2478
|
resolveControllerTaskConcurrency(config.controllerTaskConcurrency);
|
|
2507
2479
|
resolveAgentLaunchInactivityTimeoutSeconds(config.agentLaunchInactivityTimeoutSeconds);
|
package/dist/web/webSnapshot.js
CHANGED
|
@@ -92,6 +92,9 @@ export function buildWebTaskDetail(store, taskId, now = new Date()) {
|
|
|
92
92
|
const effectiveLaunch = activeRun?.effective ?? activeSession?.effective ?? null;
|
|
93
93
|
return {
|
|
94
94
|
...role,
|
|
95
|
+
// Presentation only: workflow activity is derived from AgentRun; the
|
|
96
|
+
// native Session contributes lifecycle detail when no Run is active.
|
|
97
|
+
status: activeRun === undefined ? activeSession?.status ?? "idle" : "running",
|
|
95
98
|
sessionTokens: projectSessionTokenMetrics(events, resolveSessionTokenIdentity(activeSession === undefined
|
|
96
99
|
? null
|
|
97
100
|
: { taskId, roleName: role.name, ...activeSession })),
|
package/i18n/README.zh-CN.md
CHANGED
|
@@ -2,9 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
# Yui
|
|
4
4
|
|
|
5
|
-
Yui
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
Yui 是面向智能 Codex/Claude Agent 的本地控制平面。它持久保存用户意图、
|
|
6
|
+
Project Knowledge、Task、交接和结果,并提供上下文、消息、委派、工作区、
|
|
7
|
+
Session、审查和集成等小而原子的能力。Agent 组合这些能力,自主决定规划、
|
|
8
|
+
顺序、委派、重试和恢复。
|
|
9
|
+
|
|
10
|
+
Yui 不把 Agent 的判断固化成确定性的工作流引擎。核心只负责持久身份、用户
|
|
11
|
+
授权、工作区隔离和原子状态变更;Provider Session 与运行时观测用于执行和
|
|
12
|
+
连续性,但不是 Task 事实的另一套来源。用户只需和 Operator 对话,Operator
|
|
13
|
+
负责路由,Leader 负责目标拆解、执行选择、验收和集成。
|
|
8
14
|
|
|
9
15
|
当前实现保留实用的 Role/Agent/session 与 CLI 框架,不恢复后期膨胀的数据维护、租约、定时调度和恢复账本体系。
|
|
10
16
|
|
|
@@ -514,6 +520,8 @@ Task 生命周期的交互选择只展示有效来源状态:activate 只展示
|
|
|
514
520
|
|
|
515
521
|
Run、Conversation、Activation 与 Turn 是四个独立身份。Conversation 可以跨多个 Run 和客户端连接;Activation 只代表 Yui 当前的连接,而不是对 Provider thread 的独占所有权;Turn 在写入前先持久化。写入超时或结果不明确会进入 `delivery-unknown`,不会自动重发。Codex 已存在的原生 active Turn 只会让 Yui 暂时等待,不会导致 Yui Run 失败;Claude 等独立进程 Provider 继续通过 Yui 的 view/takeover 边界进行人工控制。
|
|
516
522
|
|
|
523
|
+
AgentRun 是 Role 是否有工作正在执行的唯一持久调度状态。Conversation 不再维护另一份 current Run;Provider Turn 中的 Run id 只用于关联接收回执和终态事件。TaskRole 本身只保存身份和期望启动配置,不再保存可写的运行状态;CLI/Web 展示的 Role 状态由活动 AgentRun 派生,并叠加 Session/Driver 生命周期事实用于诊断。Agent 可以在 Provider 终态到达前声明旧 Run 的语义结果,下一批 mailbox 工作也可以先形成新的 AgentRun;Agent Host 仍会串行等待旧 Turn 结束,再投递被保留的新输入,不回滚事件,也不把旧 Conversation 强行换绑到新 Run。
|
|
524
|
+
|
|
517
525
|
Task Role 使用以下显式入口:
|
|
518
526
|
|
|
519
527
|
```sh
|
package/package.json
CHANGED
|
@@ -122,8 +122,8 @@ or yield merely to preserve that native wait.
|
|
|
122
122
|
Before the first durable Leader action, Yui observes fresh native generations
|
|
123
123
|
that produce no WorkItem, Review, Integration, or Leader-attributed durable
|
|
124
124
|
event. Two such generations create a non-blocking orchestration advisory for
|
|
125
|
-
Leader and Operator judgment; they do not fail the Role
|
|
126
|
-
|
|
125
|
+
Leader and Operator judgment; they do not fail the Role or prevent another
|
|
126
|
+
useful generation. Read the evidence
|
|
127
127
|
before retrying, then choose whether to continue, change the configured Leader,
|
|
128
128
|
or perform direct maintenance without manufacturing protocol records merely to
|
|
129
129
|
silence the advisory.
|
|
@@ -703,13 +703,35 @@ newer WorkItem. If the original execution Session cannot be resumed, surface
|
|
|
703
703
|
the recovery decision to the user; do not silently discard its context by
|
|
704
704
|
creating a replacement.
|
|
705
705
|
|
|
706
|
-
|
|
707
|
-
inspect the Run and partial work, then retry only a confirmed failed Run:
|
|
706
|
+
For a Role runtime failure, inspect the exact error and runtime identities first:
|
|
708
707
|
|
|
709
708
|
```sh
|
|
710
|
-
yui task
|
|
709
|
+
yui task event show <task> <agent-error-event>
|
|
710
|
+
yui task role session inspect <task> <role>
|
|
711
711
|
```
|
|
712
712
|
|
|
713
|
+
When a Provider-accepted Turn fails with availability, `429`, capacity, or a
|
|
714
|
+
recoverable transport error and the Session remains usable, retain the Run and
|
|
715
|
+
Session; a recovery action adds a new Turn on that same native Session. A
|
|
716
|
+
Session preparation failure or Driver rejection before input acceptance fails
|
|
717
|
+
the exact Run once; inspect its error and explicitly retry that failed Run when
|
|
718
|
+
another attempt is useful. Core will not redispatch it on a scheduler tick.
|
|
719
|
+
|
|
720
|
+
If the Driver proves that the Session cannot continue, settle or retire the
|
|
721
|
+
exact active Run, stop only that Role Session, then retry the failed Run so the
|
|
722
|
+
next dispatch starts a new Session:
|
|
723
|
+
|
|
724
|
+
```sh
|
|
725
|
+
yui task role session stop <task> <role> --reason "<error decision>"
|
|
726
|
+
yui task run retry <task>/<failed-run>
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
The new Run context contains the prior Agent, adapter, Run, Host activation,
|
|
730
|
+
native Session/Turn identities, and complete raw error through the referenced
|
|
731
|
+
Task event. Inspect recent `runtime.agent-error` events before another fresh
|
|
732
|
+
Session; after repeated fresh-Session failures, report the evidence and bounded
|
|
733
|
+
options to the user instead of inventing another automatic loop.
|
|
734
|
+
|
|
713
735
|
## Request a decision
|
|
714
736
|
|
|
715
737
|
When a real user choice, new authority, or unavailable external fact is
|
|
@@ -789,8 +811,8 @@ yui task complete <task-id> --summary "<outcome, validation, and remaining risks
|
|
|
789
811
|
|
|
790
812
|
Retire obsolete WorkItems with `yui task work retire <task>/<work> --summary
|
|
791
813
|
"..."`, optionally using `--replacement`. If the current Provider Conversation
|
|
792
|
-
cannot continue,
|
|
793
|
-
`yui task role session
|
|
794
|
-
|
|
814
|
+
cannot continue, settle its Run and stop the exact idle Session with
|
|
815
|
+
`yui task role session stop`; the next explicit Run dispatch creates the
|
|
816
|
+
replacement. Archiving is a
|
|
795
817
|
separate global Operator lifecycle action. It performs the final Task-owned
|
|
796
818
|
runtime and clean-worktree teardown, including this Leader.
|
|
@@ -349,12 +349,20 @@ the workflow without claiming that version was delivered.
|
|
|
349
349
|
treat it as a permission boundary. The Operator may make code, semantic,
|
|
350
350
|
requirement, acceptance, recovery, and integration decisions and must leave
|
|
351
351
|
the real actor and rationale in durable Task state.
|
|
352
|
-
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
352
|
+
- Inspect `runtime.agent-error` and `yui task role session inspect` before a
|
|
353
|
+
recovery. When a Provider-accepted Turn fails with availability, `429`,
|
|
354
|
+
capacity, or a recoverable transport error and the Session remains usable,
|
|
355
|
+
add a new Turn to that Session. A Session preparation failure or Driver
|
|
356
|
+
rejection before input acceptance fails the exact Run once; explicitly retry
|
|
357
|
+
that failed Run when another attempt is useful. Core does not redispatch it
|
|
358
|
+
on a scheduler tick. If the Driver proves the Session cannot continue, settle
|
|
359
|
+
or retire its exact Run, stop that one idle Session with `yui task role
|
|
360
|
+
session stop <task> <role> --reason "..."`, then retry the failed Run. The
|
|
361
|
+
replacement Run receives the old Agent, adapter, Run, Host, Session, Turn,
|
|
362
|
+
and complete raw-error facts through Task context.
|
|
363
|
+
- Inspect recent errors before creating another fresh Session. After repeated
|
|
364
|
+
fresh-Session failures, summarize the evidence and bounded options to the
|
|
365
|
+
user; do not hide them behind an automatic replacement counter or loop.
|
|
358
366
|
- Retry only an explicitly failed recovery Job.
|
|
359
367
|
- When a Leader first-progress advisory is reported, inspect its native
|
|
360
368
|
generations and absence of durable progress. It is cost evidence rather than
|
|
@@ -12,10 +12,11 @@ workspace layout, native transcript, or an earlier Run.
|
|
|
12
12
|
For every managed Task Run:
|
|
13
13
|
|
|
14
14
|
1. Read the exact Run identity from the newest Bootstrap Envelope.
|
|
15
|
-
2. Before acting, load its authorized pack with the
|
|
15
|
+
2. Before acting, load its authorized pack with the Session CLI named by the
|
|
16
|
+
current Session Manifest:
|
|
16
17
|
|
|
17
18
|
```sh
|
|
18
|
-
|
|
19
|
+
"$YUI_SESSION_CLI" task run context "$YUI_TASK_ID/<run-id>" --json
|
|
19
20
|
```
|
|
20
21
|
|
|
21
22
|
3. Verify that the returned Task, Run, Role, purpose, Snapshot digest, workspace,
|
|
@@ -27,7 +28,7 @@ For every managed Task Run:
|
|
|
27
28
|
`refId`:
|
|
28
29
|
|
|
29
30
|
```sh
|
|
30
|
-
|
|
31
|
+
"$YUI_SESSION_CLI" task run context expand "$YUI_TASK_ID/<run-id>" <ref-id> --store <store> --mode full --json
|
|
31
32
|
```
|
|
32
33
|
|
|
33
34
|
A bare `<ref-id>` remains supported only when it identifies exactly one
|
|
@@ -46,7 +47,7 @@ For a global Operator or custom GlobalRole Session, load the stable authorized v
|
|
|
46
47
|
before routing or acting:
|
|
47
48
|
|
|
48
49
|
```sh
|
|
49
|
-
|
|
50
|
+
"$YUI_SESSION_CLI" session context "$YUI_ROLE" --json
|
|
50
51
|
```
|
|
51
52
|
|
|
52
53
|
Global context grants no Task implementation workspace. Read a Task only after
|
|
@@ -60,7 +61,9 @@ supported checkpoint/yield command as the final control-plane action, then stop
|
|
|
60
61
|
immediately. If that direct command is denied or stale, report the blocker once
|
|
61
62
|
and stop; do not wrap, retry, broaden permissions, or target another Run.
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
After a failed Provider Turn, read the referenced `runtime.agent-error` fact.
|
|
65
|
+
The failed Turn is immutable; a recovery is always a new Turn. Continue on the
|
|
66
|
+
same native Session when it remains recoverable, and load only the current Run
|
|
67
|
+
delta instead of replaying its original Assignment. A new Host process does not
|
|
68
|
+
imply a new Session, and a new Session must never be substituted silently for
|
|
69
|
+
the persisted native Session id.
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Issue 04 — Provider error classification.
|
|
3
|
-
*
|
|
4
|
-
* Provider failures arrive at the driver boundary as opaque free text (Claude
|
|
5
|
-
* StopFailure `error`/`errorDetails`, Codex turn-completion summaries). Each
|
|
6
|
-
* driver parses its own Provider's format into a structured
|
|
7
|
-
* {@link ProviderErrorCode} at the driver boundary. This module maps those
|
|
8
|
-
* codes to provider-neutral error classes by lookup, falling back to text
|
|
9
|
-
* matching only when the driver could not produce a structured code.
|
|
10
|
-
*
|
|
11
|
-
* The retry-in-place coordinator needs a stable, provider-neutral error class
|
|
12
|
-
* before it can decide whether the original Session may be retried.
|
|
13
|
-
*
|
|
14
|
-
* Classes (Issue 04 §2):
|
|
15
|
-
* - `transient-provider` — 500/502/504, connection reset, backend capacity;
|
|
16
|
-
* the original Session is retried in place.
|
|
17
|
-
* - `transport-uncertain` — the request may have been accepted but the
|
|
18
|
-
* response was lost; native facts are consulted
|
|
19
|
-
* before any resend.
|
|
20
|
-
* - `policy-denied` — cyber_policy / permission boundary; never retried
|
|
21
|
-
* automatically, never worked around by switching
|
|
22
|
-
* Session or widening permission.
|
|
23
|
-
* - `session-dead` — the process/tmux/native identity is gone; in-place
|
|
24
|
-
* retry stops and a replacement blocker is raised.
|
|
25
|
-
* - `invalid-request` — deterministic parameter/protocol error; fail fast,
|
|
26
|
-
* never call the Provider again.
|
|
27
|
-
* - `unclassified` — no conservative match; behaves like
|
|
28
|
-
* `invalid-request` for retry purposes (old
|
|
29
|
-
* terminalize-immediately behavior) while remaining
|
|
30
|
-
* observable in shadow metrics.
|
|
31
|
-
*/
|
|
32
|
-
import { PROVIDER_ERROR_CODE_CLASS } from "../runtime/providerErrorCodes.js";
|
|
33
|
-
/** Classes for which the original Session may be retried in place. */
|
|
34
|
-
export const RETRYABLE_PROVIDER_ERROR_CLASSES = [
|
|
35
|
-
"transient-provider",
|
|
36
|
-
"transport-uncertain"
|
|
37
|
-
];
|
|
38
|
-
export function isRetryableProviderErrorClass(errorClass) {
|
|
39
|
-
return RETRYABLE_PROVIDER_ERROR_CLASSES.includes(errorClass);
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Ordered pattern tables. The first class whose pattern matches wins, so the
|
|
43
|
-
* table order is the precedence order. Patterns are matched case-insensitively
|
|
44
|
-
* against the concatenation of every available text field.
|
|
45
|
-
*/
|
|
46
|
-
const SESSION_DEAD_PATTERNS = [
|
|
47
|
-
{ pattern: /session not found/iu, label: "session-not-found" },
|
|
48
|
-
{ pattern: /no such (session|thread)/iu, label: "no-such-session" },
|
|
49
|
-
{ pattern: /thread not found/iu, label: "thread-not-found" },
|
|
50
|
-
{ pattern: /session (has )?expired/iu, label: "session-expired" },
|
|
51
|
-
{ pattern: /session (has )?ended/iu, label: "session-ended" },
|
|
52
|
-
{ pattern: /session (is )?dead/iu, label: "session-dead" },
|
|
53
|
-
{ pattern: /session terminated/iu, label: "session-terminated" },
|
|
54
|
-
];
|
|
55
|
-
const CONTEXT_CAPACITY_PATTERNS = [
|
|
56
|
-
{ pattern: /maximum context length/iu, label: "maximum-context-length" },
|
|
57
|
-
{ pattern: /context length exceeded/iu, label: "context-length-exceeded" },
|
|
58
|
-
{ pattern: /context window (is )?(full|exceeded)/iu, label: "context-window-exceeded" },
|
|
59
|
-
{ pattern: /prompt (is )?too long/iu, label: "prompt-too-long" },
|
|
60
|
-
{ pattern: /too many tokens/iu, label: "too-many-tokens" }
|
|
61
|
-
];
|
|
62
|
-
const POLICY_DENIED_PATTERNS = [
|
|
63
|
-
{ pattern: /cyber[_-]?policy/iu, label: "cyber-policy" },
|
|
64
|
-
{ pattern: /policy[_-]?violation/iu, label: "policy-violation" },
|
|
65
|
-
{ pattern: /usage[_-]?policy/iu, label: "usage-policy" },
|
|
66
|
-
{ pattern: /content[_-]?policy/iu, label: "content-policy" },
|
|
67
|
-
{ pattern: /safety[_-]?policy/iu, label: "safety-policy" },
|
|
68
|
-
{ pattern: /policy denial/iu, label: "policy-denial" }
|
|
69
|
-
];
|
|
70
|
-
const INVALID_REQUEST_PATTERNS = [
|
|
71
|
-
{ pattern: /invalid[_-]?request/iu, label: "invalid-request" },
|
|
72
|
-
{ pattern: /validation error/iu, label: "validation-error" },
|
|
73
|
-
{ pattern: /bad request/iu, label: "bad-request" },
|
|
74
|
-
{ pattern: /\b400\b/u, label: "http-400" },
|
|
75
|
-
{ pattern: /unknown (flag|tool|argument)/iu, label: "unknown-argument" },
|
|
76
|
-
{ pattern: /unexpected argument/iu, label: "unexpected-argument" },
|
|
77
|
-
{ pattern: /invalid schema/iu, label: "invalid-schema" }
|
|
78
|
-
];
|
|
79
|
-
const TRANSIENT_PROVIDER_PATTERNS = [
|
|
80
|
-
{ pattern: /\b50[024]\b/u, label: "http-5xx" },
|
|
81
|
-
{ pattern: /server[\s_-]?error/iu, label: "server-error" },
|
|
82
|
-
{ pattern: /internal server error/iu, label: "internal-server-error" },
|
|
83
|
-
// HTTP/2 RST_STREAM / gRPC status carried by Claude Code and Codex streams
|
|
84
|
-
// (Task-27: "stream error: stream ID …; INTERNAL_ERROR; received from peer").
|
|
85
|
-
{ pattern: /\binternal[\s_-]?error\b/iu, label: "internal-error" },
|
|
86
|
-
{ pattern: /connection lost/iu, label: "connection-lost" },
|
|
87
|
-
{ pattern: /connection reset/iu, label: "connection-reset" },
|
|
88
|
-
{ pattern: /econnreset/iu, label: "econnreset" },
|
|
89
|
-
{ pattern: /socket hang up/iu, label: "socket-hang-up" },
|
|
90
|
-
{ pattern: /kv[_-]?cache[_-]?allocate[_-]?failed/iu, label: "kv-cache-allocate-failed" },
|
|
91
|
-
{ pattern: /overloaded/iu, label: "overloaded" },
|
|
92
|
-
{ pattern: /\b429\b/u, label: "http-429" },
|
|
93
|
-
{ pattern: /rate[_-]?limit/iu, label: "rate-limit" },
|
|
94
|
-
{ pattern: /upstream/iu, label: "upstream" },
|
|
95
|
-
{ pattern: /bad gateway/iu, label: "bad-gateway" },
|
|
96
|
-
{ pattern: /gateway timeout/iu, label: "gateway-timeout" },
|
|
97
|
-
{ pattern: /service unavailable/iu, label: "service-unavailable" },
|
|
98
|
-
{ pattern: /temporarily unavailable/iu, label: "temporarily-unavailable" },
|
|
99
|
-
{ pattern: /try again/iu, label: "try-again" }
|
|
100
|
-
];
|
|
101
|
-
const TRANSPORT_UNCERTAIN_PATTERNS = [
|
|
102
|
-
{ pattern: /timed?[ -]?out/iu, label: "timeout" },
|
|
103
|
-
{ pattern: /etimedout/iu, label: "etimedout" },
|
|
104
|
-
{ pattern: /response lost/iu, label: "response-lost" },
|
|
105
|
-
{ pattern: /lost response/iu, label: "lost-response" },
|
|
106
|
-
// A stream-level failure means the response may have been cut mid-turn;
|
|
107
|
-
// the retry path consults durable completion facts before any resend.
|
|
108
|
-
{ pattern: /stream error/iu, label: "stream-error" },
|
|
109
|
-
{ pattern: /stream interrupted/iu, label: "stream-interrupted" },
|
|
110
|
-
{ pattern: /interrupted function/iu, label: "interrupted-function" },
|
|
111
|
-
{ pattern: /controller timeout/iu, label: "controller-timeout" },
|
|
112
|
-
{ pattern: /delivery (unconfirmed|uncertain|not confirmed)/iu, label: "delivery-unconfirmed" },
|
|
113
|
-
{ pattern: /unconfirmed delivery/iu, label: "unconfirmed-delivery" },
|
|
114
|
-
{ pattern: /no response/iu, label: "no-response" }
|
|
115
|
-
];
|
|
116
|
-
const CLASS_TABLE = [
|
|
117
|
-
{ errorClass: "session-dead", patterns: SESSION_DEAD_PATTERNS },
|
|
118
|
-
{ errorClass: "policy-denied", patterns: POLICY_DENIED_PATTERNS },
|
|
119
|
-
{ errorClass: "context-capacity", patterns: CONTEXT_CAPACITY_PATTERNS },
|
|
120
|
-
{ errorClass: "invalid-request", patterns: INVALID_REQUEST_PATTERNS },
|
|
121
|
-
{ errorClass: "transient-provider", patterns: TRANSIENT_PROVIDER_PATTERNS },
|
|
122
|
-
{ errorClass: "transport-uncertain", patterns: TRANSPORT_UNCERTAIN_PATTERNS }
|
|
123
|
-
];
|
|
124
|
-
/**
|
|
125
|
-
* Classifies one provider failure. When the driver produced a structured
|
|
126
|
-
* {@link ProviderErrorCode}, the class is looked up directly. Otherwise the
|
|
127
|
-
* raw text fields are matched against the fallback pattern tables. Every
|
|
128
|
-
* available text field is concatenated so a class can be recognized
|
|
129
|
-
* regardless of which field carried it.
|
|
130
|
-
*/
|
|
131
|
-
export function classifyProviderError(input) {
|
|
132
|
-
// Structured path: the driver already parsed the Provider's error format.
|
|
133
|
-
if (input.errorCode !== undefined) {
|
|
134
|
-
const errorClass = PROVIDER_ERROR_CODE_CLASS[input.errorCode];
|
|
135
|
-
if (errorClass !== undefined) {
|
|
136
|
-
return { errorClass, matched: input.errorCode, basis: "structured" };
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
// Text fallback: for drivers that cannot yet produce a structured code.
|
|
140
|
-
const text = [input.error, input.errorDetails, input.summary]
|
|
141
|
-
.filter((value) => typeof value === "string" && value.length > 0)
|
|
142
|
-
.join("\n");
|
|
143
|
-
if (text.length === 0)
|
|
144
|
-
return { errorClass: "unclassified", matched: "none", basis: "text" };
|
|
145
|
-
for (const { errorClass, patterns } of CLASS_TABLE) {
|
|
146
|
-
for (const { pattern, label } of patterns) {
|
|
147
|
-
if (pattern.test(text))
|
|
148
|
-
return { errorClass, matched: label, basis: "text" };
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
return { errorClass: "unclassified", matched: "none", basis: "text" };
|
|
152
|
-
}
|