@pellux/goodvibes-agent 1.1.6 → 1.2.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/CHANGELOG.md +176 -0
- package/README.md +46 -30
- package/dist/package/{ast-grep-napi.linux-x64-gnu-mkk8xwww.node → ast-grep-napi.linux-x64-gnu-swtppvy9.node} +0 -0
- package/dist/package/{ast-grep-napi.linux-x64-musl-ryqtgdv6.node → ast-grep-napi.linux-x64-musl-ttfcdtap.node} +0 -0
- package/dist/package/main.js +132662 -91399
- package/docs/README.md +14 -7
- package/docs/channels-remote-and-api.md +8 -5
- package/docs/connected-host.md +14 -12
- package/docs/getting-started.md +56 -30
- package/docs/knowledge-artifacts-and-multimodal.md +7 -5
- package/docs/project-planning.md +2 -2
- package/docs/providers-and-routing.md +11 -3
- package/docs/tools-and-commands.md +114 -45
- package/docs/voice-and-live-tts.md +3 -1
- package/package.json +3 -2
- package/release/release-notes.md +130 -5
- package/release/release-readiness.json +120 -90
- package/src/agent/assistant-cockpit.ts +247 -0
- package/src/agent/autonomy-schedule-format.ts +96 -0
- package/src/agent/autonomy-schedule.ts +514 -0
- package/src/agent/channel-delivery-receipts.ts +292 -0
- package/src/agent/competitive-feature-inventory.ts +296 -0
- package/src/agent/document-registry-types.ts +106 -0
- package/src/agent/document-registry.ts +734 -0
- package/src/agent/harness-control.ts +2 -2
- package/src/agent/memory-prompt.ts +2 -2
- package/src/agent/operator-actions.ts +50 -6
- package/src/agent/persona-registry.ts +8 -0
- package/src/agent/project-context-files.ts +273 -0
- package/src/agent/prompt-context-receipts.ts +502 -0
- package/src/agent/reminder-schedule-format.ts +16 -2
- package/src/agent/research-run-registry.ts +582 -0
- package/src/agent/research-source-registry.ts +441 -0
- package/src/agent/routine-registry.ts +19 -3
- package/src/agent/routine-schedule-format.ts +27 -2
- package/src/agent/runtime-profile-starters.ts +7 -0
- package/src/agent/runtime-profile.ts +106 -4
- package/src/agent/schedule-edit-format.ts +129 -0
- package/src/agent/schedule-edit.ts +496 -0
- package/src/agent/schedule-next-routes.ts +42 -0
- package/src/agent/setup-wizard-checkpoint.ts +140 -0
- package/src/agent/setup-wizard.ts +447 -0
- package/src/agent/skill-registry-types.ts +102 -0
- package/src/agent/skill-registry.ts +81 -107
- package/src/agent/vibe-confirmation-routes.ts +62 -0
- package/src/agent/vibe-file.ts +285 -0
- package/src/cli/agent-knowledge-command.ts +45 -2
- package/src/cli/help.ts +3 -0
- package/src/cli/profiles-command.ts +25 -11
- package/src/config/agent-settings-policy.ts +1 -18
- package/src/input/agent-workspace-activation.ts +53 -0
- package/src/input/agent-workspace-artifact-browser-editor.ts +494 -0
- package/src/input/agent-workspace-artifact-metadata.ts +17 -0
- package/src/input/agent-workspace-basic-command-editors.ts +5 -1
- package/src/input/agent-workspace-categories.ts +153 -155
- package/src/input/agent-workspace-channel-triage.ts +481 -0
- package/src/input/agent-workspace-channels.ts +263 -0
- package/src/input/agent-workspace-command-editor.ts +152 -0
- package/src/input/agent-workspace-context-snapshot.ts +349 -0
- package/src/input/agent-workspace-delegation-editor-submission.ts +8 -0
- package/src/input/agent-workspace-document-editor.ts +502 -0
- package/src/input/agent-workspace-document-ops-editor.ts +523 -0
- package/src/input/agent-workspace-host-category.ts +1 -1
- package/src/input/agent-workspace-local-library-snapshot.ts +167 -0
- package/src/input/agent-workspace-model-compare-editor.ts +376 -0
- package/src/input/agent-workspace-model-compare-prompt-submission.ts +552 -0
- package/src/input/agent-workspace-model-compare-types.ts +82 -0
- package/src/input/agent-workspace-model-compare-utils.ts +35 -0
- package/src/input/agent-workspace-onboarding-categories.ts +141 -0
- package/src/input/agent-workspace-operations-command-editor-submission.ts +53 -0
- package/src/input/agent-workspace-operations-command-editors.ts +22 -0
- package/src/input/agent-workspace-research-report-editor.ts +212 -0
- package/src/input/agent-workspace-research-run-editor.ts +144 -0
- package/src/input/agent-workspace-research-source-editor.ts +167 -0
- package/src/input/agent-workspace-review-packet-snapshot.ts +593 -0
- package/src/input/agent-workspace-review-packet-utils.ts +265 -0
- package/src/input/agent-workspace-settings.ts +262 -30
- package/src/input/agent-workspace-setup-checkpoint-action.ts +127 -0
- package/src/input/agent-workspace-setup-snapshot.ts +198 -0
- package/src/input/agent-workspace-setup.ts +34 -1
- package/src/input/agent-workspace-snapshot.ts +162 -147
- package/src/input/agent-workspace-types.ts +287 -2
- package/src/input/agent-workspace.ts +18 -0
- package/src/input/command-registry.ts +9 -2
- package/src/input/commands/agent-runtime-profile-runtime.ts +28 -13
- package/src/input/commands/channels-runtime.ts +102 -114
- package/src/input/commands/delegation-runtime.ts +87 -24
- package/src/input/commands/knowledge-browser-flags.ts +12 -0
- package/src/input/commands/knowledge.ts +28 -14
- package/src/input/commands/operator-actions-runtime.ts +6 -3
- package/src/input/commands/schedule-runtime.ts +71 -14
- package/src/input/commands/session-content.ts +2 -2
- package/src/input/commands/shell-core.ts +2 -0
- package/src/input/commands/vibe-runtime.ts +140 -0
- package/src/input/commands.ts +2 -0
- package/src/input/connected-host-routes.ts +123 -0
- package/src/input/settings-modal-types.ts +14 -0
- package/src/main.ts +15 -15
- package/src/panels/qr-panel.ts +2 -2
- package/src/renderer/agent-workspace-context-lines.ts +686 -0
- package/src/renderer/agent-workspace.ts +30 -419
- package/src/renderer/settings-modal-helpers.ts +12 -0
- package/src/renderer/settings-modal.ts +12 -0
- package/src/runtime/bootstrap-command-context.ts +11 -1
- package/src/runtime/bootstrap-command-parts.ts +14 -3
- package/src/runtime/bootstrap-core.ts +43 -1
- package/src/runtime/bootstrap-shell.ts +6 -0
- package/src/runtime/bootstrap.ts +113 -30
- package/src/runtime/connected-host-auth.ts +3 -2
- package/src/runtime/execution-ledger.ts +231 -0
- package/src/runtime/services.ts +88 -10
- package/src/runtime/tool-permission-safety.ts +287 -0
- package/src/shell/session-continuity-hints.ts +39 -0
- package/src/tools/agent-artifacts-tool.ts +606 -0
- package/src/tools/agent-audit-tool.ts +155 -0
- package/src/tools/agent-autonomy-schedule-tool.ts +238 -0
- package/src/tools/agent-autonomy-tool.ts +140 -0
- package/src/tools/agent-channel-send-tool.ts +24 -2
- package/src/tools/agent-channels-tool.ts +140 -0
- package/src/tools/agent-computer-tool.ts +168 -0
- package/src/tools/agent-context-policy.ts +267 -10
- package/src/tools/agent-context-tool.ts +143 -0
- package/src/tools/agent-delegation-tool.ts +128 -0
- package/src/tools/agent-device-tool.ts +240 -0
- package/src/tools/agent-documents-tool.ts +684 -0
- package/src/tools/agent-execution-tool.ts +230 -0
- package/src/tools/agent-harness-agent-orchestration.ts +703 -0
- package/src/tools/agent-harness-autonomy-intake.ts +785 -0
- package/src/tools/agent-harness-autonomy-live-records.ts +588 -0
- package/src/tools/agent-harness-autonomy-queue-types.ts +88 -0
- package/src/tools/agent-harness-autonomy-queue.ts +560 -0
- package/src/tools/agent-harness-background-processes-types.ts +35 -0
- package/src/tools/agent-harness-background-processes.ts +794 -0
- package/src/tools/agent-harness-browser-cockpit-route.ts +219 -0
- package/src/tools/agent-harness-browser-control.ts +338 -0
- package/src/tools/agent-harness-channel-metadata.ts +168 -10
- package/src/tools/agent-harness-cli-command-policy.ts +110 -0
- package/src/tools/agent-harness-command-catalog.ts +4 -2
- package/src/tools/agent-harness-command-runner.ts +42 -0
- package/src/tools/agent-harness-connected-host-status.ts +7 -4
- package/src/tools/agent-harness-delegation-posture.ts +234 -19
- package/src/tools/agent-harness-document-ops-reviewer-readiness.ts +234 -0
- package/src/tools/agent-harness-document-ops-types.ts +72 -0
- package/src/tools/agent-harness-document-ops.ts +671 -0
- package/src/tools/agent-harness-execution-history.ts +489 -0
- package/src/tools/agent-harness-execution-posture.ts +382 -0
- package/src/tools/agent-harness-file-recovery.ts +135 -0
- package/src/tools/agent-harness-keybinding-metadata.ts +16 -12
- package/src/tools/agent-harness-learning-curator-common.ts +102 -0
- package/src/tools/agent-harness-learning-curator-consolidation.ts +295 -0
- package/src/tools/agent-harness-learning-curator-proposals.ts +606 -0
- package/src/tools/agent-harness-learning-curator-types.ts +151 -0
- package/src/tools/agent-harness-learning-curator.ts +417 -0
- package/src/tools/agent-harness-local-model-benchmarks.ts +199 -0
- package/src/tools/agent-harness-local-model-cookbook.ts +238 -0
- package/src/tools/agent-harness-local-model-endpoints.ts +673 -0
- package/src/tools/agent-harness-media-posture.ts +208 -2
- package/src/tools/agent-harness-memory-posture.ts +556 -0
- package/src/tools/agent-harness-metadata.ts +100 -168
- package/src/tools/agent-harness-mode-catalog.ts +84 -33
- package/src/tools/agent-harness-model-catalog.ts +162 -0
- package/src/tools/agent-harness-model-provider-health.ts +186 -0
- package/src/tools/agent-harness-model-readiness.ts +406 -0
- package/src/tools/agent-harness-model-routing-types.ts +266 -0
- package/src/tools/agent-harness-model-routing-utils.ts +30 -0
- package/src/tools/agent-harness-model-routing.ts +137 -190
- package/src/tools/agent-harness-operator-methods.ts +115 -133
- package/src/tools/agent-harness-pairing-posture.ts +431 -18
- package/src/tools/agent-harness-personal-ops-discovery.ts +533 -0
- package/src/tools/agent-harness-personal-ops-intake.ts +385 -0
- package/src/tools/agent-harness-personal-ops-lanes.ts +204 -0
- package/src/tools/agent-harness-personal-ops-records.ts +732 -0
- package/src/tools/agent-harness-personal-ops-runner.ts +637 -0
- package/src/tools/agent-harness-personal-ops-types.ts +222 -0
- package/src/tools/agent-harness-personal-ops.ts +606 -0
- package/src/tools/agent-harness-project-context.ts +144 -0
- package/src/tools/agent-harness-prompt-context.ts +589 -0
- package/src/tools/agent-harness-provider-account-metadata.ts +2 -2
- package/src/tools/agent-harness-release-evidence.ts +9 -7
- package/src/tools/agent-harness-release-readiness.ts +9 -7
- package/src/tools/agent-harness-research-briefing.ts +427 -0
- package/src/tools/agent-harness-research-queue.ts +250 -0
- package/src/tools/agent-harness-research-runs.ts +295 -0
- package/src/tools/agent-harness-research-workflow.ts +322 -0
- package/src/tools/agent-harness-security-posture.ts +2 -2
- package/src/tools/agent-harness-service-posture.ts +9 -9
- package/src/tools/agent-harness-session-metadata.ts +3 -3
- package/src/tools/agent-harness-setup-connected-host.ts +501 -0
- package/src/tools/agent-harness-setup-describe.ts +557 -0
- package/src/tools/agent-harness-setup-handoffs.ts +502 -0
- package/src/tools/agent-harness-setup-model-helpers.ts +101 -0
- package/src/tools/agent-harness-setup-plan.ts +253 -0
- package/src/tools/agent-harness-setup-posture-types.ts +218 -0
- package/src/tools/agent-harness-setup-posture-utils.ts +173 -0
- package/src/tools/agent-harness-setup-posture.ts +449 -221
- package/src/tools/agent-harness-setup-smoke.ts +508 -0
- package/src/tools/agent-harness-sudo-posture.ts +114 -0
- package/src/tools/agent-harness-tool-schema.ts +120 -7
- package/src/tools/agent-harness-tool-types.ts +78 -0
- package/src/tools/agent-harness-tool-utils.ts +43 -0
- package/src/tools/agent-harness-tool.ts +311 -370
- package/src/tools/agent-harness-ui-surface-metadata.ts +76 -69
- package/src/tools/agent-harness-ui-surface-types.ts +46 -0
- package/src/tools/agent-harness-vibe-health.ts +105 -0
- package/src/tools/agent-harness-workspace-action-runner.ts +149 -0
- package/src/tools/agent-harness-workspace-actions.ts +114 -8
- package/src/tools/agent-harness-workspace-editor-execution.ts +214 -0
- package/src/tools/agent-harness-workspace-editor-runner.ts +755 -0
- package/src/tools/agent-host-tool.ts +159 -0
- package/src/tools/agent-knowledge-ingest-tool.ts +34 -1
- package/src/tools/agent-learning-consolidation-core.ts +327 -0
- package/src/tools/agent-learning-consolidation-tool.ts +758 -0
- package/src/tools/agent-memory-tool.ts +214 -0
- package/src/tools/agent-model-compare-export.ts +315 -0
- package/src/tools/agent-model-compare-handoff.ts +592 -0
- package/src/tools/agent-model-compare-judgment.ts +633 -0
- package/src/tools/agent-model-compare-run.ts +722 -0
- package/src/tools/agent-model-compare-tool.ts +698 -0
- package/src/tools/agent-model-compare-types.ts +191 -0
- package/src/tools/agent-model-compare-utils.ts +93 -0
- package/src/tools/agent-models-tool.ts +208 -0
- package/src/tools/agent-operator-action-tool.ts +1 -1
- package/src/tools/agent-operator-method-tool.ts +643 -0
- package/src/tools/agent-personal-ops-tool.ts +197 -0
- package/src/tools/agent-policy-explanation.ts +415 -0
- package/src/tools/agent-research-report-tool.ts +608 -0
- package/src/tools/agent-research-runs-tool.ts +434 -0
- package/src/tools/agent-research-sources-tool.ts +443 -0
- package/src/tools/agent-research-tool.ts +687 -0
- package/src/tools/agent-review-packet-presets-core.ts +757 -0
- package/src/tools/agent-review-packet-presets-tool.ts +466 -0
- package/src/tools/agent-review-packet-share-tool.ts +305 -0
- package/src/tools/agent-route-planner-candidates-setup.ts +411 -0
- package/src/tools/agent-route-planner-candidates-surfaces.ts +432 -0
- package/src/tools/agent-route-planner-candidates-work.ts +251 -0
- package/src/tools/agent-route-planner-helpers.ts +667 -0
- package/src/tools/agent-route-planner.ts +185 -0
- package/src/tools/agent-route-tool.ts +105 -0
- package/src/tools/agent-schedule-edit-tool.ts +210 -0
- package/src/tools/agent-schedule-tool.ts +282 -0
- package/src/tools/agent-security-tool.ts +145 -0
- package/src/tools/agent-sessions-tool.ts +122 -0
- package/src/tools/agent-settings-import-tool.ts +104 -0
- package/src/tools/agent-settings-tool.ts +176 -0
- package/src/tools/agent-setup-tool.ts +226 -0
- package/src/tools/agent-support-tool.ts +122 -0
- package/src/tools/agent-terminal-process-tools.ts +167 -0
- package/src/tools/agent-tool-policy-guard-types.ts +77 -0
- package/src/tools/agent-tool-policy-guard.ts +110 -89
- package/src/tools/agent-vibe-tool.ts +297 -0
- package/src/tools/agent-work-plan-tool.ts +265 -6
- package/src/tools/agent-workspace-tool.ts +305 -0
- package/src/tools/artifact-archive.ts +169 -0
- package/src/tools/tool-definition-compaction.ts +36 -0
- package/src/tools/tool-execution-safety.ts +41 -0
- package/src/version.ts +1 -1
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
import type { ArtifactDescriptor } from '@pellux/goodvibes-sdk/platform/artifacts';
|
|
2
|
+
import type { CommandContext } from './command-registry.ts';
|
|
3
|
+
import { AgentDocumentRegistry, type AgentDocumentRecord } from '../agent/document-registry.ts';
|
|
4
|
+
import type { AgentWorkspaceReviewPacketDefaults, AgentWorkspaceReviewPacketTimeline, AgentWorkspaceReviewPacketTimelineEvent, AgentWorkspaceReviewPacketWizard, AgentWorkspaceReviewPacketWizardStep, AgentWorkspaceReviewPacketWizardStepStatus, AgentWorkspaceReviewerReadinessBadge } from './agent-workspace-types.ts';
|
|
5
|
+
import { readArtifactMetadataNumber, readArtifactMetadataString, readArtifactMetadataStringList } from './agent-workspace-artifact-metadata.ts';
|
|
6
|
+
import { buildReviewPacketPresetLineage, compactTimelineText, isDocumentExportArtifact, isModelCompareArtifact, isModelCompareExportArtifact, isModelCompareJudgmentArtifact, isModelCompareRouteDecisionArtifact, isReviewerHandoffArchiveArtifact, isReviewerHandoffArtifact, isReviewPacketPresetArtifact, isoToEpoch, reviewPacketPresetFreshness, uniqueStrings } from './agent-workspace-review-packet-utils.ts';
|
|
7
|
+
|
|
8
|
+
export function readDocumentDrafts(context: CommandContext): readonly AgentDocumentRecord[] {
|
|
9
|
+
try {
|
|
10
|
+
const shellPaths = context.workspace?.shellPaths;
|
|
11
|
+
if (!shellPaths) return [];
|
|
12
|
+
return AgentDocumentRegistry.fromShellPaths(shellPaths).list();
|
|
13
|
+
} catch {
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function buildReviewPacketTimeline(
|
|
19
|
+
documents: readonly AgentDocumentRecord[],
|
|
20
|
+
artifacts: readonly ArtifactDescriptor[],
|
|
21
|
+
artifactListAvailable: boolean,
|
|
22
|
+
): AgentWorkspaceReviewPacketTimeline {
|
|
23
|
+
const events: AgentWorkspaceReviewPacketTimelineEvent[] = [];
|
|
24
|
+
for (const document of documents) {
|
|
25
|
+
const openComments = document.comments.filter((comment) => comment.status === 'open').length;
|
|
26
|
+
const proposedSuggestions = document.suggestions.filter((suggestion) => suggestion.status === 'proposed').length;
|
|
27
|
+
events.push({
|
|
28
|
+
id: `document:${document.id}`,
|
|
29
|
+
kind: 'document',
|
|
30
|
+
at: isoToEpoch(document.updatedAt),
|
|
31
|
+
label: `Document ${document.status}: ${document.title}`,
|
|
32
|
+
detail: `${document.versions.length} version(s), ${openComments} open comment(s), ${proposedSuggestions} proposed suggestion(s), ${document.attachments.length} attachment(s), last artifact ${document.lastArtifactId ?? 'none'}`,
|
|
33
|
+
status: openComments + proposedSuggestions > 0 ? 'attention' : document.status === 'reviewed' ? 'ready' : 'info',
|
|
34
|
+
route: `agent_documents show documentId:"${document.id}" includeVersions:true`,
|
|
35
|
+
sourceId: document.id,
|
|
36
|
+
});
|
|
37
|
+
for (const comment of document.comments) {
|
|
38
|
+
events.push({
|
|
39
|
+
id: `comment:${document.id}:${comment.id}`,
|
|
40
|
+
kind: 'comment',
|
|
41
|
+
at: isoToEpoch(comment.resolvedAt ?? comment.updatedAt ?? comment.createdAt),
|
|
42
|
+
label: `${comment.status === 'open' ? 'Open' : 'Resolved'} comment: ${document.title}`,
|
|
43
|
+
detail: compactTimelineText(comment.body),
|
|
44
|
+
status: comment.status === 'open' ? 'attention' : 'complete',
|
|
45
|
+
route: comment.status === 'open'
|
|
46
|
+
? `agent_documents resolveComment documentId:"${document.id}" commentId:"${comment.id}" confirm:true explicitUserRequest:"..."`
|
|
47
|
+
: `agent_documents show documentId:"${document.id}" includeVersions:true`,
|
|
48
|
+
sourceId: comment.id,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
for (const suggestion of document.suggestions) {
|
|
52
|
+
events.push({
|
|
53
|
+
id: `suggestion:${document.id}:${suggestion.id}`,
|
|
54
|
+
kind: 'suggestion',
|
|
55
|
+
at: isoToEpoch(suggestion.resolvedAt ?? suggestion.updatedAt ?? suggestion.createdAt),
|
|
56
|
+
label: `${suggestion.status === 'proposed' ? 'Proposed' : suggestion.status === 'accepted' ? 'Accepted' : 'Rejected'} suggestion: ${suggestion.title}`,
|
|
57
|
+
detail: compactTimelineText(`${document.title}: ${suggestion.summary}`),
|
|
58
|
+
status: suggestion.status === 'proposed' ? 'attention' : 'complete',
|
|
59
|
+
route: suggestion.status === 'proposed'
|
|
60
|
+
? `agent_documents acceptSuggestion documentId:"${document.id}" suggestionId:"${suggestion.id}" confirm:true explicitUserRequest:"..." or agent_documents rejectSuggestion documentId:"${document.id}" suggestionId:"${suggestion.id}" confirm:true explicitUserRequest:"..."`
|
|
61
|
+
: `agent_documents show documentId:"${document.id}" includeVersions:true`,
|
|
62
|
+
sourceId: suggestion.id,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
for (const attachment of document.attachments) {
|
|
66
|
+
events.push({
|
|
67
|
+
id: `attachment:${document.id}:${attachment.id}`,
|
|
68
|
+
kind: 'attachment',
|
|
69
|
+
at: isoToEpoch(attachment.updatedAt ?? attachment.createdAt),
|
|
70
|
+
label: `Attached artifact: ${attachment.label}`,
|
|
71
|
+
detail: `${document.title}: ${attachment.artifactId}${attachment.note ? ` - ${compactTimelineText(attachment.note, 64)}` : ''}`,
|
|
72
|
+
status: 'complete',
|
|
73
|
+
route: `agent_artifacts show artifactId:"${attachment.artifactId}"`,
|
|
74
|
+
sourceId: attachment.artifactId,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
for (const artifact of artifacts) {
|
|
80
|
+
const metadata = artifact.metadata;
|
|
81
|
+
if (isDocumentExportArtifact(artifact)) {
|
|
82
|
+
const documentId = readArtifactMetadataString(metadata, 'documentId') || 'unknown-document';
|
|
83
|
+
const versionId = readArtifactMetadataString(metadata, 'versionId') || 'unknown-version';
|
|
84
|
+
events.push({
|
|
85
|
+
id: `document-export:${artifact.id}`,
|
|
86
|
+
kind: 'document-export',
|
|
87
|
+
at: artifact.createdAt,
|
|
88
|
+
label: `Document export: ${documentId}`,
|
|
89
|
+
detail: `version ${versionId}; artifact ${artifact.id}`,
|
|
90
|
+
status: 'complete',
|
|
91
|
+
route: `agent_artifacts show artifactId:"${artifact.id}"`,
|
|
92
|
+
sourceId: artifact.id,
|
|
93
|
+
});
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (isModelCompareArtifact(artifact)) {
|
|
97
|
+
const comparisonId = readArtifactMetadataString(metadata, 'comparisonId') || artifact.id;
|
|
98
|
+
const completed = readArtifactMetadataNumber(metadata, 'completedCandidates');
|
|
99
|
+
const candidates = readArtifactMetadataNumber(metadata, 'candidateCount');
|
|
100
|
+
const source = readArtifactMetadataString(metadata, 'sourceArtifactId') || readArtifactMetadataString(metadata, 'documentId') || 'none';
|
|
101
|
+
const revealed = metadata.revealIncludedInTranscript === true;
|
|
102
|
+
events.push({
|
|
103
|
+
id: `compare:${artifact.id}`,
|
|
104
|
+
kind: 'compare',
|
|
105
|
+
at: artifact.createdAt,
|
|
106
|
+
label: `Blind compare ${revealed ? 'revealed' : 'hidden'}: ${comparisonId}`,
|
|
107
|
+
detail: `${completed ?? '?'}/${candidates ?? '?'} candidate(s) complete; source ${source}`,
|
|
108
|
+
status: revealed ? 'ready' : 'attention',
|
|
109
|
+
route: revealed ? `agent_model_compare review artifactId:"${artifact.id}" reveal:true` : `agent_model_compare reveal artifactId:"${artifact.id}"`,
|
|
110
|
+
sourceId: artifact.id,
|
|
111
|
+
});
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (isModelCompareJudgmentArtifact(artifact)) {
|
|
115
|
+
const comparisonId = readArtifactMetadataString(metadata, 'comparisonId') || 'unknown-comparison';
|
|
116
|
+
const winnerBlindId = readArtifactMetadataString(metadata, 'winnerBlindId') || 'unknown-winner';
|
|
117
|
+
const winnerModel = readArtifactMetadataString(metadata, 'winnerModel');
|
|
118
|
+
const revealed = metadata.revealIncludedInJudgment === true && winnerModel.length > 0;
|
|
119
|
+
events.push({
|
|
120
|
+
id: `judgment:${artifact.id}`,
|
|
121
|
+
kind: 'judgment',
|
|
122
|
+
at: artifact.createdAt,
|
|
123
|
+
label: `Comparison judgment ${revealed ? 'revealed' : 'hidden'}: ${comparisonId}`,
|
|
124
|
+
detail: revealed ? `winner ${winnerModel}; blind slot ${winnerBlindId}` : `winner blind slot ${winnerBlindId}; reveal needed before route decisions`,
|
|
125
|
+
status: 'attention',
|
|
126
|
+
route: revealed
|
|
127
|
+
? `agent_model_compare apply artifactId:"${artifact.id}" confirm:true explicitUserRequest:"..."`
|
|
128
|
+
: `agent_model_compare review artifactId:"${artifact.id}"`,
|
|
129
|
+
sourceId: artifact.id,
|
|
130
|
+
});
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (isModelCompareRouteDecisionArtifact(artifact)) {
|
|
134
|
+
const comparisonId = readArtifactMetadataString(metadata, 'comparisonId') || 'unknown-comparison';
|
|
135
|
+
const decisionId = readArtifactMetadataString(metadata, 'decisionId') || artifact.id;
|
|
136
|
+
const decision = readArtifactMetadataString(metadata, 'decision') || 'unknown-decision';
|
|
137
|
+
const judgmentArtifactId = readArtifactMetadataString(metadata, 'judgmentArtifactId') || 'unknown-judgment';
|
|
138
|
+
const selectedModel = readArtifactMetadataString(metadata, 'selectedModel') || readArtifactMetadataString(metadata, 'currentModel') || 'unknown-model';
|
|
139
|
+
events.push({
|
|
140
|
+
id: `route-decision:${artifact.id}`,
|
|
141
|
+
kind: 'route-decision',
|
|
142
|
+
at: artifact.createdAt,
|
|
143
|
+
label: `Route decision: ${decisionId}`,
|
|
144
|
+
detail: `${comparisonId}; ${decision}; judgment ${judgmentArtifactId}; selected ${selectedModel}`,
|
|
145
|
+
status: 'complete',
|
|
146
|
+
route: `agent_artifacts show artifactId:"${artifact.id}"`,
|
|
147
|
+
sourceId: artifact.id,
|
|
148
|
+
});
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (isReviewPacketPresetArtifact(artifact)) {
|
|
152
|
+
const name = readArtifactMetadataString(metadata, 'name') || artifact.filename || artifact.id;
|
|
153
|
+
const summary = readArtifactMetadataString(metadata, 'summary') || 'review packet preset';
|
|
154
|
+
const freshness = reviewPacketPresetFreshness(artifact, artifacts);
|
|
155
|
+
const sourceArtifactId = readArtifactMetadataString(metadata, 'revealedJudgmentArtifactId')
|
|
156
|
+
|| readArtifactMetadataString(metadata, 'judgmentArtifactId')
|
|
157
|
+
|| readArtifactMetadataString(metadata, 'comparisonArtifactId')
|
|
158
|
+
|| readArtifactMetadataString(metadata, 'documentExportArtifactId')
|
|
159
|
+
|| 'none';
|
|
160
|
+
const handoffArtifactId = readArtifactMetadataString(metadata, 'handoffArtifactId') || 'none';
|
|
161
|
+
const relatedCount = readArtifactMetadataStringList(metadata, 'relatedArtifactIds').length;
|
|
162
|
+
events.push({
|
|
163
|
+
id: `packet-preset:${artifact.id}`,
|
|
164
|
+
kind: 'packet-preset',
|
|
165
|
+
at: artifact.createdAt,
|
|
166
|
+
label: `Packet preset: ${name}`,
|
|
167
|
+
detail: `${compactTimelineText(summary, 72)}; source ${sourceArtifactId}; handoff ${handoffArtifactId}; ${relatedCount} related artifact(s); ${freshness.summary}`,
|
|
168
|
+
status: freshness.status,
|
|
169
|
+
route: `agent_review_packet_presets show artifactId:"${artifact.id}"`,
|
|
170
|
+
sourceId: artifact.id,
|
|
171
|
+
});
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (isModelCompareExportArtifact(artifact)) {
|
|
175
|
+
const comparisonId = readArtifactMetadataString(metadata, 'comparisonId') || 'unknown-comparison';
|
|
176
|
+
const sourceKind = readArtifactMetadataString(metadata, 'sourceKind') || 'unknown';
|
|
177
|
+
events.push({
|
|
178
|
+
id: `compare-export:${artifact.id}`,
|
|
179
|
+
kind: 'compare-export',
|
|
180
|
+
at: artifact.createdAt,
|
|
181
|
+
label: `Compare report: ${comparisonId}`,
|
|
182
|
+
detail: `${sourceKind} report artifact ${artifact.id}`,
|
|
183
|
+
status: 'complete',
|
|
184
|
+
route: `agent_artifacts show artifactId:"${artifact.id}"`,
|
|
185
|
+
sourceId: artifact.id,
|
|
186
|
+
});
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (isReviewerHandoffArtifact(artifact)) {
|
|
190
|
+
const handoffId = readArtifactMetadataString(metadata, 'handoffId') || artifact.id;
|
|
191
|
+
const comparisonId = readArtifactMetadataString(metadata, 'comparisonId') || 'unknown-comparison';
|
|
192
|
+
const sourceKind = readArtifactMetadataString(metadata, 'sourceKind') || 'unknown';
|
|
193
|
+
const relatedCount = readArtifactMetadataStringList(metadata, 'relatedArtifactIds').length;
|
|
194
|
+
events.push({
|
|
195
|
+
id: `handoff:${artifact.id}`,
|
|
196
|
+
kind: 'handoff',
|
|
197
|
+
at: artifact.createdAt,
|
|
198
|
+
label: `Reviewer handoff: ${handoffId}`,
|
|
199
|
+
detail: `${comparisonId}; source ${sourceKind}; ${relatedCount} related artifact(s)`,
|
|
200
|
+
status: relatedCount > 0 ? 'ready' : 'attention',
|
|
201
|
+
route: relatedCount > 0
|
|
202
|
+
? `agent_model_compare handoffDiff leftArtifactId:"${artifact.id}" rightArtifactId:"..."`
|
|
203
|
+
: `agent_model_compare handoff artifactId:"${readArtifactMetadataString(metadata, 'sourceArtifactId') || artifact.id}" relatedArtifactIds:"..." confirm:true explicitUserRequest:"..."`,
|
|
204
|
+
sourceId: artifact.id,
|
|
205
|
+
});
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
if (isReviewerHandoffArchiveArtifact(artifact)) {
|
|
209
|
+
const archiveId = readArtifactMetadataString(metadata, 'archiveId') || artifact.id;
|
|
210
|
+
const comparisonId = readArtifactMetadataString(metadata, 'comparisonId') || 'unknown-comparison';
|
|
211
|
+
const artifactCount = readArtifactMetadataNumber(metadata, 'artifactCount');
|
|
212
|
+
events.push({
|
|
213
|
+
id: `handoff-archive:${artifact.id}`,
|
|
214
|
+
kind: 'handoff-archive',
|
|
215
|
+
at: artifact.createdAt,
|
|
216
|
+
label: `Handoff archive: ${archiveId}`,
|
|
217
|
+
detail: `${comparisonId}; ${artifactCount ?? '?'} artifact(s) packaged`,
|
|
218
|
+
status: 'complete',
|
|
219
|
+
route: `agent_artifacts show artifactId:"${artifact.id}"`,
|
|
220
|
+
sourceId: artifact.id,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const ordered = events
|
|
226
|
+
.filter((event) => Number.isFinite(event.at))
|
|
227
|
+
.sort((left, right) => right.at - left.at || left.id.localeCompare(right.id));
|
|
228
|
+
const attention = ordered.find((event) => event.status === 'attention');
|
|
229
|
+
return {
|
|
230
|
+
available: artifactListAvailable,
|
|
231
|
+
count: ordered.length,
|
|
232
|
+
next: !artifactListAvailable
|
|
233
|
+
? 'Artifact listing is unavailable; timeline shows document-local events only.'
|
|
234
|
+
: attention
|
|
235
|
+
? `${attention.label}: ${attention.detail}`
|
|
236
|
+
: ordered.length > 0
|
|
237
|
+
? 'Review packet timeline is clear; export, handoff, archive, or route decisions can use the visible readiness checks.'
|
|
238
|
+
: 'Create or attach a document, source artifact, comparison, judgment, handoff, or archive to start a review packet timeline.',
|
|
239
|
+
items: ordered.slice(0, 8),
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export function buildReviewPacketDefaults(
|
|
244
|
+
documents: readonly AgentDocumentRecord[],
|
|
245
|
+
artifacts: readonly ArtifactDescriptor[],
|
|
246
|
+
): AgentWorkspaceReviewPacketDefaults {
|
|
247
|
+
const latestDocument = [...documents]
|
|
248
|
+
.filter((document) => document.status !== 'archived')
|
|
249
|
+
.sort((left, right) => isoToEpoch(right.updatedAt) - isoToEpoch(left.updatedAt) || left.id.localeCompare(right.id))[0] ?? null;
|
|
250
|
+
const latestDocumentExport = artifacts.filter(isDocumentExportArtifact).sort((left, right) => right.createdAt - left.createdAt)[0] ?? null;
|
|
251
|
+
const latestComparison = artifacts.filter(isModelCompareArtifact).sort((left, right) => right.createdAt - left.createdAt)[0] ?? null;
|
|
252
|
+
const latestJudgment = artifacts.filter(isModelCompareJudgmentArtifact).sort((left, right) => right.createdAt - left.createdAt)[0] ?? null;
|
|
253
|
+
const latestRevealedJudgment = artifacts
|
|
254
|
+
.filter((artifact) => (
|
|
255
|
+
isModelCompareJudgmentArtifact(artifact)
|
|
256
|
+
&& artifact.metadata.revealIncludedInJudgment === true
|
|
257
|
+
&& readArtifactMetadataString(artifact.metadata, 'winnerModel').length > 0
|
|
258
|
+
))
|
|
259
|
+
.sort((left, right) => right.createdAt - left.createdAt)[0] ?? null;
|
|
260
|
+
const latestHandoff = artifacts.filter(isReviewerHandoffArtifact).sort((left, right) => right.createdAt - left.createdAt)[0] ?? null;
|
|
261
|
+
const latestHandoffArchive = artifacts.filter(isReviewerHandoffArchiveArtifact).sort((left, right) => right.createdAt - left.createdAt)[0] ?? null;
|
|
262
|
+
const latestPreset = artifacts.filter(isReviewPacketPresetArtifact).sort((left, right) => right.createdAt - left.createdAt)[0] ?? null;
|
|
263
|
+
const presetMetadata = latestPreset?.metadata ?? {};
|
|
264
|
+
const latestRevealedJudgmentComparisonId = readArtifactMetadataString(latestRevealedJudgment?.metadata ?? {}, 'comparisonId');
|
|
265
|
+
const latestRouteDecision = artifacts
|
|
266
|
+
.filter(isModelCompareRouteDecisionArtifact)
|
|
267
|
+
.filter((artifact) => {
|
|
268
|
+
if (!latestRevealedJudgment) return true;
|
|
269
|
+
const judgmentArtifactId = readArtifactMetadataString(artifact.metadata, 'judgmentArtifactId');
|
|
270
|
+
const comparisonId = readArtifactMetadataString(artifact.metadata, 'comparisonId');
|
|
271
|
+
return judgmentArtifactId === latestRevealedJudgment.id || (latestRevealedJudgmentComparisonId.length > 0 && comparisonId === latestRevealedJudgmentComparisonId);
|
|
272
|
+
})
|
|
273
|
+
.sort((left, right) => right.createdAt - left.createdAt)[0] ?? null;
|
|
274
|
+
const liveRelatedArtifactIds = uniqueStrings([
|
|
275
|
+
latestDocumentExport?.id,
|
|
276
|
+
latestDocument?.lastArtifactId,
|
|
277
|
+
...(latestDocument?.attachments.map((attachment) => attachment.artifactId) ?? []),
|
|
278
|
+
readArtifactMetadataString(latestComparison?.metadata ?? {}, 'sourceArtifactId'),
|
|
279
|
+
...readArtifactMetadataStringList(latestHandoff?.metadata ?? {}, 'relatedArtifactIds'),
|
|
280
|
+
], 8);
|
|
281
|
+
const presetRelatedArtifactIds = readArtifactMetadataStringList(presetMetadata, 'relatedArtifactIds').slice(0, 8);
|
|
282
|
+
const relatedArtifactIds = liveRelatedArtifactIds.length > 0 ? liveRelatedArtifactIds : presetRelatedArtifactIds;
|
|
283
|
+
const documentId = (latestDocument?.id ?? readArtifactMetadataString(presetMetadata, 'documentId')) || null;
|
|
284
|
+
const documentTitle = (latestDocument?.title ?? readArtifactMetadataString(presetMetadata, 'documentTitle')) || null;
|
|
285
|
+
const documentExportArtifactId = (latestDocumentExport?.id ?? readArtifactMetadataString(presetMetadata, 'documentExportArtifactId')) || null;
|
|
286
|
+
const comparisonArtifactId = (latestComparison?.id ?? readArtifactMetadataString(presetMetadata, 'comparisonArtifactId')) || null;
|
|
287
|
+
const judgmentArtifactId = (latestJudgment?.id ?? readArtifactMetadataString(presetMetadata, 'judgmentArtifactId')) || null;
|
|
288
|
+
const revealedJudgmentArtifactId = (latestRevealedJudgment?.id ?? readArtifactMetadataString(presetMetadata, 'revealedJudgmentArtifactId')) || null;
|
|
289
|
+
const routeDecisionArtifactId = (latestRouteDecision?.id ?? readArtifactMetadataString(presetMetadata, 'routeDecisionArtifactId')) || null;
|
|
290
|
+
const routeDecision = latestRouteDecision
|
|
291
|
+
? readArtifactMetadataString(latestRouteDecision.metadata, 'decision') || null
|
|
292
|
+
: readArtifactMetadataString(presetMetadata, 'routeDecision') || null;
|
|
293
|
+
const handoffArtifactId = (latestHandoff?.id ?? readArtifactMetadataString(presetMetadata, 'handoffArtifactId')) || null;
|
|
294
|
+
const handoffArchiveArtifactId = (latestHandoffArchive?.id ?? readArtifactMetadataString(presetMetadata, 'handoffArchiveArtifactId')) || null;
|
|
295
|
+
const sourceArtifactId = revealedJudgmentArtifactId ?? judgmentArtifactId ?? comparisonArtifactId ?? null;
|
|
296
|
+
const reviewPacketPresetName = readArtifactMetadataString(presetMetadata, 'name') || null;
|
|
297
|
+
const reviewPacketPresetLineage = buildReviewPacketPresetLineage(latestPreset);
|
|
298
|
+
const summary = [
|
|
299
|
+
documentId ? `document ${documentId}` : '',
|
|
300
|
+
sourceArtifactId ? `source ${sourceArtifactId}` : '',
|
|
301
|
+
handoffArtifactId ? `handoff ${handoffArtifactId}` : '',
|
|
302
|
+
relatedArtifactIds.length > 0 ? `${relatedArtifactIds.length} related` : '',
|
|
303
|
+
latestPreset ? `preset ${latestPreset.id}` : '',
|
|
304
|
+
].filter(Boolean).join('; ') || 'no packet defaults yet';
|
|
305
|
+
return {
|
|
306
|
+
documentId,
|
|
307
|
+
documentTitle,
|
|
308
|
+
documentExportArtifactId,
|
|
309
|
+
comparisonArtifactId,
|
|
310
|
+
judgmentArtifactId,
|
|
311
|
+
revealedJudgmentArtifactId,
|
|
312
|
+
routeDecisionArtifactId,
|
|
313
|
+
routeDecision,
|
|
314
|
+
handoffArtifactId,
|
|
315
|
+
handoffArchiveArtifactId,
|
|
316
|
+
reviewPacketPresetArtifactId: latestPreset?.id ?? null,
|
|
317
|
+
reviewPacketPresetName,
|
|
318
|
+
reviewPacketPresetLineage,
|
|
319
|
+
relatedArtifactIds,
|
|
320
|
+
summary,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function packetStepStatus(done: boolean, priorDone: boolean): AgentWorkspaceReviewPacketWizardStepStatus {
|
|
325
|
+
if (done) return 'done';
|
|
326
|
+
return priorDone ? 'current' : 'blocked';
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function buildReviewPacketWizardStep(input: {
|
|
330
|
+
readonly id: string;
|
|
331
|
+
readonly label: string;
|
|
332
|
+
readonly status: AgentWorkspaceReviewPacketWizardStepStatus;
|
|
333
|
+
readonly detail: string;
|
|
334
|
+
readonly userRoute: string;
|
|
335
|
+
readonly modelRoute: string;
|
|
336
|
+
readonly actionId: string;
|
|
337
|
+
readonly backtrackRoute?: string | null;
|
|
338
|
+
}): AgentWorkspaceReviewPacketWizardStep {
|
|
339
|
+
return {
|
|
340
|
+
id: input.id,
|
|
341
|
+
label: input.label,
|
|
342
|
+
status: input.status,
|
|
343
|
+
detail: input.detail,
|
|
344
|
+
userRoute: input.userRoute,
|
|
345
|
+
modelRoute: input.modelRoute,
|
|
346
|
+
actionId: input.actionId,
|
|
347
|
+
backtrackRoute: input.backtrackRoute ?? (input.status === 'done' ? input.modelRoute : null),
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
export function buildReviewPacketWizard(
|
|
352
|
+
documents: readonly AgentDocumentRecord[],
|
|
353
|
+
artifactListAvailable: boolean,
|
|
354
|
+
defaults: AgentWorkspaceReviewPacketDefaults,
|
|
355
|
+
): AgentWorkspaceReviewPacketWizard {
|
|
356
|
+
const latestDocument = [...documents]
|
|
357
|
+
.filter((document) => document.status !== 'archived')
|
|
358
|
+
.sort((left, right) => isoToEpoch(right.updatedAt) - isoToEpoch(left.updatedAt) || left.id.localeCompare(right.id))[0] ?? null;
|
|
359
|
+
const openComments = latestDocument?.comments.filter((comment) => comment.status === 'open').length ?? 0;
|
|
360
|
+
const proposedSuggestions = latestDocument?.suggestions.filter((suggestion) => suggestion.status === 'proposed').length ?? 0;
|
|
361
|
+
const documentReviewed = Boolean(latestDocument && openComments === 0 && proposedSuggestions === 0);
|
|
362
|
+
const documentExported = Boolean(defaults.documentExportArtifactId || latestDocument?.lastArtifactId);
|
|
363
|
+
const judgmentReady = Boolean(defaults.revealedJudgmentArtifactId);
|
|
364
|
+
const handoffReady = Boolean(defaults.handoffArtifactId && defaults.relatedArtifactIds.length > 0);
|
|
365
|
+
const archiveReady = Boolean(defaults.handoffArchiveArtifactId);
|
|
366
|
+
const routeDecisionDone = Boolean(defaults.routeDecisionArtifactId || archiveReady);
|
|
367
|
+
const presetLineage = defaults.reviewPacketPresetLineage;
|
|
368
|
+
const finalArchiveReview = archiveReady
|
|
369
|
+
? [
|
|
370
|
+
`Inspect final archive ${defaults.handoffArchiveArtifactId}.`,
|
|
371
|
+
presetLineage?.refreshed
|
|
372
|
+
? `Verify refreshed preset lineage: ${presetLineage.summary}.`
|
|
373
|
+
: presetLineage
|
|
374
|
+
? `Preset lineage: ${presetLineage.summary}.`
|
|
375
|
+
: 'No saved packet preset lineage is attached.',
|
|
376
|
+
'Use Documents & Compare -> Share review packet only after the user confirms the delivery target.',
|
|
377
|
+
].join(' ')
|
|
378
|
+
: 'Final evidence review stays pending until a reviewer handoff ZIP archive exists.';
|
|
379
|
+
const documentRoute = latestDocument
|
|
380
|
+
? `agent_documents show documentId:"${latestDocument.id}" includeVersions:true`
|
|
381
|
+
: 'agent_documents list';
|
|
382
|
+
const steps: AgentWorkspaceReviewPacketWizardStep[] = [];
|
|
383
|
+
steps.push(buildReviewPacketWizardStep({
|
|
384
|
+
id: 'draft-review',
|
|
385
|
+
label: 'Draft review',
|
|
386
|
+
status: documentReviewed ? 'done' : 'current',
|
|
387
|
+
detail: latestDocument
|
|
388
|
+
? documentReviewed
|
|
389
|
+
? `${latestDocument.title} has no open comments or proposed suggestions.`
|
|
390
|
+
: `${latestDocument.title} has ${openComments} open comment(s) and ${proposedSuggestions} proposed suggestion(s) to resolve before export.`
|
|
391
|
+
: 'Create or select a document draft before building a reviewer packet.',
|
|
392
|
+
userRoute: latestDocument ? 'Documents & Compare -> Show document draft' : 'Documents & Compare -> Create document draft',
|
|
393
|
+
modelRoute: latestDocument
|
|
394
|
+
? documentRoute
|
|
395
|
+
: 'agent_harness mode:"workspace_action" actionId:"document-create-draft"',
|
|
396
|
+
actionId: latestDocument ? 'document-show-draft' : 'document-create-draft',
|
|
397
|
+
}));
|
|
398
|
+
steps.push(buildReviewPacketWizardStep({
|
|
399
|
+
id: 'document-export',
|
|
400
|
+
label: 'Document export',
|
|
401
|
+
status: packetStepStatus(documentExported, documentReviewed),
|
|
402
|
+
detail: documentExported
|
|
403
|
+
? `Document evidence is exported as ${defaults.documentExportArtifactId ?? latestDocument?.lastArtifactId}.`
|
|
404
|
+
: documentReviewed
|
|
405
|
+
? 'Export the reviewed draft as a saved artifact for comparison and handoff evidence.'
|
|
406
|
+
: 'Resolve draft review items before exporting reviewer evidence.',
|
|
407
|
+
userRoute: 'Documents & Compare -> Export document artifact',
|
|
408
|
+
modelRoute: latestDocument
|
|
409
|
+
? `agent_documents export documentId:"${latestDocument.id}" confirm:true explicitUserRequest:"..."`
|
|
410
|
+
: 'agent_harness mode:"workspace_action" actionId:"document-export-draft"',
|
|
411
|
+
actionId: 'document-export-draft',
|
|
412
|
+
backtrackRoute: defaults.documentExportArtifactId
|
|
413
|
+
? `agent_artifacts show artifactId:"${defaults.documentExportArtifactId}"`
|
|
414
|
+
: null,
|
|
415
|
+
}));
|
|
416
|
+
steps.push(buildReviewPacketWizardStep({
|
|
417
|
+
id: 'compare-judgment',
|
|
418
|
+
label: 'Compare judgment',
|
|
419
|
+
status: packetStepStatus(judgmentReady, documentExported),
|
|
420
|
+
detail: judgmentReady
|
|
421
|
+
? `Revealed judgment ${defaults.revealedJudgmentArtifactId} is ready for route review.`
|
|
422
|
+
: defaults.judgmentArtifactId
|
|
423
|
+
? `Judgment ${defaults.judgmentArtifactId} exists, but winner identity is not revealed for route decisions.`
|
|
424
|
+
: defaults.comparisonArtifactId
|
|
425
|
+
? `Comparison ${defaults.comparisonArtifactId} is available; save or reveal a judgment before handoff.`
|
|
426
|
+
: documentExported
|
|
427
|
+
? 'Run a blind comparison from the exported document evidence, then save a revealed judgment.'
|
|
428
|
+
: 'Export document evidence before comparing models.',
|
|
429
|
+
userRoute: defaults.comparisonArtifactId ? 'Documents & Compare -> Review saved compare' : 'Documents & Compare -> Run blind compare',
|
|
430
|
+
modelRoute: defaults.revealedJudgmentArtifactId
|
|
431
|
+
? `agent_model_compare review artifactId:"${defaults.revealedJudgmentArtifactId}" reveal:true`
|
|
432
|
+
: defaults.judgmentArtifactId
|
|
433
|
+
? `agent_model_compare review artifactId:"${defaults.judgmentArtifactId}"`
|
|
434
|
+
: defaults.comparisonArtifactId
|
|
435
|
+
? `agent_model_compare review artifactId:"${defaults.comparisonArtifactId}"`
|
|
436
|
+
: 'agent_harness mode:"workspace_action" actionId:"document-run-compare"',
|
|
437
|
+
actionId: defaults.comparisonArtifactId ? 'document-review-compare' : 'document-run-compare',
|
|
438
|
+
}));
|
|
439
|
+
steps.push(buildReviewPacketWizardStep({
|
|
440
|
+
id: 'reviewer-handoff',
|
|
441
|
+
label: 'Reviewer handoff',
|
|
442
|
+
status: packetStepStatus(handoffReady, judgmentReady),
|
|
443
|
+
detail: handoffReady
|
|
444
|
+
? `Reviewer handoff ${defaults.handoffArtifactId} includes ${defaults.relatedArtifactIds.length} related evidence artifact(s).`
|
|
445
|
+
: judgmentReady
|
|
446
|
+
? 'Create a reviewer handoff from the revealed judgment and related document/export evidence.'
|
|
447
|
+
: 'Save a revealed comparison judgment before creating reviewer handoff evidence.',
|
|
448
|
+
userRoute: 'Documents & Compare -> Export compare report',
|
|
449
|
+
modelRoute: defaults.revealedJudgmentArtifactId
|
|
450
|
+
? `agent_model_compare handoff artifactId:"${defaults.revealedJudgmentArtifactId}" relatedArtifactIds:${JSON.stringify(defaults.relatedArtifactIds)} confirm:true explicitUserRequest:"..."`
|
|
451
|
+
: 'agent_harness mode:"workspace_action" actionId:"document-export-compare"',
|
|
452
|
+
actionId: 'document-export-compare',
|
|
453
|
+
backtrackRoute: defaults.handoffArtifactId
|
|
454
|
+
? `agent_artifacts show artifactId:"${defaults.handoffArtifactId}"`
|
|
455
|
+
: null,
|
|
456
|
+
}));
|
|
457
|
+
steps.push(buildReviewPacketWizardStep({
|
|
458
|
+
id: 'route-decision',
|
|
459
|
+
label: 'Route decision',
|
|
460
|
+
status: routeDecisionDone ? 'done' : handoffReady ? 'current' : judgmentReady ? 'pending' : 'blocked',
|
|
461
|
+
detail: routeDecisionDone
|
|
462
|
+
? defaults.routeDecisionArtifactId
|
|
463
|
+
? `Route decision ${defaults.routeDecisionArtifactId} records ${defaults.routeDecision ?? 'a saved decision'}.`
|
|
464
|
+
: 'Final packet evidence exists; route-decision review has been carried to archive/final review.'
|
|
465
|
+
: handoffReady
|
|
466
|
+
? 'Apply the revealed winner or explicitly leave the current model unchanged before final archive review.'
|
|
467
|
+
: judgmentReady
|
|
468
|
+
? 'Create reviewer handoff evidence before applying or leaving the revealed winning route.'
|
|
469
|
+
: 'A revealed judgment is required before deciding whether to update the selected model route.',
|
|
470
|
+
userRoute: 'Documents & Compare -> Apply compare winner or Record route decision',
|
|
471
|
+
modelRoute: defaults.revealedJudgmentArtifactId
|
|
472
|
+
? `agent_model_compare apply artifactId:"${defaults.revealedJudgmentArtifactId}" confirm:true explicitUserRequest:"..." or agent_model_compare routeDecision artifactId:"${defaults.revealedJudgmentArtifactId}" decision:"left-unchanged" confirm:true explicitUserRequest:"..."`
|
|
473
|
+
: 'agent_harness mode:"workspace_action" actionId:"document-apply-compare"',
|
|
474
|
+
actionId: 'document-apply-compare',
|
|
475
|
+
backtrackRoute: defaults.routeDecisionArtifactId
|
|
476
|
+
? `agent_artifacts show artifactId:"${defaults.routeDecisionArtifactId}"`
|
|
477
|
+
: null,
|
|
478
|
+
}));
|
|
479
|
+
steps.push(buildReviewPacketWizardStep({
|
|
480
|
+
id: 'final-archive-review',
|
|
481
|
+
label: 'Final archive review',
|
|
482
|
+
status: archiveReady ? 'done' : routeDecisionDone && handoffReady ? 'current' : handoffReady ? 'pending' : 'blocked',
|
|
483
|
+
detail: archiveReady
|
|
484
|
+
? `Reviewer packet archive ${defaults.handoffArchiveArtifactId} is ready for final evidence review.`
|
|
485
|
+
: handoffReady
|
|
486
|
+
? 'Archive the reviewer handoff as one ZIP artifact after route-decision review.'
|
|
487
|
+
: 'Create a reviewer handoff with related evidence before archiving the packet.',
|
|
488
|
+
userRoute: 'Documents & Compare -> Export compare report',
|
|
489
|
+
modelRoute: defaults.handoffArtifactId
|
|
490
|
+
? `agent_model_compare handoffArchive artifactId:"${defaults.handoffArtifactId}" confirm:true explicitUserRequest:"..."`
|
|
491
|
+
: 'agent_harness mode:"workspace_action" actionId:"document-export-compare"',
|
|
492
|
+
actionId: 'document-export-compare',
|
|
493
|
+
backtrackRoute: defaults.handoffArchiveArtifactId
|
|
494
|
+
? `agent_artifacts show artifactId:"${defaults.handoffArchiveArtifactId}"`
|
|
495
|
+
: null,
|
|
496
|
+
}));
|
|
497
|
+
const completedSteps = steps.filter((step) => step.status === 'done').length;
|
|
498
|
+
const current = steps.find((step) => step.status === 'current') ?? steps.find((step) => step.status === 'pending') ?? null;
|
|
499
|
+
const status = !artifactListAvailable && steps.length > 0
|
|
500
|
+
? 'blocked'
|
|
501
|
+
: completedSteps === steps.length
|
|
502
|
+
? 'complete'
|
|
503
|
+
: latestDocument
|
|
504
|
+
? 'active'
|
|
505
|
+
: 'empty';
|
|
506
|
+
return {
|
|
507
|
+
available: artifactListAvailable,
|
|
508
|
+
status,
|
|
509
|
+
completedSteps,
|
|
510
|
+
totalSteps: steps.length,
|
|
511
|
+
currentStepId: current?.id ?? null,
|
|
512
|
+
currentStepLabel: current?.label ?? null,
|
|
513
|
+
next: current
|
|
514
|
+
? `${current.label}: ${current.detail}`
|
|
515
|
+
: 'Review packet wizard is complete; inspect the final archive and saved packet evidence.',
|
|
516
|
+
finalReview: finalArchiveReview,
|
|
517
|
+
presetLineage,
|
|
518
|
+
steps,
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
export function reviewerReadinessBadge(
|
|
523
|
+
documents: readonly AgentDocumentRecord[],
|
|
524
|
+
artifacts: readonly ArtifactDescriptor[],
|
|
525
|
+
artifactListAvailable: boolean,
|
|
526
|
+
): AgentWorkspaceReviewerReadinessBadge {
|
|
527
|
+
const reviewDocuments = documents.filter((document) => document.status !== 'archived');
|
|
528
|
+
const openComments = reviewDocuments.reduce((total, document) => total + document.comments.filter((comment) => comment.status === 'open').length, 0);
|
|
529
|
+
const proposedSuggestions = reviewDocuments.reduce((total, document) => total + document.suggestions.filter((suggestion) => suggestion.status === 'proposed').length, 0);
|
|
530
|
+
const documentsMissingSourceArtifacts = reviewDocuments.filter((document) => document.attachments.length === 0 && !document.lastArtifactId).length;
|
|
531
|
+
const comparisons = artifacts.filter(isModelCompareArtifact);
|
|
532
|
+
const judgments = artifacts.filter(isModelCompareJudgmentArtifact);
|
|
533
|
+
const routeDecisions = artifacts.filter(isModelCompareRouteDecisionArtifact);
|
|
534
|
+
const handoffs = artifacts.filter(isReviewerHandoffArtifact);
|
|
535
|
+
const revealedJudgments = judgments.filter((artifact) => (
|
|
536
|
+
artifact.metadata.revealIncludedInJudgment === true
|
|
537
|
+
&& readArtifactMetadataString(artifact.metadata, 'winnerModel').length > 0
|
|
538
|
+
));
|
|
539
|
+
const hiddenJudgments = judgments.filter((artifact) => (
|
|
540
|
+
artifact.metadata.revealIncludedInJudgment !== true
|
|
541
|
+
|| readArtifactMetadataString(artifact.metadata, 'winnerModel').length === 0
|
|
542
|
+
));
|
|
543
|
+
const routeDecisionComparisonIds = new Set(routeDecisions.map((artifact) => readArtifactMetadataString(artifact.metadata, 'comparisonId')).filter(Boolean));
|
|
544
|
+
const routeDecisionJudgmentArtifactIds = new Set(routeDecisions.map((artifact) => readArtifactMetadataString(artifact.metadata, 'judgmentArtifactId')).filter(Boolean));
|
|
545
|
+
const revealedJudgmentsWaitingOnRouteDecision = revealedJudgments.filter((artifact) => {
|
|
546
|
+
const comparisonId = readArtifactMetadataString(artifact.metadata, 'comparisonId');
|
|
547
|
+
return !routeDecisionJudgmentArtifactIds.has(artifact.id) && (!comparisonId || !routeDecisionComparisonIds.has(comparisonId));
|
|
548
|
+
});
|
|
549
|
+
const revealedComparisonIds = new Set(revealedJudgments.map((artifact) => readArtifactMetadataString(artifact.metadata, 'comparisonId')).filter(Boolean));
|
|
550
|
+
const unrevealedComparisons = comparisons.filter((artifact) => {
|
|
551
|
+
const comparisonId = readArtifactMetadataString(artifact.metadata, 'comparisonId');
|
|
552
|
+
return artifact.metadata.revealIncludedInTranscript !== true && (!comparisonId || !revealedComparisonIds.has(comparisonId));
|
|
553
|
+
});
|
|
554
|
+
const comparisonSourceMissing = comparisons.filter((artifact) => (
|
|
555
|
+
!readArtifactMetadataString(artifact.metadata, 'sourceArtifactId')
|
|
556
|
+
&& !readArtifactMetadataString(artifact.metadata, 'documentId')
|
|
557
|
+
)).length;
|
|
558
|
+
const missingSourceArtifacts = documentsMissingSourceArtifacts + comparisonSourceMissing;
|
|
559
|
+
const handoffsMissingRelatedArtifacts = handoffs.filter((artifact) => readArtifactMetadataStringList(artifact.metadata, 'relatedArtifactIds').length === 0).length;
|
|
560
|
+
const issueCount = openComments
|
|
561
|
+
+ proposedSuggestions
|
|
562
|
+
+ missingSourceArtifacts
|
|
563
|
+
+ unrevealedComparisons.length
|
|
564
|
+
+ hiddenJudgments.length
|
|
565
|
+
+ revealedJudgmentsWaitingOnRouteDecision.length
|
|
566
|
+
+ handoffsMissingRelatedArtifacts;
|
|
567
|
+
const next = !artifactListAvailable
|
|
568
|
+
? 'Artifact listing is unavailable; run Review readiness preflight before export, archive, or route update.'
|
|
569
|
+
: openComments + proposedSuggestions > 0
|
|
570
|
+
? 'Resolve open comments or accept/reject proposed suggestions before exporting reviewer packets.'
|
|
571
|
+
: missingSourceArtifacts > 0
|
|
572
|
+
? 'Attach source artifacts or related evidence before export, handoff, or archive.'
|
|
573
|
+
: unrevealedComparisons.length + hiddenJudgments.length > 0
|
|
574
|
+
? 'Reveal comparison/judgment identity before applying a model route or final reviewer handoff.'
|
|
575
|
+
: revealedJudgmentsWaitingOnRouteDecision.length > 0
|
|
576
|
+
? 'Apply the revealed winner or explicitly leave routing unchanged before archiving.'
|
|
577
|
+
: handoffsMissingRelatedArtifacts > 0
|
|
578
|
+
? 'Recreate reviewer handoffs with related evidence before ZIP archive.'
|
|
579
|
+
: 'Reviewer readiness preflight is clear for export, handoff archive, or route update.';
|
|
580
|
+
return {
|
|
581
|
+
status: !artifactListAvailable ? 'needs-setup' : issueCount > 0 ? 'attention' : 'ready',
|
|
582
|
+
summary: `${issueCount} issue(s): ${openComments} comment(s), ${proposedSuggestions} suggestion(s), ${missingSourceArtifacts} source/evidence gap(s), ${unrevealedComparisons.length + hiddenJudgments.length} hidden comparison item(s), ${revealedJudgmentsWaitingOnRouteDecision.length} route decision(s), ${handoffsMissingRelatedArtifacts} handoff evidence gap(s).`,
|
|
583
|
+
next,
|
|
584
|
+
issueCount,
|
|
585
|
+
openComments,
|
|
586
|
+
proposedSuggestions,
|
|
587
|
+
missingSourceArtifacts,
|
|
588
|
+
unrevealedComparisons: unrevealedComparisons.length,
|
|
589
|
+
hiddenJudgments: hiddenJudgments.length,
|
|
590
|
+
revealedJudgments: revealedJudgmentsWaitingOnRouteDecision.length,
|
|
591
|
+
handoffsMissingRelatedArtifacts,
|
|
592
|
+
};
|
|
593
|
+
}
|