@zq-silk/yui 2.1.0 → 2.3.0
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 +8 -2
- package/dist/cli/commandCatalog.js +32 -6
- package/dist/cli/commandDiscovery.js +4 -1
- package/dist/cli/interactionPolicy.js +4 -0
- package/dist/cli.js +23 -3078
- package/dist/commands/taskCommands.js +84 -28
- package/dist/commands/taskIntegrationCommands.js +8 -17
- package/dist/commands/taskUpstreamCommands.js +3 -1
- package/dist/context/runContextPack.js +132 -5
- package/dist/context/sourceRunContext.js +4 -2
- package/dist/context/taskContext.js +6 -1
- package/dist/controlPlaneCli.js +3099 -0
- package/dist/controller/clientRuntime.js +3 -2
- package/dist/controller/fileSchedulerStoreAdapter.js +19 -6
- package/dist/controller/jobControl.js +21 -0
- package/dist/executor/agentExecutor.js +1 -1
- package/dist/executor/effectiveLaunch.js +18 -5
- package/dist/executor/fileRoleLaunchPlanner.js +15 -19
- package/dist/integration/gitIntegrationService.js +58 -82
- package/dist/job/jobCleanupInspection.js +67 -0
- package/dist/message/messageContinuation.js +7 -2
- package/dist/nativeAgent/agent.js +176 -74
- package/dist/nativeAgent/cliDemo.js +37 -0
- package/dist/nativeAgent/codingTools.js +11 -0
- package/dist/nativeAgent/commandTool.js +215 -0
- package/dist/nativeAgent/compactionDemo.js +158 -0
- package/dist/nativeAgent/composition.js +71 -0
- package/dist/nativeAgent/context/budget.js +44 -0
- package/dist/nativeAgent/context/index.js +339 -0
- package/dist/nativeAgent/context/providerCompressor.js +103 -0
- package/dist/nativeAgent/demo.js +12 -1
- package/dist/nativeAgent/evaluation/cases.js +38 -0
- package/dist/nativeAgent/evaluation/checks.js +91 -0
- package/dist/nativeAgent/evaluation/demo.js +19 -0
- package/dist/nativeAgent/evaluation/files.js +54 -0
- package/dist/nativeAgent/evaluation/fixture.js +36 -0
- package/dist/nativeAgent/evaluation/index.js +239 -0
- package/dist/nativeAgent/executionOwner.js +209 -0
- package/dist/nativeAgent/filePatterns.js +170 -0
- package/dist/nativeAgent/fileToolsSupport.js +202 -0
- package/dist/nativeAgent/index.js +13 -0
- package/dist/nativeAgent/interaction/cli.js +358 -0
- package/dist/nativeAgent/interaction/contracts.js +1 -0
- package/dist/nativeAgent/interaction/index.js +3 -0
- package/dist/nativeAgent/interaction/memoryDemo.js +115 -0
- package/dist/nativeAgent/interaction/renderer.js +34 -0
- package/dist/nativeAgent/localSafety.js +258 -0
- package/dist/nativeAgent/model/anthropicMessages.js +204 -0
- package/dist/nativeAgent/model/chatCompletions.js +210 -0
- package/dist/nativeAgent/model/errors.js +47 -0
- package/dist/nativeAgent/model/gateway.js +423 -0
- package/dist/nativeAgent/model/index.js +7 -0
- package/dist/nativeAgent/model/observationAdapter.js +21 -0
- package/dist/nativeAgent/model/protocols.js +19 -0
- package/dist/nativeAgent/model/responses.js +263 -0
- package/dist/nativeAgent/model/types.js +1 -0
- package/dist/nativeAgent/model/wire.js +73 -0
- package/dist/nativeAgent/observability/index.js +220 -0
- package/dist/nativeAgent/product/catalog.js +82 -0
- package/dist/nativeAgent/product/config.js +295 -0
- package/dist/nativeAgent/product/facts.js +30 -0
- package/dist/nativeAgent/product/index.js +62 -0
- package/dist/nativeAgent/product/location.js +44 -0
- package/dist/nativeAgent/product/runtime.js +276 -0
- package/dist/nativeAgent/product/storage.js +49 -0
- package/dist/nativeAgent/product/tools.js +47 -0
- package/dist/nativeAgent/product/transport.js +54 -0
- package/dist/nativeAgent/projectGuidance/index.js +425 -0
- package/dist/nativeAgent/searchTools.js +305 -0
- package/dist/nativeAgent/session/backends.js +293 -0
- package/dist/nativeAgent/session/catalog.js +97 -0
- package/dist/nativeAgent/session/catalogDemo.js +87 -0
- package/dist/nativeAgent/session/contracts.js +1 -0
- package/dist/nativeAgent/session/format.js +269 -0
- package/dist/nativeAgent/session/index.js +5 -0
- package/dist/nativeAgent/session/location.js +36 -0
- package/dist/nativeAgent/session/sqliteFormat.js +134 -0
- package/dist/nativeAgent/session/store.js +248 -0
- package/dist/nativeAgent/textTools.js +270 -133
- package/dist/nativeAgent/toolManager/executor.js +290 -0
- package/dist/nativeAgent/toolManager/index.js +4 -0
- package/dist/nativeAgent/validation.js +2 -2
- package/dist/repository/gitWorkspace.js +41 -12
- package/dist/repository/taskWorkspaceCoordinator.js +72 -145
- package/dist/repository/taskWorkspacePreparer.js +39 -43
- package/dist/repository/workspaceCleanupInspection.js +88 -7
- package/dist/resources/resourceRegistrar.js +16 -10
- package/dist/runtime/integrationRuntimeIsolation.js +21 -0
- package/dist/runtime/taskRuntimeIsolation.js +91 -21
- package/dist/task/archiveDiagnostics.js +26 -8
- package/dist/task/archivePreflight.js +26 -9
- package/dist/task/leaderArchive.js +9 -15
- package/dist/task/taskAuthority.js +56 -0
- package/dist/web/assets/client/api.js +8 -0
- package/dist/web/assets/client/app.js +74 -9
- package/dist/web/assets/client/components.js +95 -36
- package/dist/web/assets/client/detail.js +110 -64
- package/dist/web/assets/client/dock.js +95 -11
- package/dist/web/assets/client/evidence.js +286 -94
- package/dist/web/assets/client/i18n.js +182 -62
- package/dist/web/assets/client/overview.js +9 -10
- package/dist/web/assets/client/records.js +142 -7
- package/dist/web/assets/client/sections.js +234 -198
- package/dist/web/assets/client/sidebar.js +31 -2
- package/dist/web/assets/icons.js +4 -0
- package/dist/web/assets/shell.js +2 -1
- package/dist/web/assets/styles/components.js +64 -15
- package/dist/web/assets/styles/layout.js +11 -4
- package/dist/web/assets/styles/responsive.js +16 -6
- package/dist/web/assets/styles/tokens.js +1 -1
- package/dist/web/assets/styles/views.js +62 -42
- package/dist/web/webServer.js +12 -1
- package/dist/web/webTaskSurface.js +8 -1
- package/docs/agent-result-consumption.md +16 -0
- package/docs/agent-result-consumption.zh-CN.md +13 -0
- package/docs/examples/agent-offline.mjs +194 -0
- package/docs/native-agent.md +283 -0
- package/docs/observability/README.md +13 -3
- package/docs/observability/README.zh-CN.md +10 -3
- package/docs/release-workflow.md +72 -9
- package/docs/release-workflow.zh-CN.md +55 -6
- package/docs/roles-and-configuration.md +32 -0
- package/docs/roles-and-configuration.zh-CN.md +26 -0
- package/docs/task-delivery.md +36 -8
- package/docs/task-delivery.zh-CN.md +24 -7
- package/i18n/README.zh-CN.md +3 -2
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +9 -0
- package/skills/yui-leader/references/execution.md +2 -1
- package/skills/yui-leader/references/integration.md +20 -0
- package/skills/yui-operator/SKILL.md +4 -0
- package/skills/yui-reviewer/SKILL.md +8 -0
- package/skills/yui-runtime/SKILL.md +11 -0
- package/skills/yui-runtime/references/publication.md +20 -4
- package/skills/yui-worker/SKILL.md +3 -0
|
@@ -4,11 +4,12 @@ import { agentExecutionComponentLabel } from "../agent/executionComponents.js";
|
|
|
4
4
|
import { assertLeaderArchiveAdmission } from "../task/leaderArchiveAuthority.js";
|
|
5
5
|
import { createRun, runExecutionObservation, runPurposeAdmitsTaskState } from "../agentRun/agentRun.js";
|
|
6
6
|
import { isGitArtifactRefString, parseGitArtifactRef } from "../artifacts/gitArtifactRef.js";
|
|
7
|
-
import { contextSnapshotRef } from "../context/contextSnapshot.js";
|
|
8
|
-
import {
|
|
7
|
+
import { contextContentDigest, contextSnapshotRef } from "../context/contextSnapshot.js";
|
|
8
|
+
import { sourceRunContextValue } from "../context/sourceRunContext.js";
|
|
9
|
+
import { buildRunContextDelta, buildRunContextPack, contextSnapshotDeltaRefIds, expandRunContextRef, freezeReviewStageContextSnapshot, freezeRunContextSnapshot, freezeWorkItemExecutionAssignmentContextSnapshot, freezeCandidateContextSnapshot, readRunContextSnapshot, synthesisSourceRunIds } from "../context/runContextPack.js";
|
|
9
10
|
import { createRunInput } from "../context/runInputContract.js";
|
|
10
11
|
import { parseTaskCatalogOptions, readTaskCatalog, renderTaskCatalog } from "../context/taskCatalog.js";
|
|
11
|
-
import { assertContextRecordReadable } from "../context/taskContext.js";
|
|
12
|
+
import { assertContextRecordReadable, readTaskContextResource } from "../context/taskContext.js";
|
|
12
13
|
import { boundedDocument, readOptions, messageReceipt, recordPage } from "../output/boundedRead.js";
|
|
13
14
|
import { referencedWakeRunIds } from "../context/wakeRunReferences.js";
|
|
14
15
|
import { completeProcessing, releaseProcessing } from "../coordination/workMailbox.js";
|
|
@@ -19,7 +20,7 @@ import { createExecutionGroup, createReviewExecutionAssignment, createWorkItemEx
|
|
|
19
20
|
import { projectWorkItemExecution } from "../execution/workItemExecutionProjection.js";
|
|
20
21
|
import { dispatchWorkItemSynthesis, selectedWorkItemSynthesisProducers } from "../execution/workItemMainRun.js";
|
|
21
22
|
import { createRoleSessionSet, roleAgentSessionResumeMode, roleSessionControlTarget, updateTaskRoleProviderRuntime } from "../executor/agentExecutor.js";
|
|
22
|
-
import { resolveEffectiveLaunch } from "../executor/effectiveLaunch.js";
|
|
23
|
+
import { resolveEffectiveLaunch, effectiveLaunchWithTaskMainWorkspace } from "../executor/effectiveLaunch.js";
|
|
23
24
|
import { cancelInputRequest } from "../input/inputRequest.js";
|
|
24
25
|
import { retireExactActiveRun, terminalizeExactTaskRun, validateExactRunReviewRound } from "../lifecycle/exactRunTerminalization.js";
|
|
25
26
|
import { resolveTaskInputControl } from "../message/inputControlResolution.js";
|
|
@@ -54,7 +55,7 @@ import { queueLeaderWakeup } from "../scheduler/wakeupQueue.js";
|
|
|
54
55
|
import { planningRuntimeCwd } from "../storage/homeLayout.js";
|
|
55
56
|
import { StorageConflictError } from "../storage/taskStore.js";
|
|
56
57
|
import { archiveDeliveryWarnings, archiveRetainedResources, renderArchiveDiagnostics, taskArchiveDiagnostics } from "../task/archiveDiagnostics.js";
|
|
57
|
-
import { archiveSettlementChecks } from "../task/archivePreflight.js";
|
|
58
|
+
import { archiveExecutionChecks, archiveSettlementChecks } from "../task/archivePreflight.js";
|
|
58
59
|
import { projectCompletionReadiness } from "../task/completionReadiness.js";
|
|
59
60
|
import { assertDraftTaskExecutionFree, validateDraftWorkItemEdit } from "../task/draftPlan.js";
|
|
60
61
|
import { assertTaskRemoteDeliveryProof, projectTaskRemoteDeliveryFromStore } from "../task/remoteDeliveryService.js";
|
|
@@ -1299,12 +1300,9 @@ function archiveTaskCommand(args, store, options) {
|
|
|
1299
1300
|
? assertTaskRemoteDeliveryProof(tx, task, options.archiveRemoteDeliveryProof)
|
|
1300
1301
|
: undefined;
|
|
1301
1302
|
if (!request.force) {
|
|
1302
|
-
const checks = archiveSettlementChecks(tx, task);
|
|
1303
|
+
const checks = [...archiveSettlementChecks(tx, task), ...archiveExecutionChecks(tx, task.id, options.yuiHome)];
|
|
1303
1304
|
if (checks.length > 0)
|
|
1304
1305
|
throw new CleanupInspectionError(checks);
|
|
1305
|
-
if (task.cwd !== undefined || tx.listManagedWorkspaces(task.id).length > 0) {
|
|
1306
|
-
throw usageError(`Task ${task.id} still has managed worktrees; clean them before archiving.`);
|
|
1307
|
-
}
|
|
1308
1306
|
const activeRole = tx.listRoles(task.id)
|
|
1309
1307
|
.find((role) => tx.getActiveRun(task.id, role.name) !== null);
|
|
1310
1308
|
if (activeRole !== undefined) {
|
|
@@ -1321,7 +1319,7 @@ function archiveTaskCommand(args, store, options) {
|
|
|
1321
1319
|
+ "stop that Session before archiving.");
|
|
1322
1320
|
}
|
|
1323
1321
|
}
|
|
1324
|
-
const retainedResources =
|
|
1322
|
+
const retainedResources = archiveRetainedResources(tx, task);
|
|
1325
1323
|
const warnings = request.force && remoteDelivery !== undefined ? archiveDeliveryWarnings(remoteDelivery) : [];
|
|
1326
1324
|
const archived = { ...archiveTask(task, now, { by: actor }), executionGate: { state: "stopped" } };
|
|
1327
1325
|
tx.saveTask(archived);
|
|
@@ -1350,8 +1348,9 @@ function archiveTaskCommand(args, store, options) {
|
|
|
1350
1348
|
authorizationSource: JSON.stringify(options.archiveLeaderAdmission.source)
|
|
1351
1349
|
}),
|
|
1352
1350
|
workspaceDisposition: request.disposition,
|
|
1351
|
+
cleanup: "pending",
|
|
1353
1352
|
...(request.force ? {
|
|
1354
|
-
force: "true",
|
|
1353
|
+
force: "true",
|
|
1355
1354
|
warnings: JSON.stringify(warnings),
|
|
1356
1355
|
retainedResources: JSON.stringify(retainedResources)
|
|
1357
1356
|
} : {}),
|
|
@@ -3412,6 +3411,7 @@ function updateWork(args, store, options) {
|
|
|
3412
3411
|
: { taskMainSnapshot: options.directTaskMainSnapshot })
|
|
3413
3412
|
}, now);
|
|
3414
3413
|
tx.saveWorkItem(task.id, updated);
|
|
3414
|
+
freezeCandidateContextSnapshot(tx, updated.candidates.at(-1), now);
|
|
3415
3415
|
recordTaskEvent(tx, task.id, "work.updated", {
|
|
3416
3416
|
workItemId: updated.id,
|
|
3417
3417
|
status: updated.status,
|
|
@@ -3463,8 +3463,8 @@ export function requireWorkItemAssignee(item) {
|
|
|
3463
3463
|
return item.assignee;
|
|
3464
3464
|
}
|
|
3465
3465
|
function dispatchWork(args, store, options) {
|
|
3466
|
-
const usage = "Task work dispatch usage: yui task work dispatch <task>/<work> [--input <text>] [--lane-role <role> ...].";
|
|
3467
|
-
const parsed = parseMultiValueTail(args, new Set(["--input"]), new Set(["--lane-role"]), usage);
|
|
3466
|
+
const usage = "Task work dispatch usage: yui task work dispatch <task>/<work> [--input <text>] [--context-ref <store/refId@digest> ...] [--lane-role <role> ...].";
|
|
3467
|
+
const parsed = parseMultiValueTail(args, new Set(["--input"]), new Set(["--lane-role", "--context-ref"]), usage);
|
|
3468
3468
|
exactPositionals(parsed.positionals, 1, usage);
|
|
3469
3469
|
const requestedLaneRoles = parsed.multiOptions.get("--lane-role") ?? [];
|
|
3470
3470
|
const now = clock(options);
|
|
@@ -3472,6 +3472,7 @@ function dispatchWork(args, store, options) {
|
|
|
3472
3472
|
const item = requireWorkItem(tx, parsed.positionals[0], options);
|
|
3473
3473
|
const task = requireTask(tx, item.taskId);
|
|
3474
3474
|
taskActor(tx, options, task.id);
|
|
3475
|
+
const requiredResources = readDispatchContextRefs(tx, task.id, parsed.multiOptions.get("--context-ref") ?? [], options.environment);
|
|
3475
3476
|
if (task.status !== "active")
|
|
3476
3477
|
throw usageError(inactiveTaskMessage(task, "dispatch"));
|
|
3477
3478
|
assertTaskExecutionEnabled(task, "dispatching work");
|
|
@@ -3531,7 +3532,7 @@ function dispatchWork(args, store, options) {
|
|
|
3531
3532
|
purpose: "execution",
|
|
3532
3533
|
workItemId: item.id,
|
|
3533
3534
|
workspace
|
|
3534
|
-
}, now, "controller");
|
|
3535
|
+
}, now, "controller", undefined, undefined, requiredResources);
|
|
3535
3536
|
const run = createRun(runId, task.id, role.name, roleAgentSessionResumeMode(tx.getTaskRoleSessionSet(task.id, role.name), effective.agentId, effective), createRunInput({
|
|
3536
3537
|
source: { type: "yui", channel: "workitem-dispatch" },
|
|
3537
3538
|
directive: rawInput,
|
|
@@ -3563,7 +3564,8 @@ function dispatchWork(args, store, options) {
|
|
|
3563
3564
|
const assignmentContext = contextSnapshotRef(freezeWorkItemExecutionAssignmentContextSnapshot(tx, {
|
|
3564
3565
|
taskId: task.id,
|
|
3565
3566
|
workItemId: item.id,
|
|
3566
|
-
executionGroupId: groupId
|
|
3567
|
+
executionGroupId: groupId,
|
|
3568
|
+
requiredResources
|
|
3567
3569
|
}, now));
|
|
3568
3570
|
const plans = roles.map((role, index) => {
|
|
3569
3571
|
const laneId = `${groupId}-lane-${index + 1}`;
|
|
@@ -3668,6 +3670,45 @@ function dispatchWork(args, store, options) {
|
|
|
3668
3670
|
? `Direct WorkItem AgentRun queued as ${dispatch.runs[0].id}\n`
|
|
3669
3671
|
: `Dispatch queued for ${dispatch.runs.length} replicated Lanes\n`;
|
|
3670
3672
|
}
|
|
3673
|
+
/** Explicit, bounded reads; prose never grants access or selects records. */
|
|
3674
|
+
export function readDispatchContextRefs(store, taskId, selectors, environment = {}) {
|
|
3675
|
+
if (selectors.length > 16 || new Set(selectors).size !== selectors.length) {
|
|
3676
|
+
throw usageError("Dispatch requires at most 16 distinct --context-ref values.");
|
|
3677
|
+
}
|
|
3678
|
+
return selectors.flatMap(selector => {
|
|
3679
|
+
const match = /^([^/]+)\/(.+)@([0-9a-f]{64})$/u.exec(selector);
|
|
3680
|
+
if (match === null) {
|
|
3681
|
+
throw usageError(`Invalid required Context reference: ${selector}. Use store/refId@digest from task context list/inspect.`);
|
|
3682
|
+
}
|
|
3683
|
+
const [, family, refId, digest] = match;
|
|
3684
|
+
try {
|
|
3685
|
+
const entry = readTaskContextResource(store, taskId, {
|
|
3686
|
+
store: family, refId: refId, digest: digest
|
|
3687
|
+
}, environment);
|
|
3688
|
+
const resources = [{
|
|
3689
|
+
ref: { ...entry.ref, layer: "L4", evidenceOf: "dispatch-required" },
|
|
3690
|
+
value: entry.value
|
|
3691
|
+
}];
|
|
3692
|
+
// Selecting a result Message selects its already-authorized original
|
|
3693
|
+
// result too, not just a pointer the receiving Assignment cannot expand.
|
|
3694
|
+
if (family === "task-message" && "result" in entry) {
|
|
3695
|
+
const message = entry.value;
|
|
3696
|
+
const source = store.getRun(taskId, message.resultRef.runId);
|
|
3697
|
+
const value = sourceRunContextValue(source);
|
|
3698
|
+
resources.push({
|
|
3699
|
+
ref: { layer: "L4", store: "source-run", refId: source.id,
|
|
3700
|
+
revision: source.updatedAt, digest: contextContentDigest(value),
|
|
3701
|
+
evidenceOf: "dispatch-required", summary: `Original result for Message ${message.id}` },
|
|
3702
|
+
value
|
|
3703
|
+
});
|
|
3704
|
+
}
|
|
3705
|
+
return resources;
|
|
3706
|
+
}
|
|
3707
|
+
catch (error) {
|
|
3708
|
+
throw usageError(`Required Context reference ${selector} cannot be frozen: ${error instanceof Error ? error.message : String(error)} Read an authorized current reference, correct the selection or include the requirement in the WorkItem, then dispatch again.`);
|
|
3709
|
+
}
|
|
3710
|
+
});
|
|
3711
|
+
}
|
|
3671
3712
|
function replicatedProducerAssignmentInput(input, requiresCodeRef) {
|
|
3672
3713
|
return [
|
|
3673
3714
|
input,
|
|
@@ -5051,12 +5092,20 @@ function retryRunOperation(args, store, options) {
|
|
|
5051
5092
|
throw dataError(`AgentRun ${previous.id} direct WorkItem workspace is missing or has drifted.`);
|
|
5052
5093
|
}
|
|
5053
5094
|
}
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5095
|
+
// Direct Task delivery resumes the native Session's captured authority.
|
|
5096
|
+
// New source/Role defaults are adopted only after formal replacement.
|
|
5097
|
+
const directSession = retryItem === null && previous.purpose === "execution"
|
|
5098
|
+
&& retryManagedWorkspace?.owner.type === "task"
|
|
5099
|
+
? sessions?.sessions[role.activeAgentId] : undefined;
|
|
5100
|
+
const effective = retryLane?.effective
|
|
5101
|
+
?? (directSession === undefined ? undefined
|
|
5102
|
+
: effectiveLaunchWithTaskMainWorkspace(directSession.effective, retryManagedWorkspace))
|
|
5103
|
+
?? resolveEffectiveLaunch({
|
|
5104
|
+
role,
|
|
5105
|
+
purpose: previous.purpose,
|
|
5106
|
+
...(retryManagedWorkspace === undefined ? {} : { workspace: retryManagedWorkspace }),
|
|
5107
|
+
...(retryItem === null ? {} : { workItemWriteProjectIds: retryItem.writeProjectIds })
|
|
5108
|
+
});
|
|
5060
5109
|
const runId = tx.nextRunId(task.id);
|
|
5061
5110
|
const runningGroup = retryGroup === undefined || retryLane === undefined
|
|
5062
5111
|
? undefined
|
|
@@ -5082,13 +5131,19 @@ function retryRunOperation(args, store, options) {
|
|
|
5082
5131
|
const input = retriesSynthesisMain
|
|
5083
5132
|
? previous.inputs[0].input
|
|
5084
5133
|
: (() => {
|
|
5134
|
+
// A retry keeps the explicit frozen handoff, not today's mutable
|
|
5135
|
+
// versions of those records. Legacy Runs without a Snapshot retain
|
|
5136
|
+
// the existing explicit recovery from current facts.
|
|
5137
|
+
const requiredResources = previous.inputs[0].input.contextSnapshotRef === undefined
|
|
5138
|
+
? []
|
|
5139
|
+
: readRunContextSnapshot(tx, previous).resources.filter(entry => entry.ref.evidenceOf === "dispatch-required");
|
|
5085
5140
|
const retrySnapshot = freezeRunContextSnapshot(tx, {
|
|
5086
5141
|
taskId: task.id,
|
|
5087
5142
|
roleName: role.name,
|
|
5088
5143
|
purpose: previous.purpose,
|
|
5089
5144
|
...(retryManagedWorkspace === undefined ? {} : { workspace: retryManagedWorkspace }),
|
|
5090
5145
|
...(previous.workItemId === undefined ? {} : { workItemId: previous.workItemId })
|
|
5091
|
-
}, now, "controller", retryGroup?.assignment.contextSnapshotRef);
|
|
5146
|
+
}, now, "controller", retryGroup?.assignment.contextSnapshotRef, undefined, requiredResources, "frozen");
|
|
5092
5147
|
return createRunInput({
|
|
5093
5148
|
source: {
|
|
5094
5149
|
type: "yui",
|
|
@@ -5211,12 +5266,13 @@ function taskReviewProvenance(store, task, options, expected) {
|
|
|
5211
5266
|
break;
|
|
5212
5267
|
}
|
|
5213
5268
|
}
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
|
|
5269
|
+
const target = store.getTaskWorkspace(task.id)?.entries.find(entry => entry.projectId === projectId)?.branch ?? committedAttempts[headIndex]?.targetRef;
|
|
5270
|
+
// A direct Task-main repair has no Integration at its new head. It is
|
|
5271
|
+
// still reviewable; conservatively exclude prior producers on this target
|
|
5272
|
+
// from reviewing it. This is an independence fence, not ancestry or proof
|
|
5273
|
+
// that any prior report validates the current head.
|
|
5274
|
+
const lineage = (headIndex < 0 ? committedAttempts : committedAttempts.slice(0, headIndex + 1))
|
|
5275
|
+
.filter(({ targetRef }) => targetRef === target);
|
|
5220
5276
|
for (const committed of lineage) {
|
|
5221
5277
|
if (committed.source.kind !== "work-item")
|
|
5222
5278
|
continue;
|
|
@@ -7,6 +7,7 @@ import { NodeGitWorkspace } from "../repository/gitWorkspace.js";
|
|
|
7
7
|
import { assertProjectActive, resolveProject } from "../repository/project.js";
|
|
8
8
|
import { FileTaskWorkspacePreparer } from "../repository/taskWorkspacePreparer.js";
|
|
9
9
|
import { assertTaskDeliveryAuthority as taskLocalActor } from "../task/taskAuthority.js";
|
|
10
|
+
import { taskIntegrationTargetCheckout } from "../task/taskAuthority.js";
|
|
10
11
|
import { resolveTaskRecordReference } from "../task/taskRecordReference.js";
|
|
11
12
|
import { governingWorkItemCandidate } from "../workItem/workItem.js";
|
|
12
13
|
import { workspaceProjectEntry } from "../worktree/managedWorkspace.js";
|
|
@@ -48,19 +49,8 @@ async function cleanupIntegration(args, store, home, environment) {
|
|
|
48
49
|
&& integration.status !== "failed") {
|
|
49
50
|
throw usageError(`Integration is not terminal: ${integration.id}/${integration.status}.`);
|
|
50
51
|
}
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
// running, and unacknowledged unknown-needs-attention jobs owned by it.
|
|
54
|
-
const activeIntegrationJob = store.listDurableJobs(integration.taskId).find((job) => (job.owner.kind === "integration-attempt"
|
|
55
|
-
&& job.owner.integrationAttemptId === integration.id
|
|
56
|
-
&& (job.status === "queued"
|
|
57
|
-
|| job.status === "running"
|
|
58
|
-
|| (job.status === "unknown-needs-attention" && job.acknowledgedAt === undefined))));
|
|
59
|
-
if (activeIntegrationJob !== undefined) {
|
|
60
|
-
throw usageError(`Integration ${integration.id} has an active DurableJob: `
|
|
61
|
-
+ `${activeIntegrationJob.id}/${activeIntegrationJob.status}. `
|
|
62
|
-
+ "Cancel or acknowledge it before cleanup.");
|
|
63
|
-
}
|
|
52
|
+
// The service's shared owner inspection checks both Job settlement and
|
|
53
|
+
// current physical occupancy before any runtime or worktree is released.
|
|
64
54
|
const result = await new GitIntegrationService(home, store).cleanup(integration, {
|
|
65
55
|
authorize: () => taskLocalActor(store, environment, integration.taskId)
|
|
66
56
|
});
|
|
@@ -69,9 +59,9 @@ async function cleanupIntegration(args, store, home, environment) {
|
|
|
69
59
|
}
|
|
70
60
|
return {
|
|
71
61
|
output: result === "removed"
|
|
72
|
-
? `Cleaned Integration worktree and check logs
|
|
73
|
-
: `Integration worktree
|
|
74
|
-
data: { integrationId: integration.id, cleanup: result }
|
|
62
|
+
? `Cleaned Integration worktree ${integration.id}; history and check logs retained\n`
|
|
63
|
+
: `Integration worktree already clean: ${integration.id}; history and check logs retained\n`,
|
|
64
|
+
data: { integrationId: integration.id, cleanup: result, historyRetained: true }
|
|
75
65
|
};
|
|
76
66
|
}
|
|
77
67
|
async function start(args, store, home, now, options) {
|
|
@@ -132,6 +122,7 @@ async function start(args, store, home, now, options) {
|
|
|
132
122
|
if (targetRef === undefined) {
|
|
133
123
|
throw usageError(`Task main worktree is not ready; reconcile the Task first: ${task.id}.`);
|
|
134
124
|
}
|
|
125
|
+
taskIntegrationTargetCheckout(store, options.environment, task.id, project.id, targetRef);
|
|
135
126
|
const expectedHead = (await new NodeGitWorkspace().inspect(mainEntry.path, targetRef)).baseCommit;
|
|
136
127
|
const snapshotEntry = candidate.workspace.entries.find(({ projectId }) => projectId === project.id);
|
|
137
128
|
const resultCommit = candidate.gitSnapshot.projects.find(({ projectId }) => projectId === project.id)?.commit;
|
|
@@ -139,7 +130,7 @@ async function start(args, store, home, now, options) {
|
|
|
139
130
|
throw usageError(`WorkItem result Project snapshot is incomplete: ${workItem.id}/${project.id}.`);
|
|
140
131
|
}
|
|
141
132
|
const integration = store.transaction((tx) => {
|
|
142
|
-
|
|
133
|
+
taskIntegrationTargetCheckout(tx, options.environment, task.id, project.id, targetRef);
|
|
143
134
|
const created = createIntegrationAttempt({
|
|
144
135
|
id: tx.nextIntegrationAttemptId(task.id),
|
|
145
136
|
taskId: task.id,
|
|
@@ -6,7 +6,7 @@ import { createIntegrationAttempt } from "../integration/integrationAttempt.js";
|
|
|
6
6
|
import { NodeGitWorkspace } from "../repository/gitWorkspace.js";
|
|
7
7
|
import { FileTaskWorkspacePreparer } from "../repository/taskWorkspacePreparer.js";
|
|
8
8
|
import { workspaceProjectEntry } from "../worktree/managedWorkspace.js";
|
|
9
|
-
import { taskLocalActor } from "../task/taskAuthority.js";
|
|
9
|
+
import { taskLocalActor, assertTaskProjectWriteAuthority } from "../task/taskAuthority.js";
|
|
10
10
|
export async function runTaskUpstreamCommand(args, store, home, options = {}) {
|
|
11
11
|
const [command, ...rest] = args;
|
|
12
12
|
if (command === "integrate")
|
|
@@ -71,6 +71,7 @@ async function integrateUpstream(args, store, home, options) {
|
|
|
71
71
|
let phase = "prepare";
|
|
72
72
|
let integrationId;
|
|
73
73
|
try {
|
|
74
|
+
assertTaskProjectWriteAuthority(store, options.environment, task.id, binding.projectId);
|
|
74
75
|
const project = store.getProject(binding.projectId);
|
|
75
76
|
if (project === null)
|
|
76
77
|
throw usageError(`Project not found: ${binding.projectId}.`);
|
|
@@ -94,6 +95,7 @@ async function integrateUpstream(args, store, home, options) {
|
|
|
94
95
|
branch: binding.baseRef
|
|
95
96
|
});
|
|
96
97
|
const attempt = store.transaction((tx) => {
|
|
98
|
+
assertTaskProjectWriteAuthority(tx, options.environment, task.id, binding.projectId);
|
|
97
99
|
const created = createIntegrationAttempt({
|
|
98
100
|
id: tx.nextIntegrationAttemptId(task.id),
|
|
99
101
|
taskId: task.id,
|
|
@@ -10,7 +10,112 @@ import { managedWorkspaceKey } from "../worktree/managedWorkspace.js";
|
|
|
10
10
|
import { contextContentDigest, contextSnapshotRef, createContextSnapshot, validateContextSnapshot } from "./contextSnapshot.js";
|
|
11
11
|
import { MAX_SYNTHESIS_SOURCE_RUNS, sourceRunContextValue } from "./sourceRunContext.js";
|
|
12
12
|
export const RUN_CONTEXT_PACK_SCHEMA_VERSION = 1;
|
|
13
|
-
|
|
13
|
+
function mergeRequiredContext(automatic, required, requiredPolicy = "current") {
|
|
14
|
+
const entries = new Map(automatic.map(entry => [`${entry.ref.store}/${entry.ref.refId}`, entry]));
|
|
15
|
+
for (const entry of required) {
|
|
16
|
+
const key = `${entry.ref.store}/${entry.ref.refId}`;
|
|
17
|
+
const existing = entries.get(key);
|
|
18
|
+
if (requiredPolicy === "current" && existing !== undefined && existing.ref.digest !== entry.ref.digest) {
|
|
19
|
+
throw new Error(`Required Context changed during dispatch: ${key}. Read its current reference and dispatch again.`);
|
|
20
|
+
}
|
|
21
|
+
entries.set(key, entry);
|
|
22
|
+
}
|
|
23
|
+
return [...entries.values()];
|
|
24
|
+
}
|
|
25
|
+
/** Pin the original result together with the candidate, using the existing
|
|
26
|
+
* immutable Snapshot store rather than a second result/provenance ledger. */
|
|
27
|
+
export function freezeCandidateContextSnapshot(store, candidate, now) {
|
|
28
|
+
if (candidate.source.type !== "run")
|
|
29
|
+
return undefined;
|
|
30
|
+
const source = store.getRun(candidate.taskId, candidate.source.runId);
|
|
31
|
+
if (source === null || source.taskId !== candidate.taskId
|
|
32
|
+
|| source.workItemId !== candidate.workItemId || source.purpose !== "execution"
|
|
33
|
+
|| source.status !== "completed" || source.result === undefined
|
|
34
|
+
|| Date.parse(source.updatedAt) > Date.parse(candidate.createdAt)) {
|
|
35
|
+
throw new Error(`Candidate source report is missing or mismatched: ${candidate.workItemId}/${candidate.id}.`);
|
|
36
|
+
}
|
|
37
|
+
const evidenceOf = `${candidate.workItemId}/${candidate.id}`;
|
|
38
|
+
const report = materialize("L4", "source-run", source.id, sourceRunContextValue(source));
|
|
39
|
+
const resources = [
|
|
40
|
+
materialize("L3", "candidate", evidenceOf, candidate),
|
|
41
|
+
{ ...report, ref: { ...report.ref, evidenceOf } }
|
|
42
|
+
];
|
|
43
|
+
const snapshot = createContextSnapshot({
|
|
44
|
+
id: store.nextContextSnapshotId(candidate.taskId),
|
|
45
|
+
taskId: candidate.taskId, scope: "workitem", scopeRef: `candidate:${evidenceOf}`,
|
|
46
|
+
sequence: 1, refs: resources.map(({ ref }) => ref), resources, acceptRefs: [],
|
|
47
|
+
frozenAt: now, frozenBy: "controller"
|
|
48
|
+
});
|
|
49
|
+
store.saveContextSnapshot(snapshot);
|
|
50
|
+
return snapshot;
|
|
51
|
+
}
|
|
52
|
+
function candidateReviewContext(store, candidate) {
|
|
53
|
+
const identity = `${candidate.workItemId}/${candidate.id}`;
|
|
54
|
+
if (candidate.source.type === "direct") {
|
|
55
|
+
return [materialize("L3", "candidate", identity, candidate)];
|
|
56
|
+
}
|
|
57
|
+
const sourceRunId = candidate.source.runId;
|
|
58
|
+
const snapshots = store.listContextSnapshots(candidate.taskId).filter(snapshot => snapshot.scope === "workitem" && snapshot.scopeRef === `candidate:${identity}`);
|
|
59
|
+
if (snapshots.length !== 1) {
|
|
60
|
+
throw new Error(`Frozen candidate report is unavailable: ${identity}. Inspect source Run ${candidate.taskId}/${sourceRunId}; for a new Review use newly authorized delivery with a newly captured Candidate. Historical Snapshots are not rewritten.`);
|
|
61
|
+
}
|
|
62
|
+
const snapshot = validateContextSnapshot(snapshots[0]);
|
|
63
|
+
const proof = snapshot.resources.find(({ ref }) => ref.store === "candidate" && ref.refId === identity);
|
|
64
|
+
const report = snapshot.resources.find(({ ref }) => ref.store === "source-run"
|
|
65
|
+
&& ref.refId === sourceRunId && ref.evidenceOf === identity);
|
|
66
|
+
const source = store.getRun(candidate.taskId, sourceRunId);
|
|
67
|
+
if (proof?.ref.digest !== contextContentDigest(candidate) || report === undefined
|
|
68
|
+
|| source === null || source.status !== "completed" || source.result === undefined
|
|
69
|
+
|| source.taskId !== candidate.taskId || source.workItemId !== candidate.workItemId
|
|
70
|
+
|| source.purpose !== "execution"
|
|
71
|
+
|| report.ref.digest !== contextContentDigest(sourceRunContextValue(source))) {
|
|
72
|
+
throw new Error(`Frozen candidate source/report drifted: ${identity}. Inspect the exact source and capture a new Candidate; do not substitute a newer result.`);
|
|
73
|
+
}
|
|
74
|
+
return [proof, report];
|
|
75
|
+
}
|
|
76
|
+
/** Reuse only exact head/target evidence. Temporal ordering and a shared branch
|
|
77
|
+
* name do not prove ancestry; absent proof is a reviewable evidence gap. */
|
|
78
|
+
function taskReviewCandidateSources(store, taskId, heads) {
|
|
79
|
+
const selected = new Map();
|
|
80
|
+
const select = (candidate) => selected.set(`${candidate.workItemId}/${candidate.id}`, candidate);
|
|
81
|
+
const workspace = store.getTaskWorkspace(taskId);
|
|
82
|
+
const attempts = store.listIntegrationAttempts(taskId);
|
|
83
|
+
const items = store.listWorkItems(taskId);
|
|
84
|
+
const unmatchedHeads = [];
|
|
85
|
+
for (const { projectId, commit } of heads.projects) {
|
|
86
|
+
const targetRef = workspace?.entries.find(entry => entry.projectId === projectId)?.branch;
|
|
87
|
+
let matched = false;
|
|
88
|
+
for (const attempt of attempts.filter(entry => entry.projectId === projectId
|
|
89
|
+
&& entry.status === "committed" && entry.candidateCommit === commit
|
|
90
|
+
&& entry.targetRef === targetRef)) {
|
|
91
|
+
if (attempt.source.kind !== "work-item")
|
|
92
|
+
continue;
|
|
93
|
+
const source = attempt.source;
|
|
94
|
+
const item = store.getWorkItem(taskId, source.workItemId);
|
|
95
|
+
const candidate = [...(item?.candidates ?? [])].reverse().find(entry => entry.gitSnapshot?.projects.some(project => project.projectId === projectId && project.commit === source.resultCommit));
|
|
96
|
+
if (candidate !== undefined) {
|
|
97
|
+
select(candidate);
|
|
98
|
+
matched = true;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
for (const item of items) {
|
|
102
|
+
const candidate = [...item.candidates].reverse().find(entry => entry.taskMainSnapshot?.projects.some(project => project.projectId === projectId && project.headCommit === commit
|
|
103
|
+
&& project.branch === targetRef)
|
|
104
|
+
|| entry.gitSnapshot?.projects.some(project => project.projectId === projectId && project.commit === commit));
|
|
105
|
+
if (candidate !== undefined) {
|
|
106
|
+
select(candidate);
|
|
107
|
+
matched = true;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (!matched)
|
|
111
|
+
unmatchedHeads.push(`${projectId}@${commit}`);
|
|
112
|
+
}
|
|
113
|
+
return { candidates: [...selected.values()], unmatchedHeads };
|
|
114
|
+
}
|
|
115
|
+
export function freezeRunContextSnapshot(store, run, now, frozenBy = "controller", baselineRef, sourceRunIds, requiredResources = [],
|
|
116
|
+
// Only retry of a validated prior Snapshot inherits frozen values over live
|
|
117
|
+
// automatic context; a new dispatch must still match current references.
|
|
118
|
+
requiredPolicy = "current") {
|
|
14
119
|
if (baselineRef !== undefined) {
|
|
15
120
|
const baseline = store.getContextSnapshot(run.taskId, baselineRef.id);
|
|
16
121
|
if (baseline === null
|
|
@@ -28,7 +133,7 @@ export function freezeRunContextSnapshot(store, run, now, frozenBy = "controller
|
|
|
28
133
|
...collectRunContextOverlays(store, run),
|
|
29
134
|
...collectSourceRunContext(store, run, sourceRunIds)
|
|
30
135
|
];
|
|
31
|
-
const resources = [...new Map([...baseline.resources, ...overlays].map((entry) => [
|
|
136
|
+
const resources = [...new Map(mergeRequiredContext([...baseline.resources, ...overlays], requiredResources, requiredPolicy).map((entry) => [
|
|
32
137
|
contextRefIdentity(entry.ref),
|
|
33
138
|
entry
|
|
34
139
|
])).values()].sort((left, right) => (contextRefIdentity(left.ref).localeCompare(contextRefIdentity(right.ref))));
|
|
@@ -60,7 +165,7 @@ export function freezeRunContextSnapshot(store, run, now, frozenBy = "controller
|
|
|
60
165
|
? "workitem"
|
|
61
166
|
: "task";
|
|
62
167
|
const scopeRef = run.reviewRoundId ?? run.workItemId;
|
|
63
|
-
const materialized = collectAuthorizedContext(store, run);
|
|
168
|
+
const materialized = mergeRequiredContext(collectAuthorizedContext(store, run), requiredResources, requiredPolicy);
|
|
64
169
|
const previous = store.listContextSnapshots(run.taskId)
|
|
65
170
|
.filter((candidate) => candidate.scope === scope && candidate.scopeRef === scopeRef)
|
|
66
171
|
.sort((left, right) => left.sequence - right.sequence)
|
|
@@ -117,7 +222,7 @@ export function freezeWorkItemExecutionAssignmentContextSnapshot(store, input, n
|
|
|
117
222
|
materialized.push(materialize("L1", "project-knowledge", `${project.id}:${entry.id}`, { projectId: project.id, ...entry }));
|
|
118
223
|
}
|
|
119
224
|
}
|
|
120
|
-
const resources = [...new Map(materialized.map((entry) => [
|
|
225
|
+
const resources = [...new Map(mergeRequiredContext(materialized, input.requiredResources ?? []).map((entry) => [
|
|
121
226
|
contextRefIdentity(entry.ref),
|
|
122
227
|
entry
|
|
123
228
|
])).values()].sort((left, right) => (contextRefIdentity(left.ref).localeCompare(contextRefIdentity(right.ref))));
|
|
@@ -365,7 +470,14 @@ function collectAuthorizedContext(store, run) {
|
|
|
365
470
|
const round = store.getReviewRound(task.id, run.reviewRoundId);
|
|
366
471
|
if (round === null)
|
|
367
472
|
throw new Error(`AgentRun ReviewRound not found: ${run.reviewRoundId}.`);
|
|
368
|
-
|
|
473
|
+
let roundContext = materialize("L3", "review-round", round.id, round);
|
|
474
|
+
if (round.scope === "work-item") {
|
|
475
|
+
const item = store.getWorkItem(task.id, round.workItemId);
|
|
476
|
+
const candidate = item?.candidates.find(({ id }) => id === round.candidateId);
|
|
477
|
+
if (candidate === undefined)
|
|
478
|
+
throw new Error(`Review candidate is unavailable: ${round.candidateId}.`);
|
|
479
|
+
result.push(...candidateReviewContext(store, candidate));
|
|
480
|
+
}
|
|
369
481
|
if (round.scope === "task") {
|
|
370
482
|
for (const item of store.listWorkItems(task.id).filter(({ status }) => status !== "retired")) {
|
|
371
483
|
const candidate = governingWorkItemCandidate(item);
|
|
@@ -374,7 +486,22 @@ function collectAuthorizedContext(store, run) {
|
|
|
374
486
|
result.push(materialize("L3", "candidate", `${item.id}/${candidate.id}`, candidate));
|
|
375
487
|
result.push(...candidateArtifacts(task.id, [candidate]));
|
|
376
488
|
}
|
|
489
|
+
const evidence = taskReviewCandidateSources(store, task.id, round.taskCandidate);
|
|
490
|
+
// Existing pointer metadata exposes the gap without changing the Round,
|
|
491
|
+
// inventing validation, or adding another persisted evidence record.
|
|
492
|
+
roundContext = {
|
|
493
|
+
...roundContext, ref: {
|
|
494
|
+
...roundContext.ref,
|
|
495
|
+
summary: `Task-final Review ${round.id}. Producer reports are evidence only for their named Candidate, not validation of the entire Task head.${evidence.unmatchedHeads.length === 0 ? ""
|
|
496
|
+
: ` Producer evidence gap: ${evidence.unmatchedHeads.join(", ")}. Review these fixed heads and report missing validation; the gap does not prohibit review.`}`
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
for (const candidate of evidence.candidates) {
|
|
500
|
+
result.push(...candidateReviewContext(store, candidate));
|
|
501
|
+
result.push(...candidateArtifacts(task.id, [candidate]));
|
|
502
|
+
}
|
|
377
503
|
}
|
|
504
|
+
result.push(roundContext);
|
|
378
505
|
if (round.deltaRecheck !== undefined) {
|
|
379
506
|
const previous = store.getReviewRound(task.id, round.deltaRecheck.previousReviewRoundId);
|
|
380
507
|
const previousRun = previous?.reviewerRunId === undefined
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { MAX_RUN_RESULT_OUTPUT_BYTES } from "../domain/agentResultTransport.js";
|
|
2
2
|
export const MAX_SYNTHESIS_SOURCE_RUNS = 8;
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
// A Task review may combine several candidate reports, synthesis and
|
|
4
|
+
// continuation evidence. Preserve the existing aggregate byte ceiling.
|
|
5
|
+
export const MAX_CONTEXT_SOURCE_RUNS = 64;
|
|
6
|
+
export const MAX_CONTEXT_SOURCE_RUN_BYTES = (MAX_SYNTHESIS_SOURCE_RUNS + 1) * (MAX_RUN_RESULT_OUTPUT_BYTES + 16 * 1024);
|
|
5
7
|
/**
|
|
6
8
|
* Frozen input for synthesis. The main Agent needs the producer identity and
|
|
7
9
|
* exact result, not another copy of its prompt history, launch configuration,
|
|
@@ -158,6 +158,11 @@ export function readTaskContextDelta(store, taskId, input, environment = {}) {
|
|
|
158
158
|
});
|
|
159
159
|
}
|
|
160
160
|
export function inspectTaskContext(store, taskId, selector, environment = {}) {
|
|
161
|
+
const response = readTaskContextResource(store, taskId, selector, environment);
|
|
162
|
+
return boundedDocument(response, `task:${taskId}/${selector.store}/${selector.refId}`, selector.cursor);
|
|
163
|
+
}
|
|
164
|
+
/** The same authorized read as inspect, before transport pagination. */
|
|
165
|
+
export function readTaskContextResource(store, taskId, selector, environment = {}) {
|
|
161
166
|
return store.readTransaction((reader) => {
|
|
162
167
|
const scope = authorizeContext(reader, taskId, environment);
|
|
163
168
|
const value = isAllowed(scope.allow, selector.store, selector.refId)
|
|
@@ -177,7 +182,7 @@ export function inspectTaskContext(store, taskId, selector, environment = {}) {
|
|
|
177
182
|
? { result: expansion.result } : {}),
|
|
178
183
|
...(selector.store === "run" ? { execution: runExecutionObservation(value, reader.getTaskRoleSessionSet(taskId, value.roleName)?.providerBinding, reader.listEventsByType(taskId, ["runtime.agent-error"])) } : {}),
|
|
179
184
|
};
|
|
180
|
-
return
|
|
185
|
+
return response;
|
|
181
186
|
});
|
|
182
187
|
}
|
|
183
188
|
/** Discover one authorized family without copying its bodies or unrelated Task
|