@zq-silk/yui 0.15.11 → 0.16.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/ARCHITECTURE.md +11 -6
- package/ARCHITECTURE.zh-CN.md +8 -4
- package/README.md +13 -5
- package/dist/agentRun/agentRun.js +3 -0
- package/dist/artifacts/artifactCommitLock.js +16 -55
- package/dist/artifacts/taskArtifactRepository.js +3 -3
- package/dist/cli/agentConfigurationPicker.js +1 -1
- package/dist/cli/commandCatalog.js +92 -48
- package/dist/cli/completion.js +18 -18
- package/dist/cli/completionWizard.js +1 -1
- package/dist/cli/dynamicCompletion.js +1 -1
- package/dist/cli/interactionPolicy.js +11 -3
- package/dist/cli/invocationAuthority.js +64 -0
- package/dist/cli/managedDiagnostics.js +2 -2
- package/dist/cli/parseRepeatable.js +35 -0
- package/dist/cli/updatePorts.js +26 -5
- package/dist/cli.js +1303 -1235
- package/dist/commands/agentCommands.js +4 -4
- package/dist/commands/capabilityCommands.js +1 -1
- package/dist/commands/configCommands.js +6 -57
- package/dist/commands/configOverview.js +2 -2
- package/dist/commands/durableJobCommands.js +12 -6
- package/dist/commands/executionAuditCommands.js +10 -0
- package/dist/commands/globalRoleCommands.js +78 -29
- package/dist/commands/grantCommands.js +0 -3
- package/dist/commands/jobCommands.js +1 -4
- package/dist/commands/operatorCommands.js +3 -3
- package/dist/commands/projectCommands.js +45 -25
- package/dist/commands/resourcesCommands.js +10 -40
- package/dist/commands/roleConfiguration.js +2 -6
- package/dist/commands/taskActivationCommands.js +4 -8
- package/dist/commands/taskAgentCapabilities.js +9 -0
- package/dist/commands/taskCommandSupport.js +155 -0
- package/dist/commands/taskCommandTypes.js +1 -0
- package/dist/commands/taskCommands.js +355 -732
- package/dist/commands/taskCompletionGate.js +1 -1
- package/dist/commands/taskExecutionCommands.js +1 -1
- package/dist/commands/taskFactCommands.js +325 -0
- package/dist/commands/taskInputCommands.js +12 -42
- package/dist/commands/taskIntegrationCommands.js +20 -58
- package/dist/commands/taskNextActionCommand.js +7 -6
- package/dist/commands/taskPublicationAdoptCommand.js +127 -0
- package/dist/commands/taskPublicationCommands.js +12 -3
- package/dist/commands/taskPublicationVerifyCommand.js +24 -40
- package/dist/commands/taskRemoteDeliveryCommand.js +5 -86
- package/dist/commands/taskUpstreamCommands.js +19 -8
- package/dist/commands/workflowCommands.js +6 -1
- package/dist/completion/completionInstaller.js +26 -26
- package/dist/completion/completionState.js +26 -26
- package/dist/completion/fileCompletionManager.js +6 -11
- package/dist/config/configCatalog.js +0 -2
- package/dist/config/timeZone.js +14 -0
- package/dist/config/yuiConfig.js +0 -29
- package/dist/context/runContextPack.js +5 -3
- package/dist/context/taskCatalog.js +185 -0
- package/dist/context/taskContext.js +152 -151
- package/dist/context/wakeRunReferences.js +11 -0
- package/dist/controller/agentCapabilities.js +58 -0
- package/dist/controller/agentRuntimeObserver.js +6 -11
- package/dist/controller/clientRuntime.js +22 -14
- package/dist/controller/controller.js +20 -24
- package/dist/controller/fileSchedulerStoreAdapter.js +191 -225
- package/dist/controller/globalInputDelivery.js +13 -0
- package/dist/controller/jobClient.js +4 -4
- package/dist/controller/jobControl.js +60 -25
- package/dist/controller/jobSupervisor.js +4 -4
- package/dist/controller/providerRetryAdmission.js +100 -0
- package/dist/controller/providerRetryDelivery.js +218 -0
- package/dist/controller/runtime.js +85 -43
- package/dist/controller/runtimeEventProcessor.js +0 -5
- package/dist/controller/sessionOwnerReconciliation.js +5 -0
- package/dist/controller/taskAgentError.js +35 -0
- package/dist/coordination/workMailboxQueue.js +2 -24
- package/dist/core/controllerClient.js +2 -2
- package/dist/core/fileLockOwner.js +74 -0
- package/dist/decision/decision.js +17 -0
- package/dist/doctor/doctor.js +18 -9
- package/dist/event/taskEvent.js +12 -0
- package/dist/execution/workItemExecutionProjection.js +2 -2
- package/dist/executor/agentCapabilityConfig.js +43 -0
- package/dist/executor/agentConfigurationCatalog.js +49 -11
- package/dist/executor/agentExecutor.js +5 -8
- package/dist/executor/fileRoleLaunchPlanner.js +11 -53
- package/dist/executor/taskAgentCapabilities.js +64 -0
- package/dist/integration/deliveryObligation.js +1 -69
- package/dist/integration/gitIntegrationService.js +79 -90
- package/dist/integration/integrationAttempt.js +3 -14
- package/dist/integration/integrationSourceApplication.js +4 -12
- package/dist/integration/manifestTags.js +2 -2
- package/dist/job/durableJob.js +4 -25
- package/dist/job/jobAssignmentScope.js +22 -0
- package/dist/job/jobOperation.js +16 -0
- package/dist/job/jobRunner.js +2 -1
- package/dist/job/stepDirectory.js +15 -0
- package/dist/kernel/builtinCapabilities.js +15 -11
- package/dist/kernel/kernelPorts.js +1 -17
- package/dist/lifecycle/exactRunTerminalization.js +5 -10
- package/dist/message/globalProviderRetry.js +15 -0
- package/dist/message/inputControlResolution.js +3 -4
- package/dist/message/message.js +17 -20
- package/dist/message/messageContinuation.js +1 -1
- package/dist/milestone/milestone.js +11 -0
- package/dist/observability/executionAudit.js +19 -0
- package/dist/observability/orchestrationMetrics.js +24 -1
- package/dist/observability/runtimeIdentity.js +1 -17
- package/dist/output/agentConfigurationPresentation.js +2 -0
- package/dist/output/timePresentation.js +1 -14
- package/dist/plugins/pluginService.js +12 -4
- package/dist/release/releaseWorkflowPorts.js +45 -96
- package/dist/release/runtimeRelease.js +9 -15
- package/dist/repository/gitWorkspace.js +371 -105
- package/dist/repository/projectMaintenanceLock.js +98 -82
- package/dist/repository/taskBaseFreshness.js +1 -1
- package/dist/repository/taskWorkspaceCoordinator.js +82 -144
- package/dist/repository/taskWorkspacePreparer.js +113 -47
- package/dist/repository/workspaceCleanupInspection.js +187 -0
- package/dist/resources/autoResourceGc.js +4 -77
- package/dist/resources/liveReferences.js +7 -54
- package/dist/resources/resourceDiscovery.js +5 -118
- package/dist/resources/resourceGc.js +233 -181
- package/dist/resources/resourceRegistrar.js +5 -4
- package/dist/resources/resourceRegistry.js +3 -37
- package/dist/resources/resourceRegistryStore.js +13 -36
- package/dist/resources/sqliteResourceRegistry.js +43 -26
- package/dist/review/deltaRecheck.js +1 -1
- package/dist/review/reviewAcceptance.js +1 -1
- package/dist/review/reviewDecision.js +1 -1
- package/dist/review/reviewRound.js +8 -7
- package/dist/review/taskFinalReviewContractResolution.js +1 -1
- package/dist/runtime/acpProtocol.js +4 -51
- package/dist/runtime/acpSession.js +10 -75
- package/dist/runtime/acpSessionConfiguration.js +1 -8
- package/dist/runtime/agentEndpoint.js +3 -2
- package/dist/runtime/agentError.js +5 -3
- package/dist/runtime/agentFailureContext.js +43 -0
- package/dist/runtime/agentHost.js +42 -25
- package/dist/runtime/builtinAgentErrorMappers.js +91 -0
- package/dist/runtime/codexAppServerRuntime.js +34 -3
- package/dist/runtime/codexInteractiveHost.js +2 -2
- package/dist/runtime/index.js +0 -1
- package/dist/runtime/managedCaller.js +21 -1
- package/dist/runtime/providerControl.js +5 -1
- package/dist/runtime/providerErrors.js +38 -0
- package/dist/runtime/providerRetry.js +198 -0
- package/dist/runtime/providerRuntimeIdentity.js +28 -2
- package/dist/runtime/runtimeObservation.js +0 -5
- package/dist/runtime/runtimeSessionCandidate.js +2 -3
- package/dist/runtime/sessionOwnerIdentity.js +1 -1
- package/dist/runtime/sessionTokenMetrics.js +15 -5
- package/dist/runtime/structuredProviderHost.js +10 -43
- package/dist/runtime/taskUsageMetrics.js +275 -0
- package/dist/runtime/tmuxAdapters.js +6 -8
- package/dist/scheduler/activeRoleRunDelivery.js +19 -7
- package/dist/scheduler/leaderWakeupProcessor.js +24 -6
- package/dist/scheduler/operatorEvent.js +12 -20
- package/dist/scheduler/operatorInputNotificationProcessor.js +1 -1
- package/dist/scheduler/ports.js +5 -8
- package/dist/scheduler/roleRunLiveness.js +4 -4
- package/dist/scheduler/roleRunStall.js +16 -23
- package/dist/scheduler/taskExecutionProjection.js +49 -36
- package/dist/scheduler/taskObservabilityProjection.js +6 -45
- package/dist/scheduler/taskWake.js +5 -10
- package/dist/scheduler/wakeReason.js +2 -0
- package/dist/scheduler/wakeupQueue.js +2 -4
- package/dist/setup/setupCommand.js +1 -1
- package/dist/storage/contextRecords.js +106 -0
- package/dist/storage/currentTaskStore.js +1 -1
- package/dist/storage/homeLayout.js +13 -17
- package/dist/storage/migrations/agentFailureContext.js +22 -0
- package/dist/storage/migrations/currentInputContract.js +86 -0
- package/dist/storage/migrations/currentRuntimeContract.js +228 -0
- package/dist/storage/migrations/historicalVerificationPlan.js +35 -0
- package/dist/storage/migrations/integrationContinuation.js +5 -4
- package/dist/storage/migrations/narrowAgentFailureContext.js +65 -0
- package/dist/storage/migrations/notificationOnlyWakes.js +74 -0
- package/dist/storage/migrations/verificationPlanV1.js +162 -0
- package/dist/storage/migrations/verificationPolicy.js +74 -0
- package/dist/storage/migrations/workItemHistory.js +46 -0
- package/dist/storage/persistenceWorker.js +12 -4
- package/dist/storage/recordValidation.js +87 -0
- package/dist/storage/sqliteSchema.js +173 -1
- package/dist/storage/sqliteStore.js +172 -161
- package/dist/storage/storageSchema.js +2 -14
- package/dist/storage/storageVersions.js +1 -1
- package/dist/storage/storeRpc.js +16 -7
- package/dist/storage/taskCatalog.js +123 -0
- package/dist/storage/taskStore.js +5 -7
- package/dist/storage/upgrade/upgradeOrchestrator.js +25 -37
- package/dist/task/archiveDiagnostics.js +1 -0
- package/dist/task/archivePreflight.js +124 -0
- package/dist/task/completionReadiness.js +5 -24
- package/dist/task/draftPlan.js +0 -53
- package/dist/task/nextAction.js +7 -13
- package/dist/task/publicationAdoption.js +56 -0
- package/dist/task/publicationReference.js +10 -0
- package/dist/task/remoteDelivery.js +31 -16
- package/dist/task/remoteDeliveryService.js +89 -0
- package/dist/task/taskActivation.js +2 -25
- package/dist/task/taskActivationService.js +0 -2
- package/dist/task/taskRecordReference.js +0 -1
- package/dist/task/taskSubmission.js +3 -14
- package/dist/telemetry/sqliteTelemetryBatch.js +29 -0
- package/dist/telemetry/sqliteTelemetryStore.js +49 -49
- package/dist/telemetry/telemetryWiring.js +4 -3
- package/dist/tmux/tmuxManager.js +29 -20
- package/dist/verification/gateArtifact.js +15 -24
- package/dist/verification/gateArtifactStore.js +14 -7
- package/dist/verification/verificationGateService.js +29 -88
- package/dist/verification/verificationPlan.js +27 -72
- package/dist/web/assets/client/app.js +92 -17
- package/dist/web/assets/client/components.js +55 -13
- package/dist/web/assets/client/i18n.js +72 -4
- package/dist/web/assets/client/taskSurface.js +6 -5
- package/dist/web/assets/client/view.js +35 -7
- package/dist/web/assets/shell.js +6 -0
- package/dist/web/assets/styles/layout.js +7 -0
- package/dist/web/webServer.js +12 -3
- package/dist/web/webSnapshot.js +14 -85
- package/dist/web/webTaskSurface.js +17 -46
- package/dist/workItem/workItem.js +1 -12
- package/dist/workspace/cleanupInspection.js +63 -0
- package/dist/workspace/workItemChangeSetManager.js +110 -50
- package/docs/agent-result-consumption.md +4 -0
- package/docs/agent-result-consumption.zh-CN.md +3 -0
- package/docs/agent-runtime-drivers.md +7 -0
- package/docs/agent-runtime-drivers.zh-CN.md +5 -0
- package/docs/architecture/README.md +2 -0
- package/docs/architecture/README.zh-CN.md +3 -1
- package/docs/architecture/capabilities-and-resources.md +42 -5
- package/docs/architecture/capabilities-and-resources.zh-CN.md +33 -3
- package/docs/managed-turn-and-session-runtime.md +121 -1
- package/docs/managed-turn-and-session-runtime.zh-CN.md +96 -2
- package/docs/observability/README.md +62 -0
- package/docs/observability/README.zh-CN.md +47 -0
- package/docs/plugin-sdk.md +4 -2
- package/docs/project-refresh.md +77 -0
- package/docs/project-refresh.zh-CN.md +59 -0
- package/docs/provider-retry.md +70 -0
- package/docs/provider-runtime.md +3 -1
- package/docs/provider-runtime.zh-CN.md +4 -2
- package/docs/release-workflow.md +190 -7
- package/docs/release-workflow.zh-CN.md +139 -5
- package/docs/roles-and-configuration.md +29 -0
- package/docs/roles-and-configuration.zh-CN.md +21 -0
- package/docs/sqlite-control-plane-design.md +16 -3
- package/docs/sqlite-control-plane-design.zh-CN.md +13 -2
- package/docs/task-dag-semantics.md +3 -3
- package/docs/task-dag-semantics.zh-CN.md +2 -2
- package/docs/task-delivery.md +223 -17
- package/docs/task-delivery.zh-CN.md +171 -14
- package/docs/task-discovery.md +101 -0
- package/docs/task-discovery.zh-CN.md +85 -0
- package/docs/testing/verification-levels.md +161 -9
- package/docs/testing/verification-levels.zh-CN.md +116 -9
- package/i18n/README.zh-CN.md +13 -7
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +5 -0
- package/skills/yui-leader/references/execution.md +3 -2
- package/skills/yui-leader/references/integration.md +9 -5
- package/skills/yui-leader/references/planning.md +9 -3
- package/skills/yui-operator/SKILL.md +24 -8
- package/skills/yui-reviewer/SKILL.md +4 -0
- package/skills/yui-runtime/SKILL.md +17 -2
- package/skills/yui-runtime/references/publication.md +26 -4
- package/skills/yui-runtime/references/recovery.md +71 -0
- package/dist/agent/agentRegistry.js +0 -10
- package/dist/agentRun/runIdentity.js +0 -22
- package/dist/commands/deliveryGuardPreflight.js +0 -30
- package/dist/commands/taskIntegrationQueueCommands.js +0 -226
- package/dist/commands/taskOverviewCommand.js +0 -376
- package/dist/completion/completionWizard.js +0 -125
- package/dist/context/dispatchContext.js +0 -110
- package/dist/context/wakeNotification.js +0 -144
- package/dist/integration/integrationCheckEvidenceReuse.js +0 -53
- package/dist/integration/integrationQueueEntry.js +0 -191
- package/dist/integration/integrationQueueService.js +0 -810
- package/dist/release/fakeReleasePorts.js +0 -55
- package/dist/runtime/sessionOwnerRegistry.js +0 -137
- package/dist/task/deliveryGuard.js +0 -226
- /package/dist/{commands/taskActor.js → task/taskAuthority.js} +0 -0
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { runExecutionObservation } from "../agentRun/agentRun.js";
|
|
2
|
+
import { isGitArtifactRefString, parseGitArtifactRef } from "../artifacts/gitArtifactRef.js";
|
|
3
|
+
import { taskNotFound, usageError } from "../errors/cliError.js";
|
|
4
|
+
import { expandTaskMessageResult } from "../message/message.js";
|
|
2
5
|
import { resolveManagedTaskReader } from "../runtime/managedCaller.js";
|
|
6
|
+
import { providerRetryProjection } from "../runtime/providerRetry.js";
|
|
7
|
+
import { projectTaskRemoteDeliveryFromStore } from "../task/remoteDeliveryService.js";
|
|
8
|
+
import { managedWorkspaceKey } from "../worktree/managedWorkspace.js";
|
|
3
9
|
import { contextContentDigest } from "./contextSnapshot.js";
|
|
4
10
|
import { buildRunContextPack } from "./runContextPack.js";
|
|
5
11
|
import { sourceRunContextValue } from "./sourceRunContext.js";
|
|
6
|
-
import { expandTaskMessageResult } from "../message/message.js";
|
|
7
|
-
import { managedWorkspaceKey } from "../worktree/managedWorkspace.js";
|
|
8
|
-
import { runExecutionObservation } from "../agentRun/agentRun.js";
|
|
9
|
-
import { isGitArtifactRefString, parseGitArtifactRef } from "../artifacts/gitArtifactRef.js";
|
|
10
12
|
const MAX_RECORDS = 256;
|
|
11
13
|
const MAX_VALUE_BYTES = 4096;
|
|
12
14
|
const MAX_PAGE_BYTES = 128 * 1024;
|
|
@@ -17,64 +19,74 @@ const MAX_ATTENTION_REFS = 8;
|
|
|
17
19
|
* Every public path checks the same scope before reading, counting or paging.
|
|
18
20
|
*/
|
|
19
21
|
export function readTaskContext(store, taskId, environment = {}) {
|
|
20
|
-
return store.
|
|
21
|
-
const
|
|
22
|
+
return store.readTransaction((reader) => {
|
|
23
|
+
const scope = authorizeContext(reader, taskId, environment);
|
|
24
|
+
const sources = authorizedSources(reader, scope);
|
|
25
|
+
const count = sources.reduce((total, source) => total + source.count, 0);
|
|
22
26
|
const cursor = currentCursor(reader, taskId);
|
|
23
27
|
// Reserve a small, classified view before ordinary history consumes the
|
|
24
28
|
// page. Counts and samples come from the exact same authorized read.
|
|
25
|
-
const attention = summarizeAttention(
|
|
29
|
+
const attention = summarizeAttention(reader, taskId, scope.allow);
|
|
26
30
|
let bytes = Buffer.byteLength(JSON.stringify(attention));
|
|
27
31
|
const records = [];
|
|
28
|
-
|
|
29
|
-
for (const
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
32
|
+
let runtimeEvents;
|
|
33
|
+
page: for (const source of sources)
|
|
34
|
+
for (const entry of source.read()) {
|
|
35
|
+
if (records.length >= MAX_RECORDS)
|
|
36
|
+
break page;
|
|
37
|
+
if (entry.ref.store === "run")
|
|
38
|
+
runtimeEvents ??= reader.listEventsByType(taskId, ["runtime.agent-error"]);
|
|
39
|
+
const valueBytes = Buffer.byteLength(JSON.stringify(entry.value));
|
|
40
|
+
const content = valueBytes > MAX_VALUE_BYTES
|
|
41
|
+
? { ref: entry.ref, summary: summarize(entry.value), omitted: true }
|
|
42
|
+
: { ...entry, omitted: false };
|
|
43
|
+
const record = { ...content, ...(entry.ref.store === "run" ? {
|
|
44
|
+
execution: runExecutionObservation(entry.value, reader.getTaskRoleSessionSet(taskId, entry.value.roleName)?.providerBinding, runtimeEvents)
|
|
45
|
+
} : {}), ...(entry.ref.store === "role" ? {
|
|
46
|
+
providerRetry: providerRetryProjection(reader.getTaskRoleSessionSet(taskId, entry.value.name)?.providerBinding)
|
|
47
|
+
} : {}) };
|
|
48
|
+
const size = Buffer.byteLength(JSON.stringify(record));
|
|
49
|
+
if (bytes + size > MAX_PAGE_BYTES)
|
|
50
|
+
break page;
|
|
51
|
+
records.push(record);
|
|
52
|
+
bytes += size;
|
|
53
|
+
}
|
|
43
54
|
return {
|
|
44
55
|
taskId, coreCursor: encode(cursor), throughCursor: encode(cursor),
|
|
45
56
|
attention,
|
|
46
|
-
records, count
|
|
47
|
-
omitted: { records:
|
|
57
|
+
records, count,
|
|
58
|
+
omitted: { records: count - records.length, values: records.filter((r) => r.omitted).length },
|
|
48
59
|
observations: [],
|
|
49
60
|
limits: { records: MAX_RECORDS, valueBytes: MAX_VALUE_BYTES, pageBytes: MAX_PAGE_BYTES,
|
|
50
61
|
attentionRefsPerCategory: MAX_ATTENTION_REFS, attentionRefBytesPerCategory: MAX_VALUE_BYTES }
|
|
51
62
|
};
|
|
52
63
|
});
|
|
53
64
|
}
|
|
54
|
-
function summarizeAttention(
|
|
65
|
+
function summarizeAttention(store, taskId, allow) {
|
|
55
66
|
const group = () => ({ count: 0, refs: [], omittedRefs: 0 });
|
|
56
67
|
const attention = {
|
|
57
68
|
openInputs: group(), pendingOperations: group(), unknownOperations: group()
|
|
58
69
|
};
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
continue;
|
|
70
|
+
for (const [category, family, statuses] of [
|
|
71
|
+
["openInputs", "input-request", ["open"]],
|
|
72
|
+
["pendingOperations", "job", ["queued", "running"]],
|
|
73
|
+
["unknownOperations", "job", ["unknown-needs-attention"]]
|
|
74
|
+
]) {
|
|
75
|
+
const page = store.queryContextRecords(taskId, {
|
|
76
|
+
family, statuses, ids: allowedIds(allow, family), limit: MAX_ATTENTION_REFS
|
|
77
|
+
});
|
|
68
78
|
const summary = attention[category];
|
|
69
|
-
summary.count
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
summary.
|
|
79
|
+
summary.count = page.count;
|
|
80
|
+
let bytes = 0;
|
|
81
|
+
for (const { id, value } of page.records) {
|
|
82
|
+
const ref = materialize(family, id, value).ref;
|
|
83
|
+
const size = Buffer.byteLength(JSON.stringify(ref)) + 1;
|
|
84
|
+
if (bytes + size > MAX_VALUE_BYTES)
|
|
85
|
+
break;
|
|
86
|
+
summary.refs.push(ref);
|
|
87
|
+
bytes += size;
|
|
77
88
|
}
|
|
89
|
+
summary.omittedRefs = summary.count - summary.refs.length;
|
|
78
90
|
}
|
|
79
91
|
return attention;
|
|
80
92
|
}
|
|
@@ -83,11 +95,10 @@ function summarizeAttention(entries) {
|
|
|
83
95
|
* A continuation carries the first page's fixed upper event bound.
|
|
84
96
|
*/
|
|
85
97
|
export function readTaskContextDelta(store, taskId, input, environment = {}) {
|
|
86
|
-
return store.
|
|
98
|
+
return store.readTransaction((reader) => {
|
|
87
99
|
const { allow } = authorizeContext(reader, taskId, environment);
|
|
88
|
-
const history = reader.listEvents(taskId);
|
|
89
100
|
const start = decode(input.after, taskId);
|
|
90
|
-
const now = currentCursor(reader, taskId
|
|
101
|
+
const now = currentCursor(reader, taskId);
|
|
91
102
|
const continuation = input.continuation === undefined ? undefined : decodePage(input.continuation, taskId);
|
|
92
103
|
const bound = continuation ?? now;
|
|
93
104
|
const after = continuation?.after ?? start.sequence;
|
|
@@ -99,13 +110,14 @@ export function readTaskContextDelta(store, taskId, input, environment = {}) {
|
|
|
99
110
|
if (!Number.isSafeInteger(limit) || limit < 1 || limit > MAX_EVENTS) {
|
|
100
111
|
throw usageError(`Context delta limit must be between 1 and ${MAX_EVENTS}.`);
|
|
101
112
|
}
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
113
|
+
const selected = reader.queryContextRecords(taskId, {
|
|
114
|
+
family: "task-event", ids: allowedIds(allow, "task-event"),
|
|
115
|
+
afterSequence: after, throughSequence: bound.sequence, limit
|
|
116
|
+
});
|
|
106
117
|
const page = [];
|
|
107
118
|
let bytes = 0;
|
|
108
|
-
for (const
|
|
119
|
+
for (const { value } of selected.records) {
|
|
120
|
+
const event = value;
|
|
109
121
|
const entry = materialize("task-event", event.id, event);
|
|
110
122
|
const record = Buffer.byteLength(JSON.stringify(event)) > MAX_VALUE_BYTES
|
|
111
123
|
? { ref: entry.ref, omitted: true }
|
|
@@ -117,10 +129,10 @@ export function readTaskContextDelta(store, taskId, input, environment = {}) {
|
|
|
117
129
|
bytes += size;
|
|
118
130
|
}
|
|
119
131
|
const last = page.at(-1)?.ref.refId;
|
|
120
|
-
const more =
|
|
132
|
+
const more = selected.count > page.length;
|
|
121
133
|
const through = { taskId, sequence: bound.sequence, revision: bound.revision };
|
|
122
134
|
return {
|
|
123
|
-
taskId, events: page, count:
|
|
135
|
+
taskId, events: page, count: selected.count, throughCursor: encode(through),
|
|
124
136
|
...(more && last !== undefined
|
|
125
137
|
? { continuation: encode({ ...through, after: sequence(last) }) } : {}),
|
|
126
138
|
observations: []
|
|
@@ -128,7 +140,7 @@ export function readTaskContextDelta(store, taskId, input, environment = {}) {
|
|
|
128
140
|
});
|
|
129
141
|
}
|
|
130
142
|
export function inspectTaskContext(store, taskId, selector, environment = {}) {
|
|
131
|
-
return store.
|
|
143
|
+
return store.readTransaction((reader) => {
|
|
132
144
|
const scope = authorizeContext(reader, taskId, environment);
|
|
133
145
|
const value = isAllowed(scope.allow, selector.store, selector.refId)
|
|
134
146
|
? inspectValue(reader, scope, selector) : null;
|
|
@@ -148,7 +160,7 @@ export function inspectTaskContext(store, taskId, selector, environment = {}) {
|
|
|
148
160
|
: undefined;
|
|
149
161
|
const response = { ...entry, ...(expansion !== undefined && "result" in expansion
|
|
150
162
|
? { result: expansion.result } : {}),
|
|
151
|
-
...(selector.store === "run" ? { execution: runExecutionObservation(value, reader.getTaskRoleSessionSet(taskId, value.roleName)?.providerBinding, reader.
|
|
163
|
+
...(selector.store === "run" ? { execution: runExecutionObservation(value, reader.getTaskRoleSessionSet(taskId, value.roleName)?.providerBinding, reader.listEventsByType(taskId, ["runtime.agent-error"])) } : {}),
|
|
152
164
|
coreCursor: encode(currentCursor(reader, taskId)) };
|
|
153
165
|
if (Buffer.byteLength(JSON.stringify(response)) > MAX_INSPECT_BYTES) {
|
|
154
166
|
throw usageError("Expanded Context exceeds the bounded inspect limit.", undefined, { ref: entry.ref, maxBytes: MAX_INSPECT_BYTES });
|
|
@@ -157,7 +169,7 @@ export function inspectTaskContext(store, taskId, selector, environment = {}) {
|
|
|
157
169
|
});
|
|
158
170
|
}
|
|
159
171
|
export function listContextMessages(store, taskId, environment = {}) {
|
|
160
|
-
return store.
|
|
172
|
+
return store.readTransaction((reader) => {
|
|
161
173
|
const { allow } = authorizeContext(reader, taskId, environment);
|
|
162
174
|
return reader.listMessages(taskId)
|
|
163
175
|
.filter((message) => isAllowed(allow, "task-message", message.id))
|
|
@@ -201,10 +213,9 @@ export async function withContextObservations(core, providers, timeoutMs = 250)
|
|
|
201
213
|
}));
|
|
202
214
|
return { ...core, observations };
|
|
203
215
|
}
|
|
204
|
-
|
|
216
|
+
/** Shared current/historical Session read identity; discovery may only narrow it. */
|
|
217
|
+
export function resolveContextReader(store, environment) {
|
|
205
218
|
const caller = resolveManagedTaskReader(store, environment);
|
|
206
|
-
if (caller !== undefined && caller.taskId !== taskId)
|
|
207
|
-
throw usageError("Context is outside the caller's Task.");
|
|
208
219
|
if (caller === undefined && environment.YUI_SESSION_SCOPE === "global" && environment.YUI_ROLE !== "operator") {
|
|
209
220
|
throw usageError("Only Operator may read Task context from a global Session.");
|
|
210
221
|
}
|
|
@@ -216,6 +227,12 @@ function authorizeContext(store, taskId, environment) {
|
|
|
216
227
|
if (environment.YUI_SESSION_SCOPE !== undefined && !["task", "global"].includes(environment.YUI_SESSION_SCOPE)) {
|
|
217
228
|
throw usageError("Incomplete managed Context caller identity.");
|
|
218
229
|
}
|
|
230
|
+
return caller;
|
|
231
|
+
}
|
|
232
|
+
function authorizeContext(store, taskId, environment) {
|
|
233
|
+
const caller = resolveContextReader(store, environment);
|
|
234
|
+
if (caller !== undefined && caller.taskId !== taskId)
|
|
235
|
+
throw usageError("Context is outside the caller's Task.");
|
|
219
236
|
const task = store.getTask(taskId);
|
|
220
237
|
if (task === null)
|
|
221
238
|
throw taskNotFound(taskId);
|
|
@@ -227,63 +244,45 @@ function authorizeContext(store, taskId, environment) {
|
|
|
227
244
|
allow = new Set(pack.authority.readableRefs.map((ref) => `${ref.store}:${ref.refId}`));
|
|
228
245
|
allow.add(`role:${caller.roleName}`);
|
|
229
246
|
allow.add(`turn:${caller.currentRunId}`);
|
|
230
|
-
//
|
|
231
|
-
//
|
|
232
|
-
//
|
|
233
|
-
// holds no Assignment), so recognize it explicitly: the shared block below
|
|
234
|
-
// must never leak it, and the steer-delta block authorizes it only to its own
|
|
235
|
-
// recipient. `interruptThen.reusedInput` is the interrupt-then composition
|
|
236
|
-
// whose carried input can itself be a steer.
|
|
237
|
-
const isSteerMessage = (message) => message.inputControl?.action === "steer"
|
|
238
|
-
|| message.interruptThen?.reusedInput?.action === "steer";
|
|
239
|
-
// A frozen Assignment is not a cutoff for the Task's current user intent.
|
|
240
|
-
// Untargeted human/Operator messages are shared Task requirements; scoped
|
|
241
|
-
// messages, other Roles' results, and steers still require an explicit grant.
|
|
242
|
-
const sharedMessageIds = new Set(store.listMessages(taskId)
|
|
243
|
-
.filter(message => (message.kind === "user" || message.kind === "operator")
|
|
244
|
-
&& message.recipient === undefined && message.workItemId === undefined
|
|
245
|
-
&& message.runId === undefined && !isSteerMessage(message))
|
|
246
|
-
.map(message => message.id));
|
|
247
|
-
for (const id of sharedMessageIds)
|
|
248
|
-
allow.add(`task-message:${id}`);
|
|
249
|
-
for (const event of store.listEvents(taskId)) {
|
|
250
|
-
if (event.type.startsWith("message.") && sharedMessageIds.has(event.payload.messageId)) {
|
|
251
|
-
allow.add(`task-event:${event.id}`);
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
// A steer targets this Role's exact current native Turn (decision-3 §9,
|
|
255
|
-
// message-5 gap E). Unlike a queued or addressed Message — which reaches the
|
|
256
|
-
// Role through a new AgentRun's frozen Context pack — a steer is pushed into
|
|
257
|
-
// the *current* turn and is never captured by any frozen snapshot. So the
|
|
258
|
-
// steer header directs the recipient to reconcile the input "through your
|
|
259
|
-
// authorized Context read path"; that path must therefore resolve the exact
|
|
260
|
-
// steer Message it names. Authorize the steers addressed to this caller's
|
|
261
|
-
// exact current Assignment scope as a live delta — the same way untargeted
|
|
262
|
-
// user intent is layered on — WITHOUT expanding the frozen Assignment's
|
|
263
|
-
// readableRefs. Scope is the tightest signal a steer carries (it never gains
|
|
264
|
-
// a continuation runId), so a steer for a different WorkItem/Round is not
|
|
265
|
-
// authorized, and only genuine steers gain this read (an ordinary addressed
|
|
266
|
-
// Message still requires its own frozen delta).
|
|
247
|
+
// Shared current user intent and this exact Assignment's live steers augment
|
|
248
|
+
// the frozen refs. Query identities only: another Role's results, ordinary
|
|
249
|
+
// addressed messages and Leader steers remain outside this scope.
|
|
267
250
|
const run = store.getRun(taskId, caller.currentRunId);
|
|
268
|
-
const
|
|
269
|
-
.
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
&& message.recipient.reviewRoundId === run?.reviewRoundId)
|
|
273
|
-
.map(message => message.id));
|
|
274
|
-
for (const id of steerMessageIds)
|
|
251
|
+
const current = store.contextInputReferences(taskId, {
|
|
252
|
+
roleName: caller.roleName, workItemId: run?.workItemId, reviewRoundId: run?.reviewRoundId
|
|
253
|
+
});
|
|
254
|
+
for (const id of current.messages)
|
|
275
255
|
allow.add(`task-message:${id}`);
|
|
276
|
-
for (const
|
|
277
|
-
|
|
278
|
-
|
|
256
|
+
for (const id of current.events)
|
|
257
|
+
allow.add(`task-event:${id}`);
|
|
258
|
+
if (run?.workItemId !== undefined) {
|
|
259
|
+
for (const job of store.listDurableJobs(taskId)) {
|
|
260
|
+
if (job.owner.kind === "work-item" && job.owner.workItemId === run.workItemId)
|
|
261
|
+
allow.add(`job:${job.id}`);
|
|
279
262
|
}
|
|
280
263
|
}
|
|
281
264
|
}
|
|
282
265
|
return { task, allow, caller };
|
|
283
266
|
}
|
|
267
|
+
/** Independent record commands share Context's exact read boundary, not a
|
|
268
|
+
* second role-based approximation of Assignment visibility. */
|
|
269
|
+
export function contextRecordReader(store, taskId, environment = {}) {
|
|
270
|
+
const { allow } = authorizeContext(store, taskId, environment);
|
|
271
|
+
return (family, id) => isAllowed(allow, family, id);
|
|
272
|
+
}
|
|
273
|
+
export function assertContextRecordReadable(store, taskId, family, id, environment = {}) {
|
|
274
|
+
if (!contextRecordReader(store, taskId, environment)(family, id)) {
|
|
275
|
+
throw usageError("Context reference is outside the caller's Assignment.");
|
|
276
|
+
}
|
|
277
|
+
}
|
|
284
278
|
function isAllowed(allow, family, id) {
|
|
285
279
|
return allow === undefined || allow.has(`${family}:${id}`);
|
|
286
280
|
}
|
|
281
|
+
function allowedIds(allow, family) {
|
|
282
|
+
const prefix = `${family}:`;
|
|
283
|
+
return allow === undefined ? undefined : [...allow]
|
|
284
|
+
.filter(ref => ref.startsWith(prefix)).map(ref => ref.slice(prefix.length));
|
|
285
|
+
}
|
|
287
286
|
function roleProfile(role) {
|
|
288
287
|
return {
|
|
289
288
|
name: role.name, defaultAccess: role.defaultAccess, description: role.description,
|
|
@@ -299,6 +298,8 @@ function inspectValue(store, { task, allow, caller }, { store: family, refId })
|
|
|
299
298
|
switch (family) {
|
|
300
299
|
case "task": return refId === taskId ? task : null;
|
|
301
300
|
case "task-brief": return refId === taskId ? store.getTaskBrief(taskId) : null;
|
|
301
|
+
case "remote-delivery": return refId === taskId && allow === undefined
|
|
302
|
+
? projectTaskRemoteDeliveryFromStore(store, task) : null;
|
|
302
303
|
case "role": return store.getRole(taskId, refId);
|
|
303
304
|
case "role-profile": {
|
|
304
305
|
const role = store.getRole(taskId, refId);
|
|
@@ -330,7 +331,10 @@ function inspectValue(store, { task, allow, caller }, { store: family, refId })
|
|
|
330
331
|
return store.getWorkItem(taskId, parts[0])?.candidates
|
|
331
332
|
.find((candidate) => candidate.id === parts[1]) ?? null;
|
|
332
333
|
}
|
|
333
|
-
case "task-message":
|
|
334
|
+
case "task-message":
|
|
335
|
+
case "publication":
|
|
336
|
+
case "task-event":
|
|
337
|
+
return store.queryContextRecords(taskId, { family, ids: [refId], limit: 1 }).records[0]?.value ?? null;
|
|
334
338
|
case "run": return store.getRun(taskId, refId);
|
|
335
339
|
case "source-run": {
|
|
336
340
|
if (!allow?.has(`source-turn:${refId}`))
|
|
@@ -382,21 +386,31 @@ function inspectValue(store, { task, allow, caller }, { store: family, refId })
|
|
|
382
386
|
case "task-decision": return store.getDecision(taskId, refId);
|
|
383
387
|
case "task-milestone": return store.getMilestone(taskId, refId);
|
|
384
388
|
case "job": return store.getDurableJob(taskId, refId);
|
|
385
|
-
case "publication": return store.listPublicationReferences(taskId).find((item) => item.id === refId) ?? null;
|
|
386
|
-
case "task-event": return store.listEvents(taskId).find((event) => event.id === refId) ?? null;
|
|
387
389
|
default: return null;
|
|
388
390
|
}
|
|
389
391
|
}
|
|
390
|
-
function
|
|
391
|
-
const
|
|
392
|
-
const
|
|
392
|
+
function authorizedSources(store, { task, allow, caller }) {
|
|
393
|
+
const taskId = task.id;
|
|
394
|
+
const sources = [];
|
|
393
395
|
const add = (family, id, value) => {
|
|
394
396
|
if (value !== null && isAllowed(allow, family, id)) {
|
|
395
|
-
|
|
397
|
+
sources.push({ count: 1, read: () => [materialize(family, id, value)] });
|
|
396
398
|
}
|
|
397
399
|
};
|
|
400
|
+
const query = (family, options = {}) => {
|
|
401
|
+
const selection = { ...options, family, ids: allowedIds(allow, family) };
|
|
402
|
+
const { count } = store.queryContextRecords(taskId, { ...selection, limit: 0 });
|
|
403
|
+
sources.push({ count, *read() {
|
|
404
|
+
for (const { id, value } of store.queryContextRecords(taskId, {
|
|
405
|
+
...selection, limit: MAX_RECORDS
|
|
406
|
+
}).records)
|
|
407
|
+
yield materialize(family, id, value);
|
|
408
|
+
} });
|
|
409
|
+
};
|
|
398
410
|
add("task", taskId, task);
|
|
399
411
|
add("task-brief", taskId, store.getTaskBrief(taskId));
|
|
412
|
+
if (allow === undefined)
|
|
413
|
+
add("remote-delivery", taskId, projectTaskRemoteDeliveryFromStore(store, task));
|
|
400
414
|
for (const role of store.listRoles(taskId)) {
|
|
401
415
|
add("role", role.name, role);
|
|
402
416
|
add("role-profile", role.name, roleProfile(role));
|
|
@@ -412,65 +426,52 @@ function authorizedEntries(store, taskId, environment) {
|
|
|
412
426
|
}
|
|
413
427
|
}
|
|
414
428
|
// Current responsibilities and unanswered inputs precede historical bulk.
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
for (const
|
|
418
|
-
add("work-item",
|
|
419
|
-
if (allow?.has(`accepted-work-item:${item.id}`))
|
|
420
|
-
add("accepted-work-item", item.id, item);
|
|
421
|
-
for (const candidate of [...item.candidates].reverse())
|
|
422
|
-
add("candidate", `${item.id}/${candidate.id}`, candidate);
|
|
429
|
+
query("input-request", { statuses: ["open"] });
|
|
430
|
+
query("work-item");
|
|
431
|
+
for (const id of allowedIds(allow, "accepted-work-item") ?? []) {
|
|
432
|
+
add("accepted-work-item", id, store.getWorkItem(taskId, id));
|
|
423
433
|
}
|
|
434
|
+
query("candidate");
|
|
424
435
|
// File artifacts are not enumerated into the synchronous Context listing: the
|
|
425
436
|
// core cursor does not cover file edits and an ambient directory index here
|
|
426
437
|
// would be the forbidden update-time mirror (§3.7). Current artifacts are
|
|
427
438
|
// listed on demand via the async `artifact.list` capability; frozen Candidate
|
|
428
439
|
// artifacts remain reachable as commit-pinned pointers under their Candidate.
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
for (const workspace of store.listManagedWorkspaces(taskId))
|
|
432
|
-
add("managed-workspace", managedWorkspaceKey(workspace.owner), workspace);
|
|
440
|
+
query("environment-preparation");
|
|
441
|
+
query("managed-workspace");
|
|
433
442
|
if (caller?.currentRunId !== undefined) {
|
|
434
443
|
add("managed-workspace", `${taskId}/${caller.roleName}`, store.getRun(taskId, caller.currentRunId)?.workspace ?? null);
|
|
435
444
|
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
add("source-run", run.id, sourceRunContextValue(run));
|
|
445
|
+
query("change-set");
|
|
446
|
+
query("task-message", { descending: true });
|
|
447
|
+
query("run", { descending: true });
|
|
448
|
+
for (const id of allowedIds(allow, "source-turn") ?? []) {
|
|
449
|
+
const run = store.getRun(taskId, id);
|
|
450
|
+
if (run !== null)
|
|
451
|
+
add("source-run", id, sourceRunContextValue(run));
|
|
444
452
|
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
for (const request of store.listInputRequests(taskId).filter((r) => r.status !== "open"))
|
|
448
|
-
add("input-request", request.id, request);
|
|
453
|
+
query("review-round", { descending: true });
|
|
454
|
+
query("input-request", { excludeStatuses: ["open"] });
|
|
449
455
|
if (allow === undefined) {
|
|
450
456
|
add("mailbox", "task", store.getWorkMailbox({ kind: "task", taskId }));
|
|
451
457
|
for (const role of store.listRoles(taskId)) {
|
|
452
458
|
add("mailbox", `role:${role.name}`, store.getWorkMailbox({ kind: "role", taskId, roleName: role.name }));
|
|
453
459
|
}
|
|
454
460
|
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
for (const publication of store.listPublicationReferences(taskId))
|
|
462
|
-
add("publication", publication.id, publication);
|
|
463
|
-
for (const event of store.listEvents(taskId).reverse())
|
|
464
|
-
add("task-event", event.id, event);
|
|
465
|
-
return entries;
|
|
461
|
+
query("task-decision");
|
|
462
|
+
query("task-milestone");
|
|
463
|
+
query("job");
|
|
464
|
+
query("publication");
|
|
465
|
+
query("task-event", { descending: true });
|
|
466
|
+
return sources;
|
|
466
467
|
}
|
|
467
|
-
function materialize(store, refId, value) {
|
|
468
|
+
export function materialize(store, refId, value) {
|
|
468
469
|
const digest = contextContentDigest(value);
|
|
469
470
|
const record = value;
|
|
470
471
|
return { ref: { store, refId, revision: String(record.revision ?? record.updatedAt ?? record.createdAt ?? digest), digest }, value };
|
|
471
472
|
}
|
|
472
|
-
function currentCursor(store, taskId
|
|
473
|
-
return { taskId, sequence:
|
|
473
|
+
function currentCursor(store, taskId) {
|
|
474
|
+
return { taskId, sequence: store.latestEventSequence(taskId), revision: store.getStateRevision() };
|
|
474
475
|
}
|
|
475
476
|
function sequence(id) {
|
|
476
477
|
const result = /^event-(\d+)$/.exec(id);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { operationalTaskRecords } from "../task/taskRecordRetirement.js";
|
|
2
|
+
/** Exact results named by a notification delta, including Runs older than its cursor. */
|
|
3
|
+
export function referencedWakeRunIds(runs, allEvents, terminalEvents) {
|
|
4
|
+
const runsById = new Map(operationalTaskRecords(runs, allEvents, "run").map(run => [run.id, run]));
|
|
5
|
+
return [...new Set(terminalEvents.flatMap(event => {
|
|
6
|
+
if (!["run.completed", "run.failed", "run.cancelled"].includes(event.type))
|
|
7
|
+
return [];
|
|
8
|
+
const runId = event.payload.runId;
|
|
9
|
+
return runId !== undefined && runsById.has(runId) ? [runId] : [];
|
|
10
|
+
}))];
|
|
11
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { usageError } from "../errors/cliError.js";
|
|
2
|
+
import { resolveTaskAgentCapabilities } from "../executor/taskAgentCapabilities.js";
|
|
3
|
+
import { requireManagedGlobalCaller } from "../runtime/managedCaller.js";
|
|
4
|
+
const READER_FIELDS = [
|
|
5
|
+
"YUI_SESSION_SCOPE", "YUI_TASK_ID", "YUI_ROLE", "YUI_NATIVE_SESSION_ID",
|
|
6
|
+
"YUI_AGENT_ID", "YUI_ADAPTER_ID", "YUI_WORKSPACE", "CODEX_THREAD_ID"
|
|
7
|
+
];
|
|
8
|
+
/** Transport only the existing reader identity, never the caller's credentials. */
|
|
9
|
+
export function capabilityReaderIdentity(environment) {
|
|
10
|
+
if (environment.YUI_SESSION_SCOPE === undefined) {
|
|
11
|
+
if (["YUI_ROLE", "YUI_AGENT_ID", "YUI_NATIVE_SESSION_ID"].some(key => environment[key] !== undefined)) {
|
|
12
|
+
throw usageError("Managed reader identity is incomplete.");
|
|
13
|
+
}
|
|
14
|
+
return {};
|
|
15
|
+
}
|
|
16
|
+
return Object.fromEntries(READER_FIELDS.flatMap(key => environment[key] === undefined ? [] : [[key, environment[key]]]));
|
|
17
|
+
}
|
|
18
|
+
/** Metadata discovery uses the Controller's launch environment. No start,
|
|
19
|
+
* retry, credential forwarding or Role mutation belongs to this read port. */
|
|
20
|
+
export async function readTaskAgentCapabilities(store, catalogs, params) {
|
|
21
|
+
if (!params || typeof params !== "object" || Array.isArray(params)) {
|
|
22
|
+
throw usageError("Task capability query parameters are invalid.");
|
|
23
|
+
}
|
|
24
|
+
const input = params;
|
|
25
|
+
if (Object.keys(input).some(key => !["taskId", "roleName", "errorId", "refresh", "reader"].includes(key))
|
|
26
|
+
|| typeof input.taskId !== "string" || input.taskId.length === 0
|
|
27
|
+
|| typeof input.roleName !== "string" || input.roleName.length === 0
|
|
28
|
+
|| (input.errorId !== undefined && (typeof input.errorId !== "string" || input.errorId.length === 0))
|
|
29
|
+
|| (input.refresh !== undefined && typeof input.refresh !== "boolean")
|
|
30
|
+
|| !input.reader || typeof input.reader !== "object" || Array.isArray(input.reader)) {
|
|
31
|
+
throw usageError("Task capability query parameters are invalid.");
|
|
32
|
+
}
|
|
33
|
+
const reader = {};
|
|
34
|
+
for (const [key, value] of Object.entries(input.reader)) {
|
|
35
|
+
if (!READER_FIELDS.includes(key) || typeof value !== "string") {
|
|
36
|
+
throw usageError("Task capability reader contains unsupported fields.");
|
|
37
|
+
}
|
|
38
|
+
reader[key] = value;
|
|
39
|
+
}
|
|
40
|
+
if (Object.keys(reader).length > 0 && reader.YUI_SESSION_SCOPE !== "task"
|
|
41
|
+
&& reader.YUI_SESSION_SCOPE !== "global")
|
|
42
|
+
throw usageError("Managed reader scope is invalid.");
|
|
43
|
+
if (reader.YUI_SESSION_SCOPE === "global") {
|
|
44
|
+
const caller = requireManagedGlobalCaller(store, reader);
|
|
45
|
+
if (caller.roleName !== "operator")
|
|
46
|
+
throw usageError("Only the Operator may query another Role's native configuration.");
|
|
47
|
+
}
|
|
48
|
+
const request = resolveTaskAgentCapabilities({
|
|
49
|
+
taskId: input.taskId, roleName: input.roleName,
|
|
50
|
+
...(input.errorId === undefined ? {} : { errorId: input.errorId }),
|
|
51
|
+
refresh: input.refresh === true,
|
|
52
|
+
}, store, reader);
|
|
53
|
+
const resolved = await catalogs.resolve(request.input);
|
|
54
|
+
const result = {
|
|
55
|
+
...resolved, context: { ...request.context, environmentSource: "controller" }
|
|
56
|
+
};
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
@@ -238,17 +238,12 @@ export class AgentRuntimeObserver {
|
|
|
238
238
|
}
|
|
239
239
|
activeSources() {
|
|
240
240
|
const result = [];
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
.sort(numericCompare)
|
|
248
|
-
.map((taskId) => this.store.getTask(taskId))
|
|
249
|
-
.filter((task) => (task !== null
|
|
250
|
-
&& task.status === "active"
|
|
251
|
-
&& task.executionGate.state === "enabled"));
|
|
241
|
+
const activeTasks = [...new Set(this.store.listActiveTaskIds())]
|
|
242
|
+
.sort(numericCompare)
|
|
243
|
+
.map((taskId) => this.store.getTask(taskId))
|
|
244
|
+
.filter((task) => (task !== null
|
|
245
|
+
&& task.status === "active"
|
|
246
|
+
&& task.executionGate.state === "enabled"));
|
|
252
247
|
for (const task of activeTasks) {
|
|
253
248
|
// A Task still incurs one O(E) event projection. Group those observations
|
|
254
249
|
// by AgentRun and sort each group once so every active AgentRun can reuse the same
|