@agentskit/doc-bridge 1.7.44 → 1.9.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 +471 -0
- package/CONTRIBUTING.md +29 -4
- package/README.md +87 -40
- package/SECURITY.md +7 -0
- package/action.yml +1 -1
- package/bin/ak-docs.js +2 -2
- package/bin/ak-verify.js +13 -7
- package/dist/cli/program.d.ts +3 -1
- package/dist/cli/program.js +15888 -6061
- package/dist/cli/program.js.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.js +91 -9
- package/dist/config/index.js.map +1 -1
- package/dist/index-Beor6Yhi.d.ts +792 -0
- package/dist/index.d.ts +9979 -3257
- package/dist/index.js +15954 -5774
- package/dist/index.js.map +1 -1
- package/docs/MARKETPLACE.md +1 -1
- package/docs/PRD-documentation-efficiency-study.md +406 -0
- package/docs/PRD-knowledge-retrieval-and-enrichment.md +466 -0
- package/docs/RELEASE.md +22 -8
- package/docs/adr/0002-documentation-audit-boundary.md +22 -0
- package/docs/adr/0003-study-protocol-and-historical-evidence.md +40 -0
- package/docs/adr/0004-controlled-study-runner.md +25 -0
- package/docs/adr/0005-documentation-quality-and-criticality.md +20 -0
- package/docs/adr/0006-registry-semantic-grounding.md +20 -0
- package/docs/adr/0007-longitudinal-study-metrics.md +21 -0
- package/docs/adr/0008-study-verification-boundary.md +21 -0
- package/docs/adr/0009-study-provider-cli-adapter.md +25 -0
- package/docs/agent-corpus/INDEX.md +14 -3
- package/docs/agent-corpus/OVERVIEW.md +25 -0
- package/docs/agent-corpus/chat.md +7 -3
- package/docs/agent-corpus/cli.md +18 -2
- package/docs/agent-corpus/conformance.md +14 -2
- package/docs/agent-corpus/doc-bridge.md +48 -1
- package/docs/agent-corpus/doctor.md +10 -2
- package/docs/agent-corpus/gates.md +6 -2
- package/docs/agent-corpus/mcp.md +15 -2
- package/docs/agent-corpus/memory.md +6 -2
- package/docs/agent-corpus/query.md +35 -2
- package/docs/bench/README.md +122 -0
- package/docs/bench/retrieval-baseline-v1.json +28 -0
- package/docs/bench/retrieval-suite-v1.json +1033 -0
- package/docs/chat-and-rag.md +3 -2
- package/docs/for-agents.md +9 -1
- package/docs/getting-started.md +4 -11
- package/docs/guides/gate-ci.md +11 -1
- package/docs/guides/install-and-run.md +9 -65
- package/docs/index.md +22 -1
- package/docs/knowledge-engine-runbook.md +51 -4
- package/docs/landing/assets/context-payload-reduction.svg +21 -0
- package/docs/landing/assets/controlled-ab-comparison.svg +30 -0
- package/docs/landing/index.html +119 -5
- package/docs/loop-workflow.md +117 -0
- package/docs/mcp.md +6 -1
- package/docs/parity/public-claims-v1.json +145 -0
- package/docs/playbook/doc-bridge-pattern.md +1 -1
- package/docs/query.md +90 -2
- package/docs/recipes/index-pipeline.md +1 -1
- package/docs/schemas/agent-handoff-v1.md +15 -0
- package/docs/schemas/doc-bridge-index-v1.md +65 -0
- package/docs/spec/benchmark-v1.md +39 -1
- package/docs/spec/cli.md +30 -10
- package/docs/spec/config-v1.md +192 -8
- package/docs/spec/documentation-audit-v1.md +61 -0
- package/docs/spec/enrichment-overlay-v1.md +241 -0
- package/docs/spec/graph-signals-v1.md +92 -0
- package/docs/spec/incremental-scan-v1.md +102 -0
- package/docs/spec/markdown-analyzer-v1.md +73 -0
- package/docs/spec/mcp-knowledge-tools-v1.md +147 -0
- package/docs/spec/measured-enrichment-v1.md +229 -0
- package/docs/spec/public-parity-v1.md +119 -0
- package/docs/spec/registry-agents.md +6 -0
- package/docs/spec/render-v1.md +122 -0
- package/docs/spec/retrieval-index-v1.md +164 -0
- package/docs/spec/study-metrics-v1.md +58 -0
- package/docs/spec/study-protocol-v1.md +46 -0
- package/docs/spec/study-provider-cli-v1.md +116 -0
- package/docs/spec/study-runner-v1.md +35 -0
- package/docs/spec/study-task-suite-v1.md +41 -0
- package/docs/spec/study-verification-v1.md +40 -0
- package/docs/study/README.md +84 -0
- package/docs/study/ab-adjudicated-cost-analysis-v1.md +29 -0
- package/docs/study/ab-adjudicated-cost-plan-v1.json +33 -0
- package/docs/study/ab-adjudicated-cost-plan-v2-v1.json +33 -0
- package/docs/study/ab-adjudicated-cost-result-v1.json +80 -0
- package/docs/study/ab-baseline-analysis-v1.md +21 -0
- package/docs/study/ab-baseline-plan-v1.json +33 -0
- package/docs/study/ab-baseline-recovery-plan-v1.json +33 -0
- package/docs/study/ab-baseline-result-v1.json +79 -0
- package/docs/study/documentation-audit-round-2026-08-31.json +183 -0
- package/docs/study/historical-evidence-v1.json +252 -0
- package/docs/study/observation-ledger-v1.json +30632 -0
- package/docs/study/phase3-task-coverage-v1.json +34 -0
- package/docs/study/phase4-public-pilot-ledger-v1.json +1344 -0
- package/docs/study/phase4-public-pilot-result-v1.json +52 -0
- package/docs/study/phase4-public-pilot-run-plan-v1.json +26 -0
- package/docs/study/phase4-public-pilot-task-suite-v1.json +71 -0
- package/docs/study/pilot-round-2026-08-31.json +46 -0
- package/docs/study/protocol-v1.json +90 -0
- package/docs/study/publication-gate-v1.md +45 -0
- package/docs/study/quality-scorecard-cycle-plan.md +545 -0
- package/docs/study/quality-scorecard-v1.json +38 -0
- package/docs/study/round-1-adjudicated-smoke-v1.json +30642 -0
- package/docs/study/round-1-instrumentation-plan-v1.md +39 -0
- package/docs/study/round-2-expanded-adjudication-v1.json +91 -0
- package/docs/study/round-2-expanded-validation-v1.md +58 -0
- package/docs/study/round-3-evidence-contract-v1.json +75 -0
- package/docs/study/round-3-evidence-contract-v1.md +57 -0
- package/docs/study/round-4-confirmation-v1.json +75 -0
- package/docs/study/round-4-confirmation-v1.md +55 -0
- package/docs/study/run-plan-v1.json +33 -0
- package/docs/study/semantic-adjudication-cycle-8.md +20 -0
- package/docs/study/task-suite-v1.json +96 -0
- package/docs/study/token-efficiency-plan-v1.md +337 -0
- package/docs/study/token-efficiency-protocol-v2.json +62 -0
- package/docs/study/verification-binding-v1.json +27 -0
- package/docs/validation-cycle-plan.md +33 -0
- package/docs/verification-harness.md +15 -6
- package/ecosystem-claims.json +2 -2
- package/ecosystem-upstream.json +2 -2
- package/ecosystem.json +4 -4
- package/mcpb/manifest.json +9 -1
- package/package.json +89 -72
- package/scripts/check-ecosystem-upstream.mjs +36 -7
- package/scripts/report-visual-check.mjs +20 -3
- package/skills/doc-bridge-handoff/fixtures/synthetic-repo/docs/for-agents/packages/payments.md +7 -0
- package/skills/doc-bridge-handoff/scripts/resolve-handoff.mjs +1 -1
- package/src/agents/registry-adapter.ts +192 -24
- package/src/audit/documentation.ts +513 -0
- package/src/bench/baseline.ts +198 -0
- package/src/bench/overlay-delta.ts +139 -0
- package/src/bench/retrieval.ts +319 -0
- package/src/budget/compile.ts +91 -0
- package/src/budget/sections.ts +70 -0
- package/src/cli/demo.ts +2 -2
- package/src/cli/program.ts +699 -79
- package/src/cli/usage.ts +71 -0
- package/src/config/defaults.ts +1 -0
- package/src/config/index.ts +4 -0
- package/src/config/load-config.ts +7 -1
- package/src/config/schema.ts +121 -4
- package/src/conformance/documentation-standard-v1.ts +22 -14
- package/src/discovery/areas.ts +182 -0
- package/src/discovery/documentation.ts +255 -23
- package/src/discovery/identity.ts +24 -0
- package/src/discovery/incremental.ts +314 -0
- package/src/discovery/inputs.ts +110 -0
- package/src/discovery/markdown.ts +481 -0
- package/src/discovery/repository.ts +557 -125
- package/src/doctor/run-doctor.ts +246 -27
- package/src/enrich/approvals.ts +190 -0
- package/src/enrich/cache.ts +93 -0
- package/src/enrich/context-pack.ts +272 -0
- package/src/enrich/overlay.ts +255 -0
- package/src/enrich/review.ts +106 -0
- package/src/enrich/stage.ts +374 -0
- package/src/enrich/stats.ts +100 -0
- package/src/enrich/validate.ts +410 -0
- package/src/federation/llms.ts +74 -24
- package/src/findings/report.ts +103 -0
- package/src/fixes/proposals.ts +4 -3
- package/src/graph/build.ts +356 -0
- package/src/graph/memory.ts +208 -0
- package/src/index-builder/build-handoffs.ts +22 -11
- package/src/index-builder/build-index.ts +132 -3
- package/src/index-builder/human-adapters/fumadocs.ts +1 -1
- package/src/index-builder/llms-txt.ts +48 -8
- package/src/index-builder/project-corpus.ts +111 -0
- package/src/index-builder/watch-index.ts +1 -1
- package/src/index.ts +630 -2
- package/src/lib/bounded-text.ts +15 -10
- package/src/lib/fuzzy-match.ts +235 -0
- package/src/mcp/knowledge.ts +554 -0
- package/src/mcp/server.ts +113 -18
- package/src/metrics/benchmark.ts +21 -0
- package/src/parity/check.ts +309 -0
- package/src/parity/claims.ts +259 -0
- package/src/parity/resolve.ts +160 -0
- package/src/query/handoff.ts +326 -0
- package/src/query/load-index.ts +53 -1
- package/src/query/query.ts +92 -59
- package/src/query/search.ts +289 -92
- package/src/query/text.ts +155 -0
- package/src/reconciliation/reconcile.ts +148 -15
- package/src/render/data.ts +356 -0
- package/src/render/engine.ts +398 -0
- package/src/render/generated.ts +77 -0
- package/src/render/render.ts +209 -0
- package/src/render/template-source.ts +52 -0
- package/src/render/templates.ts +289 -0
- package/src/report/html.ts +23 -17
- package/src/retrieval/bm25.ts +161 -0
- package/src/retrieval/project.ts +495 -0
- package/src/retrieval/rank.ts +383 -0
- package/src/retrieval/weights.ts +39 -0
- package/src/retriever/doc-bridge-retriever.ts +100 -15
- package/src/rules/engine.ts +45 -12
- package/src/safety/repository.ts +1 -1
- package/src/schemas/agent-handoff.ts +56 -0
- package/src/schemas/budget.ts +37 -0
- package/src/schemas/doc-bridge-index.ts +53 -2
- package/src/schemas/enrichment.ts +369 -0
- package/src/schemas/json-schemas.ts +39 -2
- package/src/schemas/knowledge.ts +19 -3
- package/src/schemas/retrieval-index.ts +152 -0
- package/src/shims/graphology.d.ts +91 -0
- package/src/study/adjudication.ts +196 -0
- package/src/study/execution.ts +350 -0
- package/src/study/expectations.ts +219 -0
- package/src/study/metrics.ts +467 -0
- package/src/study/protocol.ts +271 -0
- package/src/study/provider-cli.ts +115 -0
- package/src/study/provider-telemetry.ts +47 -0
- package/src/study/quality-scorecard.ts +164 -0
- package/src/study/runner.ts +461 -0
- package/src/study/task-suite.ts +321 -0
- package/src/study/verification.ts +134 -0
- package/src/validate.ts +8 -5
- package/src/version.ts +1 -1
- package/src/workflow/engine.ts +36 -11
- package/dist/index-C2PCQSrB.d.ts +0 -2251
- package/scripts/verification-harness.mjs +0 -483
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs'
|
|
2
|
+
import { spawn } from 'node:child_process'
|
|
2
3
|
import { join, resolve } from 'node:path'
|
|
3
4
|
import { pathToFileURL } from 'node:url'
|
|
4
5
|
import { z } from 'zod'
|
|
5
6
|
|
|
6
7
|
import type { DocBridgeConfigV1 } from '../config/schema.js'
|
|
8
|
+
import type { DocumentationAuditReportV1 } from '../audit/documentation.js'
|
|
7
9
|
import { AgentProposalV1Schema, type AgentProposalV1, type DiscoverySnapshotV1, type ReconciliationReportV1 } from '../schemas/knowledge.js'
|
|
8
10
|
import { contentHashForArtifactV1, sha256NormalizedV1 } from '../index-builder/content-hash.js'
|
|
9
11
|
import { containedPath, redactValue } from '../safety/repository.js'
|
|
@@ -24,6 +26,7 @@ export type RegistryAgentContext = {
|
|
|
24
26
|
readonly snapshot: DiscoverySnapshotV1
|
|
25
27
|
readonly report: ReconciliationReportV1
|
|
26
28
|
readonly evidence: readonly ReconciliationReportV1['diagnostics'][number]['evidence'][number][]
|
|
29
|
+
readonly documentation?: Pick<DocumentationAuditReportV1, 'contentHash' | 'sourceRevision' | 'status' | 'findings' | 'documentAssessments' | 'metrics' | 'limitations'>
|
|
27
30
|
readonly capabilities: readonly ['snapshot.read', 'evidence.read', 'proposal.write']
|
|
28
31
|
readonly network: false
|
|
29
32
|
readonly shell: false
|
|
@@ -32,9 +35,35 @@ export type RegistryAgentContext = {
|
|
|
32
35
|
|
|
33
36
|
export type RegistryAgentRunner = (context: RegistryAgentContext) => Promise<unknown> | unknown
|
|
34
37
|
|
|
38
|
+
type RegistryCliConfig = NonNullable<NonNullable<NonNullable<DocBridgeConfigV1['intelligence']>['registry']>['cli']>
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The v2 protocol: a task and a bounded set of context packs, never the snapshot.
|
|
42
|
+
*
|
|
43
|
+
* `curate` and `review` return `proposals` — `EnrichmentProposalV1` values, validated by the
|
|
44
|
+
* enrich stage, never here; `adjudicate` returns adjudications under the same key. The adapter
|
|
45
|
+
* checks transport and budget and returns the raw array: grounding is the validators' job, and
|
|
46
|
+
* keeping it there is what makes a stored overlay reproducible from its proposals.
|
|
47
|
+
*/
|
|
48
|
+
export const REGISTRY_AGENT_PROTOCOL_V2 = 'doc-bridge.registry-agent.v2'
|
|
49
|
+
|
|
50
|
+
export type RegistryEnrichmentContext = {
|
|
51
|
+
readonly protocol: typeof REGISTRY_AGENT_PROTOCOL_V2
|
|
52
|
+
readonly task: 'curate' | 'review' | 'adjudicate'
|
|
53
|
+
readonly role: string
|
|
54
|
+
readonly promptVersion: string
|
|
55
|
+
readonly packs: readonly unknown[]
|
|
56
|
+
readonly capabilities: readonly ['pack.read', 'proposal.write']
|
|
57
|
+
readonly network: false
|
|
58
|
+
readonly shell: false
|
|
59
|
+
readonly deterministic: boolean
|
|
60
|
+
}
|
|
61
|
+
|
|
35
62
|
export type RegistryAgentAdapter = {
|
|
36
63
|
readonly metadata: RegistryAgentMetadata
|
|
37
|
-
readonly run: (snapshot: DiscoverySnapshotV1, report: ReconciliationReportV1, evidence?: readonly RegistryAgentContext['evidence'][number][]) => Promise<AgentProposalV1>
|
|
64
|
+
readonly run: (snapshot: DiscoverySnapshotV1, report: ReconciliationReportV1, evidence?: readonly RegistryAgentContext['evidence'][number][], documentation?: DocumentationAuditReportV1) => Promise<AgentProposalV1>
|
|
65
|
+
/** Send packs for a task and return the raw `proposals` array. Throws on transport, budget or shape failure. */
|
|
66
|
+
readonly enrich: (task: RegistryEnrichmentContext['task'], packs: readonly unknown[], options?: { readonly role?: string; readonly promptVersion?: string }) => Promise<readonly unknown[]>
|
|
38
67
|
}
|
|
39
68
|
|
|
40
69
|
const deepFreeze = <T>(value: T): T => {
|
|
@@ -47,6 +76,91 @@ const deepFreeze = <T>(value: T): T => {
|
|
|
47
76
|
|
|
48
77
|
const registryConfig = (config: DocBridgeConfigV1) => config.intelligence?.registry
|
|
49
78
|
|
|
79
|
+
const evidenceKey = (item: RegistryAgentContext['evidence'][number]): string => `${item.source}:${item.path}:${item.lineStart ?? ''}:${item.lineEnd ?? ''}`
|
|
80
|
+
|
|
81
|
+
const validateGrounding = (proposal: AgentProposalV1, snapshot: DiscoverySnapshotV1, report: ReconciliationReportV1, documentation?: DocumentationAuditReportV1): void => {
|
|
82
|
+
const diagnosticIds = new Set(report.diagnostics.map((diagnostic) => diagnostic.id))
|
|
83
|
+
for (const finding of documentation?.findings ?? []) diagnosticIds.add(finding.id)
|
|
84
|
+
const evidence = [
|
|
85
|
+
...report.diagnostics.flatMap((diagnostic) => diagnostic.evidence),
|
|
86
|
+
...snapshot.entities.flatMap((entity) => entity.evidence),
|
|
87
|
+
...snapshot.relations.flatMap((relation) => relation.evidence),
|
|
88
|
+
...(documentation?.findings.flatMap((finding) => finding.evidence) ?? []),
|
|
89
|
+
]
|
|
90
|
+
const evidenceKeys = new Set(evidence.map(evidenceKey))
|
|
91
|
+
if (!proposal.evidence.length) throw new Error('Registry agent proposal must contain at least one evidence reference.')
|
|
92
|
+
if (proposal.relatedDiagnosticIds.some((id) => !diagnosticIds.has(id))) throw new Error('Registry agent proposal references an unknown diagnostic.')
|
|
93
|
+
if (proposal.evidence.some((item) => !evidenceKeys.has(evidenceKey(item)))) throw new Error('Registry agent proposal contains evidence outside the supplied snapshot/report.')
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const runCli = (root: string, cli: RegistryCliConfig, context: RegistryAgentContext | RegistryEnrichmentContext, timeoutMs: number, maxInputBytes: number, maxResponseBytes: number): Promise<unknown> => new Promise((resolve, reject) => {
|
|
97
|
+
const v2 = 'protocol' in context
|
|
98
|
+
const input = JSON.stringify(
|
|
99
|
+
v2
|
|
100
|
+
? { protocol: REGISTRY_AGENT_PROTOCOL_V2, response: 'Return exactly one JSON object { "proposals": [...] } on stdout. Do not emit markdown or logs on stdout.', context }
|
|
101
|
+
: { protocol: 'doc-bridge.registry-agent.v1', response: 'Return exactly one AgentProposalV1 JSON object on stdout. Do not emit markdown or logs on stdout.', context },
|
|
102
|
+
)
|
|
103
|
+
if (Buffer.byteLength(input, 'utf8') > maxInputBytes) {
|
|
104
|
+
reject(new Error(`Registry agent CLI input limit ${maxInputBytes} bytes exceeded.`))
|
|
105
|
+
return
|
|
106
|
+
}
|
|
107
|
+
const child = spawn(cli.command, cli.args ?? [], {
|
|
108
|
+
cwd: root,
|
|
109
|
+
shell: false,
|
|
110
|
+
env: process.env,
|
|
111
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
112
|
+
})
|
|
113
|
+
let stdout = ''
|
|
114
|
+
let stderr = ''
|
|
115
|
+
let settled = false
|
|
116
|
+
const finish = (callback: () => void): void => {
|
|
117
|
+
if (settled) return
|
|
118
|
+
settled = true
|
|
119
|
+
callback()
|
|
120
|
+
}
|
|
121
|
+
const timer = setTimeout(() => {
|
|
122
|
+
child.kill('SIGTERM')
|
|
123
|
+
finish(() => reject(new Error(`Registry agent CLI timed out after ${timeoutMs}ms.`)))
|
|
124
|
+
}, timeoutMs)
|
|
125
|
+
child.stdout.on('data', (chunk: Buffer) => {
|
|
126
|
+
stdout += chunk.toString('utf8')
|
|
127
|
+
if (Buffer.byteLength(stdout, 'utf8') > maxResponseBytes) {
|
|
128
|
+
clearTimeout(timer)
|
|
129
|
+
child.kill('SIGTERM')
|
|
130
|
+
finish(() => reject(new Error(`Registry agent CLI response limit ${maxResponseBytes} bytes exceeded.`)))
|
|
131
|
+
}
|
|
132
|
+
})
|
|
133
|
+
child.stderr.on('data', (chunk: Buffer) => {
|
|
134
|
+
stderr += chunk.toString('utf8')
|
|
135
|
+
if (Buffer.byteLength(stderr, 'utf8') > maxResponseBytes) stderr = stderr.slice(-maxResponseBytes)
|
|
136
|
+
})
|
|
137
|
+
child.once('error', (error) => {
|
|
138
|
+
clearTimeout(timer)
|
|
139
|
+
finish(() => reject(new Error(`Registry agent CLI failed to start: ${error.message}`)))
|
|
140
|
+
})
|
|
141
|
+
child.once('close', (code, signal) => {
|
|
142
|
+
clearTimeout(timer)
|
|
143
|
+
finish(() => {
|
|
144
|
+
if (code !== 0) {
|
|
145
|
+
const detail = stderr.trim() ? `: ${stderr.trim()}` : signal ? ` (${signal})` : ''
|
|
146
|
+
reject(new Error(`Registry agent CLI exited with code ${code ?? 'unknown'}${detail}`))
|
|
147
|
+
return
|
|
148
|
+
}
|
|
149
|
+
try {
|
|
150
|
+
resolve(JSON.parse(stdout) as unknown)
|
|
151
|
+
} catch (error) {
|
|
152
|
+
reject(new Error(`Registry agent CLI must return one JSON object on stdout: ${error instanceof Error ? error.message : String(error)}`))
|
|
153
|
+
}
|
|
154
|
+
})
|
|
155
|
+
})
|
|
156
|
+
child.stdin.once('error', (error) => {
|
|
157
|
+
clearTimeout(timer)
|
|
158
|
+
child.kill('SIGTERM')
|
|
159
|
+
finish(() => reject(new Error(`Registry agent CLI stdin failed: ${error.message}`)))
|
|
160
|
+
})
|
|
161
|
+
child.stdin.end(input)
|
|
162
|
+
})
|
|
163
|
+
|
|
50
164
|
export const loadRegistryAgentRunner = async (root: string, config: DocBridgeConfigV1): Promise<RegistryAgentRunner> => {
|
|
51
165
|
const metadata = loadRegistryAgentMetadata(root, config)
|
|
52
166
|
const configured = registryConfig(config)?.runnerModule
|
|
@@ -71,41 +185,95 @@ export const loadRegistryAgentMetadata = (root: string, config: DocBridgeConfigV
|
|
|
71
185
|
return { ...metadata, root: agentPath }
|
|
72
186
|
}
|
|
73
187
|
|
|
74
|
-
export const createRegistryAgentAdapter = (root: string, config: DocBridgeConfigV1, runner
|
|
188
|
+
export const createRegistryAgentAdapter = (root: string, config: DocBridgeConfigV1, runner?: RegistryAgentRunner): RegistryAgentAdapter => {
|
|
75
189
|
if (!registryConfig(config)?.enabled) throw new Error('Registry agents are disabled. Set intelligence.registry.enabled: true to run an assisted workflow.')
|
|
76
190
|
const metadata = loadRegistryAgentMetadata(resolve(root), config)
|
|
77
191
|
const settings = registryConfig(config) ?? {}
|
|
78
192
|
const timeoutMs = settings.timeoutMs ?? 120_000
|
|
193
|
+
const maxInputBytes = settings.maxInputBytes ?? 8_000_000
|
|
79
194
|
const maxResponseBytes = settings.maxResponseBytes ?? 256_000
|
|
80
195
|
const maxTokens = settings.maxTokens ?? Math.ceil(maxResponseBytes / 4)
|
|
81
196
|
const maxConcurrency = settings.maxConcurrency ?? 1
|
|
82
197
|
let active = 0
|
|
83
198
|
const deterministicCache = new Map<string, AgentProposalV1>()
|
|
199
|
+
/** One transport for both protocols: the configured CLI, or the local runner, under the same limits. */
|
|
200
|
+
const transport = async (context: RegistryAgentContext | RegistryEnrichmentContext): Promise<unknown> => {
|
|
201
|
+
if (active >= maxConcurrency) throw new Error(`Registry agent concurrency limit ${maxConcurrency} exceeded.`)
|
|
202
|
+
if (!settings.cli && !runner) throw new Error('Registry agent requires either intelligence.registry.cli or a local runner module.')
|
|
203
|
+
active += 1
|
|
204
|
+
let timer: ReturnType<typeof setTimeout> | undefined
|
|
205
|
+
try {
|
|
206
|
+
let raw: unknown
|
|
207
|
+
if (settings.cli) {
|
|
208
|
+
raw = await runCli(resolve(root), settings.cli, context, timeoutMs, maxInputBytes, maxResponseBytes)
|
|
209
|
+
} else {
|
|
210
|
+
const localRunner = runner as RegistryAgentRunner
|
|
211
|
+
const timeout = new Promise<never>((_, reject) => { timer = setTimeout(() => reject(new Error(`Registry agent timed out after ${timeoutMs}ms.`)), timeoutMs) })
|
|
212
|
+
raw = await Promise.race([Promise.resolve(localRunner(context as RegistryAgentContext)), timeout])
|
|
213
|
+
}
|
|
214
|
+
const responseBytes = Buffer.byteLength(JSON.stringify(raw) ?? '')
|
|
215
|
+
if (responseBytes > maxResponseBytes) throw new Error(`Registry agent response limit ${maxResponseBytes} bytes exceeded.`)
|
|
216
|
+
if (Math.ceil(responseBytes / 4) > maxTokens) throw new Error(`Registry agent token budget ${maxTokens} exceeded.`)
|
|
217
|
+
return raw
|
|
218
|
+
} finally {
|
|
219
|
+
if (timer) clearTimeout(timer)
|
|
220
|
+
active -= 1
|
|
221
|
+
}
|
|
222
|
+
}
|
|
84
223
|
return {
|
|
85
224
|
metadata,
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
225
|
+
enrich: async (task, packs, options = {}) => {
|
|
226
|
+
const input = JSON.stringify(packs)
|
|
227
|
+
if (Buffer.byteLength(input, 'utf8') > maxInputBytes) throw new Error(`Registry agent input limit ${maxInputBytes} bytes exceeded.`)
|
|
228
|
+
const context = deepFreeze({
|
|
229
|
+
protocol: REGISTRY_AGENT_PROTOCOL_V2,
|
|
230
|
+
task,
|
|
231
|
+
role: options.role ?? task,
|
|
232
|
+
promptVersion: options.promptVersion ?? '1',
|
|
233
|
+
packs: redactValue(packs),
|
|
234
|
+
capabilities: ['pack.read', 'proposal.write'] as const,
|
|
235
|
+
network: false as const,
|
|
236
|
+
shell: false as const,
|
|
237
|
+
deterministic: settings.deterministic ?? true,
|
|
238
|
+
}) as RegistryEnrichmentContext
|
|
239
|
+
const raw = await transport(context)
|
|
240
|
+
const proposals = raw && typeof raw === 'object' && 'proposals' in raw ? (raw as { proposals: unknown }).proposals : undefined
|
|
241
|
+
if (!Array.isArray(proposals)) throw new Error('Registry agent must return one JSON object with a "proposals" array.')
|
|
242
|
+
if (proposals.length > 1_024) throw new Error('Registry agent returned more than 1024 proposals.')
|
|
243
|
+
return proposals
|
|
244
|
+
},
|
|
245
|
+
run: async (snapshot, report, evidence = report.diagnostics.flatMap((diagnostic) => diagnostic.evidence).slice(0, 64), documentation) => {
|
|
246
|
+
const cacheKey = sha256NormalizedV1({ snapshotHash: snapshot.contentHash, reportHash: report.contentHash, documentationAuditHash: documentation?.contentHash ?? null, agentId: metadata.id, agentVersion: metadata.version, cli: settings.cli ?? null, maxInputBytes, evidence })
|
|
89
247
|
if (settings.deterministic && deterministicCache.has(cacheKey)) return deterministicCache.get(cacheKey) as AgentProposalV1
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
248
|
+
const context = deepFreeze({
|
|
249
|
+
snapshot: redactValue(snapshot),
|
|
250
|
+
report: redactValue(report),
|
|
251
|
+
evidence: redactValue(evidence),
|
|
252
|
+
...(documentation ? {
|
|
253
|
+
documentation: redactValue({
|
|
254
|
+
contentHash: documentation.contentHash,
|
|
255
|
+
sourceRevision: documentation.sourceRevision,
|
|
256
|
+
status: documentation.status,
|
|
257
|
+
findings: documentation.findings.slice(0, 64),
|
|
258
|
+
documentAssessments: documentation.documentAssessments.slice(0, 128),
|
|
259
|
+
metrics: documentation.metrics,
|
|
260
|
+
limitations: documentation.limitations,
|
|
261
|
+
}),
|
|
262
|
+
} : {}),
|
|
263
|
+
capabilities: ['snapshot.read', 'evidence.read', 'proposal.write'] as const,
|
|
264
|
+
network: false as const,
|
|
265
|
+
shell: false as const,
|
|
266
|
+
deterministic: settings.deterministic ?? true,
|
|
267
|
+
}) as RegistryAgentContext
|
|
268
|
+
const raw = await transport(context)
|
|
269
|
+
const proposal = AgentProposalV1Schema.parse(raw)
|
|
270
|
+
if (proposal.contentHash !== contentHashForArtifactV1(proposal)) throw new Error('Registry agent proposal contentHash does not match its canonical contents.')
|
|
271
|
+
if (proposal.baseSnapshotHash !== snapshot.contentHash || proposal.baseReportHash !== report.contentHash) throw new Error('Registry agent proposal is not based on the supplied snapshot/report hashes.')
|
|
272
|
+
if (documentation && proposal.baseDocumentationAuditHash !== documentation.contentHash) throw new Error('Registry agent proposal is not based on the supplied documentation audit hash.')
|
|
273
|
+
if (proposal.origin.kind !== 'registry-agent' || proposal.origin.id !== metadata.id || proposal.origin.version !== metadata.version) throw new Error(`Registry agent proposal origin must be ${metadata.id}@${metadata.version}.`)
|
|
274
|
+
validateGrounding(proposal, snapshot, report, documentation)
|
|
275
|
+
if (settings.deterministic) deterministicCache.set(cacheKey, proposal)
|
|
276
|
+
return proposal
|
|
109
277
|
},
|
|
110
278
|
}
|
|
111
279
|
}
|