@piagent/platform 1.5.5 → 1.6.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 +117 -0
- package/README.md +9 -8
- package/README.vi.md +9 -5
- package/adapters/web-frontend/profile.json +2 -4
- package/architecture/layers.json +18 -3
- package/benchmarks/deep-logic-v1/SPECIALIST_PROTOCOL.vi.md +122 -0
- package/benchmarks/deep-logic-v1/grade.mjs +272 -10
- package/benchmarks/deep-logic-v1/project/apps/admin/src/billing-summary.js +3 -0
- package/benchmarks/deep-logic-v1/project/benchmark-contract/public-smoke.test.js +166 -0
- package/benchmarks/deep-logic-v1/project/package.json +1 -1
- package/benchmarks/deep-logic-v1/project/packages/billing/src/close-period.js +3 -0
- package/benchmarks/deep-logic-v1/project/packages/billing/src/plan-timeline.js +3 -0
- package/benchmarks/deep-logic-v1/project/test/smoke.test.js +7 -1
- package/benchmarks/deep-logic-v1/prompts/budgeted-context-graph.md +2 -0
- package/benchmarks/deep-logic-v1/prompts/fair-dependency-scheduler.md +2 -0
- package/benchmarks/deep-logic-v1/prompts/layered-policy-resolution.md +2 -0
- package/benchmarks/deep-logic-v1/prompts/resumable-stream-assembly.md +3 -1
- package/benchmarks/deep-logic-v1/prompts/revision-event-reconciliation.md +2 -0
- package/benchmarks/deep-logic-v1/prompts/temporal-usage-billing-close.md +123 -0
- package/benchmarks/deep-logic-v1/prompts/transactional-config-merge.md +2 -0
- package/benchmarks/deep-logic-v1/suite.json +51 -3
- package/benchmarks/deep-logic-v1/variant.mjs +22 -1
- package/benchmarks/production-v1/spend-control.v1.json +68 -0
- package/benchmarks/production-v1/suite.json +42 -3
- package/catalog/capabilities.json +6 -6
- package/docs/command-reference-vietnamese.md +6 -6
- package/docs/context-engine.md +7 -1
- package/docs/distribution-standard.md +7 -7
- package/docs/en/architecture.md +1 -0
- package/docs/languages.json +4 -4
- package/docs/model-options.md +8 -5
- package/docs/operator-manual-vietnamese.md +13 -11
- package/docs/project-adapters.md +2 -2
- package/docs/publishing-for-teams.md +5 -0
- package/docs/quality-benchmark.md +271 -62
- package/docs/release-install-policy.md +10 -9
- package/docs/runtime-policy-design.md +4 -4
- package/docs/runtime-quality-baseline.md +13 -6
- package/docs/security-threat-model.md +2 -2
- package/docs/task-lifecycle-vietnamese.md +2 -2
- package/docs/team-onboarding.md +2 -2
- package/docs/usage-observability.md +7 -2
- package/docs/vi/architecture.md +1 -0
- package/docs-site/architecture.html +1 -1
- package/docs-site/benchmark.html +1 -1
- package/docs-site/commands.html +1 -1
- package/docs-site/context-engine.html +1 -1
- package/docs-site/en/architecture.html +1 -1
- package/docs-site/en/benchmark.html +1 -1
- package/docs-site/en/commands.html +1 -1
- package/docs-site/en/context-engine.html +1 -1
- package/docs-site/en/index.html +1 -1
- package/docs-site/en/mcp-approval.html +1 -1
- package/docs-site/en/mcp-auth.html +1 -1
- package/docs-site/en/mcp-servers.html +1 -1
- package/docs-site/en/mcp.html +1 -1
- package/docs-site/en/permissions.html +1 -1
- package/docs-site/en/profiles.html +1 -1
- package/docs-site/en/quickstart.html +1 -1
- package/docs-site/en/runtime.html +1 -1
- package/docs-site/en/scope.html +1 -1
- package/docs-site/en/security.html +1 -1
- package/docs-site/en/team.html +1 -1
- package/docs-site/en/whats-new.html +1 -1
- package/docs-site/en/workflows.html +1 -1
- package/docs-site/index.html +1 -1
- package/docs-site/mcp-approval.html +1 -1
- package/docs-site/mcp-auth.html +1 -1
- package/docs-site/mcp-servers.html +1 -1
- package/docs-site/mcp.html +1 -1
- package/docs-site/permissions.html +1 -1
- package/docs-site/profiles.html +1 -1
- package/docs-site/quickstart.html +1 -1
- package/docs-site/runtime.html +1 -1
- package/docs-site/scope.html +1 -1
- package/docs-site/security.html +1 -1
- package/docs-site/team.html +1 -1
- package/docs-site/whats-new.html +1 -1
- package/docs-site/workflows.html +1 -1
- package/evals/fixtures/benchmark-assurance-evidence.invalid.json +1 -1
- package/evals/fixtures/benchmark-assurance-evidence.valid.json +1 -1
- package/evals/fixtures/piagent-webui/session-live-state-v1.invalid.json +18 -0
- package/evals/fixtures/piagent-webui/session-live-state-v1.valid.json +27 -0
- package/evals/fs4-readiness-matrix.v1.json +2 -2
- package/evals/fs5-causal-arm.v1.json +2 -2
- package/evals/fs5-pilot-protocol.v1.json +2 -2
- package/evals/fs5-pilot-protocol.v4.json +6 -5
- package/evals/fs5-pilot-protocol.v5.json +7 -6
- package/evals/private-holdout-v1/public-exposure.v1.json +1 -1
- package/package.json +3 -1
- package/packages/piagent-core/benchmark/benchmark-assurance.js +4 -1
- package/packages/piagent-core/benchmark/benchmark-bootstrap.js +91 -9
- package/packages/piagent-core/benchmark/benchmark-claim-restrictions.js +38 -7
- package/packages/piagent-core/benchmark/benchmark-cli.js +7 -7
- package/packages/piagent-core/benchmark/benchmark-codex.js +3 -1
- package/packages/piagent-core/benchmark/benchmark-comparison.js +271 -2
- package/packages/piagent-core/benchmark/benchmark-core.js +732 -661
- package/packages/piagent-core/benchmark/benchmark-execution-guard.js +7 -5
- package/packages/piagent-core/benchmark/benchmark-forensics.js +439 -4
- package/packages/piagent-core/benchmark/benchmark-host-readiness.js +639 -0
- package/packages/piagent-core/benchmark/benchmark-matrix.js +22 -4
- package/packages/piagent-core/benchmark/benchmark-normalized-cost.js +317 -0
- package/packages/piagent-core/benchmark/benchmark-preflight.js +3 -1
- package/packages/piagent-core/benchmark/benchmark-process.js +6 -5
- package/packages/piagent-core/benchmark/benchmark-provider-wire.js +126 -0
- package/packages/piagent-core/benchmark/benchmark-record-validation.js +183 -0
- package/packages/piagent-core/benchmark/benchmark-report.js +116 -12
- package/packages/piagent-core/benchmark/benchmark-resume-recovery.js +14 -0
- package/packages/piagent-core/benchmark/benchmark-runner-policy.js +26 -0
- package/packages/piagent-core/benchmark/benchmark-stage-diagnostic.js +782 -0
- package/packages/piagent-core/benchmark/benchmark-statistics.js +64 -0
- package/packages/piagent-core/benchmark/benchmark-stop-policy.js +8 -5
- package/packages/piagent-core/benchmark/benchmark-suite-identity.js +31 -0
- package/packages/piagent-core/benchmark/benchmark-suite-runtime.js +13 -9
- package/packages/piagent-core/benchmark/benchmark-suite.js +128 -2
- package/packages/piagent-core/benchmark/benchmark-summary-support.js +376 -0
- package/packages/piagent-core/benchmark/benchmark-timing-diagnostics.js +971 -0
- package/packages/piagent-core/benchmark/benchmark-usage.js +311 -0
- package/packages/piagent-core/benchmark/benchmark-workflow.js +166 -0
- package/packages/piagent-core/docs/context-efficiency-improvement-plan.md +1080 -0
- package/packages/piagent-core/extensions/acceptance-contract-semantics.js +83 -69
- package/packages/piagent-core/extensions/acceptance-error-classes.js +160 -0
- package/packages/piagent-core/extensions/acceptance-executable-evidence.js +12 -9
- package/packages/piagent-core/extensions/acceptance-receipt.js +34 -11
- package/packages/piagent-core/extensions/acceptance-state-machine-evidence.js +518 -0
- package/packages/piagent-core/extensions/acceptance-test-binding-evidence.js +60 -0
- package/packages/piagent-core/extensions/context-efficiency-metrics.js +302 -0
- package/packages/piagent-core/extensions/context-efficiency-report.js +167 -0
- package/packages/piagent-core/extensions/context-engine.js +148 -145
- package/packages/piagent-core/extensions/context-evidence.js +48 -0
- package/packages/piagent-core/extensions/context-import-links.js +296 -0
- package/packages/piagent-core/extensions/context-telemetry-integrity.js +65 -0
- package/packages/piagent-core/extensions/criterion-context-pack.js +422 -7
- package/packages/piagent-core/extensions/criterion-graph.js +78 -8
- package/packages/piagent-core/extensions/guard-types.ts +2 -0
- package/packages/piagent-core/extensions/javascript-regex-evidence.js +32 -0
- package/packages/piagent-core/extensions/piagent-guard.ts +233 -41
- package/packages/piagent-core/extensions/task-contract-view.js +17 -3
- package/packages/piagent-core/extensions/task-lifecycle.js +7 -2
- package/packages/piagent-core/extensions/task-state.js +40 -134
- package/packages/piagent-core/extensions/verification-intelligence.js +3 -1
- package/packages/piagent-core/extensions/workspace-evidence-roots.js +157 -0
- package/packages/piagent-core/package.json +1 -1
- package/packages/piagent-core/policies/base-policy.json +2 -0
- package/packages/piagent-core/runtime/context/context-delivery.ts +103 -0
- package/packages/piagent-core/runtime/context/context-delta-shadow.ts +53 -0
- package/packages/piagent-core/runtime/context/context-efficiency-format.ts +47 -0
- package/packages/piagent-core/runtime/context/context-evidence-qualification.ts +32 -0
- package/packages/piagent-core/runtime/context/prefix-telemetry.ts +47 -0
- package/packages/piagent-core/runtime/context/repository-memory-hints.ts +27 -0
- package/packages/piagent-core/runtime/hooks/agent-prompt-telemetry.ts +56 -0
- package/packages/piagent-core/runtime/hooks/agent-start-hook.ts +162 -102
- package/packages/piagent-core/runtime/hooks/completion-hook.ts +5 -6
- package/packages/piagent-core/runtime/hooks/input-hook.ts +11 -1
- package/packages/piagent-core/runtime/hooks/session-hooks.ts +22 -2
- package/packages/piagent-core/runtime/hooks/session-start-hook.ts +7 -2
- package/packages/piagent-core/runtime/hooks/tool-result-content-guards.ts +95 -0
- package/packages/piagent-core/runtime/hooks/tool-result-hook.ts +84 -102
- package/packages/piagent-core/runtime/inspection/activity-event-adapter.ts +4 -2
- package/packages/piagent-core/runtime/inspection/activity-recovery.ts +104 -0
- package/packages/piagent-core/runtime/inspection/task-compaction-history.ts +1 -1
- package/packages/piagent-core/runtime/inspection/task-handoff-history.ts +1 -1
- package/packages/piagent-core/runtime/inspection/tool-failure-classification.ts +53 -0
- package/packages/piagent-core/runtime/inspection/webui-snapshot.ts +34 -6
- package/packages/piagent-core/runtime/model/authenticated-catalog.ts +17 -9
- package/packages/piagent-core/runtime/model/openai-codex-reasoning.ts +83 -0
- package/packages/piagent-core/runtime/model/provider-wire-fingerprint.ts +238 -0
- package/packages/piagent-core/runtime/orchestration/role-policy.ts +1 -1
- package/packages/piagent-core/runtime/product/activity-inspector.ts +7 -2
- package/packages/piagent-core/runtime/product/efficiency-metrics.ts +4 -2
- package/packages/piagent-core/runtime/quality/exact-output-contract.ts +2 -1
- package/packages/piagent-core/runtime/quality/performance-assurance-signals.ts +23 -0
- package/packages/piagent-core/runtime/quality/performance-assurance.ts +6 -2
- package/packages/piagent-core/runtime/recovery/edit-recovery-context.ts +113 -0
- package/packages/piagent-core/runtime/recovery/edit-recovery-delivery.ts +42 -0
- package/packages/piagent-core/runtime/recovery/semantic-repair-handshake.ts +55 -2
- package/packages/piagent-core/runtime/recovery/semantic-repair-runtime.ts +55 -2
- package/packages/piagent-core/runtime/registration/context-commands.ts +66 -5
- package/packages/piagent-core/runtime/registration/policy-tools.ts +46 -11
- package/packages/piagent-core/runtime/registration/task-completion-tools.ts +49 -16
- package/packages/piagent-core/runtime/registration/task-start-guidance.ts +163 -0
- package/packages/piagent-core/runtime/registration/task-start-retry-helpers.ts +37 -0
- package/packages/piagent-core/runtime/registration/task-start-tool.ts +67 -62
- package/packages/piagent-core/runtime/session/runtime-state.ts +154 -2
- package/packages/piagent-core/runtime/session/system-prompt.ts +4 -4
- package/packages/piagent-core/runtime/tools/apply-patch-tool.ts +500 -0
- package/packages/piagent-core/runtime/trajectory/trajectory-runtime.ts +2 -1
- package/packages/piagent-core/runtime/workflows/task-intake.ts +43 -2
- package/packages/piagent-core/security/sensitive-data.js +13 -218
- package/packages/piagent-core/security/sensitive-project-file.js +42 -0
- package/packages/piagent-core/security/sensitive-source-expression.js +330 -0
- package/packages/piagent-core/security/sensitive-source-formats.js +394 -0
- package/packages/piagent-core/security/sensitive-text.js +234 -0
- package/packages/piagent-core/subagents/piagent-worker.md +1 -1
- package/packages/piagent-webui/dist/client/assets/{MarkdownMessage-rD9WJKxs.js → MarkdownMessage-CxeZqTte.js} +1 -1
- package/packages/piagent-webui/dist/client/assets/index-DynIMe8I.js +176 -0
- package/packages/piagent-webui/dist/client/index.html +1 -1
- package/packages/piagent-webui/gateway/gateway-events.ts +109 -5
- package/packages/piagent-webui/gateway/gateway-service.ts +3 -0
- package/packages/piagent-webui/gateway/gateway-session-stream.ts +93 -7
- package/packages/piagent-webui/gateway/session-command-controller.ts +18 -3
- package/packages/piagent-webui/gateway/session-effective-options.ts +47 -0
- package/packages/piagent-webui/gateway/session-live-state.ts +21 -0
- package/packages/piagent-webui/gateway/session-operation-start.ts +5 -1
- package/packages/piagent-webui/gateway/session-operation-watchdog.ts +158 -0
- package/packages/piagent-webui/gateway/session-runtime-factory.ts +45 -0
- package/packages/piagent-webui/gateway/session-runtime-supervisor.ts +139 -124
- package/packages/piagent-webui/server/loopback-server.ts +8 -0
- package/packages/piagent-webui/server/transcript-projection.ts +22 -4
- package/packages/piagent-webui/shared/text-visibility.ts +10 -0
- package/schemas/piagent-webui/catalog-v1.json +9 -0
- package/schemas/piagent-webui/gateway-protocol-v1.schema.json +53 -3
- package/schemas/piagent-webui/session-live-state-v1.schema.json +76 -0
- package/schemas/task-contract.schema.json +12 -1
- package/scripts/benchmark-runner-core.mjs +355 -359
- package/scripts/benchmark-runner-finalization.mjs +309 -0
- package/scripts/benchmark-runner-host-readiness.mjs +94 -0
- package/scripts/benchmark-runner-support.mjs +200 -0
- package/scripts/benchmark-session.mjs +95 -41
- package/scripts/configure-model-scope.sh +4 -3
- package/scripts/helper-evaluation.mjs +1 -1
- package/scripts/install-global.sh +2 -2
- package/scripts/pi-usage-history.mjs +37 -10
- package/scripts/setup.sh +2 -2
- package/scripts/verify-local.sh +5 -1
- package/templates/global/settings.json +2 -1
- package/packages/piagent-webui/dist/client/assets/index-BZRFw1u6.js +0 -174
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export function median(values) {
|
|
2
|
+
const finite = values.filter(Number.isFinite).sort((left, right) => left - right);
|
|
3
|
+
if (finite.length === 0) return null;
|
|
4
|
+
const middle = Math.floor(finite.length / 2);
|
|
5
|
+
return finite.length % 2 ? finite[middle] : (finite[middle - 1] + finite[middle]) / 2;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function geometricMean(values) {
|
|
9
|
+
if (!Array.isArray(values) || values.length === 0) return null;
|
|
10
|
+
if (values.some((value) => !Number.isFinite(value) || value <= 0)) return null;
|
|
11
|
+
return Math.exp(values.reduce((sum, value) => sum + Math.log(value), 0) / values.length);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function rounded(value, digits = 3) {
|
|
15
|
+
if (!Number.isFinite(value)) return null;
|
|
16
|
+
const factor = 10 ** digits;
|
|
17
|
+
return Math.round(value * factor) / factor;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function clamp(value, minimum = 0, maximum = 10) {
|
|
21
|
+
return Math.max(minimum, Math.min(maximum, value));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function wilsonInterval(successes, total, z = 1.959963984540054) {
|
|
25
|
+
if (!Number.isInteger(total) || total <= 0 || !Number.isInteger(successes) || successes < 0 || successes > total) return null;
|
|
26
|
+
const proportion = successes / total;
|
|
27
|
+
const zSquared = z ** 2;
|
|
28
|
+
const denominator = 1 + (zSquared / total);
|
|
29
|
+
const center = (proportion + (zSquared / (2 * total))) / denominator;
|
|
30
|
+
const margin = (z / denominator) * Math.sqrt(((proportion * (1 - proportion)) / total) + (zSquared / (4 * total ** 2)));
|
|
31
|
+
return { lower: rounded(Math.max(0, center - margin), 4), upper: rounded(Math.min(1, center + margin), 4) };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const STUDENT_T_975 = Object.freeze([
|
|
35
|
+
null, 12.706, 4.303, 3.182, 2.776, 2.571, 2.447, 2.365, 2.306, 2.262,
|
|
36
|
+
2.228, 2.201, 2.179, 2.16, 2.145, 2.131, 2.12, 2.11, 2.101, 2.093,
|
|
37
|
+
2.086, 2.08, 2.074, 2.069, 2.064, 2.06, 2.056, 2.052, 2.048, 2.045, 2.042
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
export function geometricMeanConfidence95Raw(values) {
|
|
41
|
+
if (!Array.isArray(values) || values.length < 2 || values.some((value) => !Number.isFinite(value) || value <= 0)) return null;
|
|
42
|
+
const logs = values.map(Math.log);
|
|
43
|
+
const mean = logs.reduce((sum, value) => sum + value, 0) / logs.length;
|
|
44
|
+
const variance = logs.reduce((sum, value) => sum + ((value - mean) ** 2), 0) / (logs.length - 1);
|
|
45
|
+
const critical = STUDENT_T_975[logs.length - 1] ?? 1.96;
|
|
46
|
+
const margin = critical * Math.sqrt(variance / logs.length);
|
|
47
|
+
return {
|
|
48
|
+
lower: Math.exp(mean - margin),
|
|
49
|
+
upper: Math.exp(mean + margin),
|
|
50
|
+
sampleUnit: "scenario-family",
|
|
51
|
+
scenarioCount: logs.length
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function geometricMeanConfidence95(values) {
|
|
56
|
+
const interval = geometricMeanConfidence95Raw(values);
|
|
57
|
+
return interval ? { ...interval, lower: rounded(interval.lower, 4), upper: rounded(interval.upper, 4) } : null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function atMostWithinFloatingPrecision(value, maximum) {
|
|
61
|
+
if (!Number.isFinite(value) || !Number.isFinite(maximum)) return false;
|
|
62
|
+
const tolerance = Number.EPSILON * Math.max(1, Math.abs(value), Math.abs(maximum)) * 8;
|
|
63
|
+
return value <= maximum || Math.abs(value - maximum) <= tolerance;
|
|
64
|
+
}
|
|
@@ -5,11 +5,14 @@ function samePair(left, right) {
|
|
|
5
5
|
function outcomeFailure(run, floor) {
|
|
6
6
|
if (run?.surface !== "piagent") return null;
|
|
7
7
|
if (run?.resolved !== true) return "unresolved-outcome";
|
|
8
|
-
if (run
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (run
|
|
12
|
-
|
|
8
|
+
if (run?.scope?.passed !== true) return "scope-safety-evidence-failed";
|
|
9
|
+
if (run?.outputSafety?.passed !== true) return "output-safety-evidence-failed";
|
|
10
|
+
if (run.scenarioKind === "safety-refusal") return run?.grade?.passed === true ? null : "safety-refusal-grade-failed";
|
|
11
|
+
if (run?.grade?.passed !== true) return "quality-grade-failed";
|
|
12
|
+
if (run?.graderIntegrity?.passed !== true) return "grader-integrity-failed";
|
|
13
|
+
if (run?.outputEvidence?.passed === false) return "output-evidence-failed";
|
|
14
|
+
if (!Number.isFinite(run.grade?.score) || run.grade.score <= floor) return "quality-outcome-floor";
|
|
15
|
+
if (!Number.isFinite(run.workflow?.score) || run.workflow.score <= floor) return "workflow-outcome-floor";
|
|
13
16
|
return null;
|
|
14
17
|
}
|
|
15
18
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
export const BUILT_IN_BENCHMARK_SUITE_IDS = Object.freeze([
|
|
5
|
+
"core-v1",
|
|
6
|
+
"capability-v1",
|
|
7
|
+
"e2-framework-v1",
|
|
8
|
+
"deep-logic-v1",
|
|
9
|
+
"production-v1"
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
const reservedSuiteIds = new Set(BUILT_IN_BENCHMARK_SUITE_IDS);
|
|
13
|
+
|
|
14
|
+
export function isReservedBenchmarkSuiteId(value) {
|
|
15
|
+
return reservedSuiteIds.has(value);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function builtInBenchmarkSuiteManifest(packageRoot, suiteId) {
|
|
19
|
+
return isReservedBenchmarkSuiteId(suiteId)
|
|
20
|
+
? path.join(packageRoot, "benchmarks", suiteId, "suite.json")
|
|
21
|
+
: null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function canonicalBuiltInBenchmarkSuiteId(packageRoot, manifestPath) {
|
|
25
|
+
const resolvedManifest = fs.realpathSync(manifestPath);
|
|
26
|
+
for (const suiteId of BUILT_IN_BENCHMARK_SUITE_IDS) {
|
|
27
|
+
const candidate = builtInBenchmarkSuiteManifest(packageRoot, suiteId);
|
|
28
|
+
if (fs.existsSync(candidate) && fs.realpathSync(candidate) === resolvedManifest) return suiteId;
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
@@ -5,6 +5,11 @@ import path from "node:path";
|
|
|
5
5
|
import { benchmarkAssuranceEvidenceValidationErrors } from "./benchmark-core.js";
|
|
6
6
|
import { validateBenchmarkSuite } from "./benchmark-suite.js";
|
|
7
7
|
import { assertBenchmarkModuleGraphBound } from "./benchmark-suite-assets.js";
|
|
8
|
+
import {
|
|
9
|
+
builtInBenchmarkSuiteManifest,
|
|
10
|
+
canonicalBuiltInBenchmarkSuiteId,
|
|
11
|
+
isReservedBenchmarkSuiteId
|
|
12
|
+
} from "./benchmark-suite-identity.js";
|
|
8
13
|
|
|
9
14
|
function fail(message) {
|
|
10
15
|
const error = new Error(message);
|
|
@@ -18,14 +23,7 @@ function inside(parent, target) {
|
|
|
18
23
|
}
|
|
19
24
|
|
|
20
25
|
export function loadBenchmarkSuite(input, packageRoot) {
|
|
21
|
-
const
|
|
22
|
-
["core-v1", path.join(packageRoot, "benchmarks", "core-v1", "suite.json")],
|
|
23
|
-
["capability-v1", path.join(packageRoot, "benchmarks", "capability-v1", "suite.json")],
|
|
24
|
-
["e2-framework-v1", path.join(packageRoot, "benchmarks", "e2-framework-v1", "suite.json")],
|
|
25
|
-
["deep-logic-v1", path.join(packageRoot, "benchmarks", "deep-logic-v1", "suite.json")],
|
|
26
|
-
["production-v1", path.join(packageRoot, "benchmarks", "production-v1", "suite.json")]
|
|
27
|
-
]);
|
|
28
|
-
const candidate = builtIn.get(input) ?? path.resolve(input);
|
|
26
|
+
const candidate = builtInBenchmarkSuiteManifest(packageRoot, input) ?? path.resolve(input);
|
|
29
27
|
const manifestPath = fs.existsSync(candidate) && fs.statSync(candidate).isDirectory()
|
|
30
28
|
? path.join(candidate, "suite.json")
|
|
31
29
|
: candidate;
|
|
@@ -33,7 +31,13 @@ export function loadBenchmarkSuite(input, packageRoot) {
|
|
|
33
31
|
try { raw = JSON.parse(fs.readFileSync(manifestPath, "utf8")); }
|
|
34
32
|
catch (error) { fail(`Cannot read benchmark suite ${manifestPath}: ${error.message}`); }
|
|
35
33
|
const suite = validateBenchmarkSuite(raw);
|
|
36
|
-
|
|
34
|
+
const resolvedManifestPath = fs.realpathSync(manifestPath);
|
|
35
|
+
const builtInId = canonicalBuiltInBenchmarkSuiteId(packageRoot, resolvedManifestPath);
|
|
36
|
+
if (builtInId && suite.id !== builtInId) fail(`Built-in benchmark suite identity mismatch: expected ${builtInId}, found ${suite.id}`);
|
|
37
|
+
if (!builtInId && isReservedBenchmarkSuiteId(suite.id)) {
|
|
38
|
+
fail(`Benchmark suite id ${suite.id} is reserved for its canonical built-in suite`);
|
|
39
|
+
}
|
|
40
|
+
return { suite, manifestPath: resolvedManifestPath, suiteRoot: fs.realpathSync(path.dirname(resolvedManifestPath)), builtInId };
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
export function resolveBenchmarkSuiteEntry(suiteRoot, relativePath, kind) {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { benchmarkAssuranceValidationErrors } from "./benchmark-assurance.js";
|
|
2
|
+
import { benchmarkPricingSnapshotValidationErrors } from "./benchmark-normalized-cost.js";
|
|
2
3
|
|
|
3
4
|
const SUITE_FIELDS = new Set([
|
|
4
5
|
"schemaVersion", "id", "title", "description", "profile", "defaultRepeats", "timeoutSeconds",
|
|
5
|
-
"assurance", "releaseGate", "scenarios"
|
|
6
|
+
"assurance", "releaseGate", "executionContract", "pricingSnapshot", "scenarios"
|
|
6
7
|
]);
|
|
7
8
|
const SCENARIO_FIELDS = new Set([
|
|
8
9
|
"id", "title", "description", "kind", "fixture", "prompt", "grader", "allowedChanges",
|
|
@@ -12,11 +13,24 @@ const SCENARIO_FIELDS = new Set([
|
|
|
12
13
|
const RELEASE_GATE_FIELDS = new Set([
|
|
13
14
|
"minimumQualityScore", "minimumSafetyScore", "minimumReliabilityScore", "minimumWorkflowScore",
|
|
14
15
|
"minimumCategoryScore", "minimumOutcomeScoreExclusive", "minimumPairedScenarios", "minimumRepeats",
|
|
15
|
-
"minimumComparableEfficiencyScenarios", "maximumFreshTokenRatioUpper95", "
|
|
16
|
+
"minimumComparableEfficiencyScenarios", "maximumFreshTokenRatioUpper95", "maximumDurationRatioUpper95",
|
|
17
|
+
"maximumBandDurationRatio", "maximumFamilyDurationRatio",
|
|
18
|
+
"maximumBandFreshTokenRatio", "maximumFamilyFreshTokenRatio",
|
|
19
|
+
"maximumNormalizedCostRatioUpper95", "maximumBandNormalizedCostRatio", "maximumFamilyNormalizedCostRatio",
|
|
20
|
+
"maximumInfrastructureRetries", "primaryEfficiencyEstimand", "requireEfficiencyClaim", "requireFullSuiteForClaim",
|
|
21
|
+
"requireStableProviderWireSurface", "requireNormalizedCostClaim", "requireHostReadinessForClaim",
|
|
22
|
+
"requireCausalContextReceipt"
|
|
16
23
|
]);
|
|
24
|
+
const EXECUTION_CONTRACT_FIELDS = new Set(["surfaces", "model", "thinking", "codexMode"]);
|
|
25
|
+
const THINKING_LEVELS = new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
|
|
17
26
|
const SCENARIO_KINDS = new Set(["source-change", "read-only", "safety-refusal"]);
|
|
18
27
|
const SCENARIO_DIFFICULTIES = new Set(["small", "medium", "large"]);
|
|
19
28
|
const SCENARIO_LIFECYCLES = new Set(["steady-state", "cold-start"]);
|
|
29
|
+
const PRIMARY_EFFICIENCY_ESTIMANDS = new Set([
|
|
30
|
+
"successful-pair-family-ratio",
|
|
31
|
+
"failure-aware-family-ratio",
|
|
32
|
+
"fixed-workload-family-ratio"
|
|
33
|
+
]);
|
|
20
34
|
const ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
21
35
|
|
|
22
36
|
function plainObject(value) {
|
|
@@ -86,13 +100,96 @@ export function benchmarkSuiteValidationErrors(input) {
|
|
|
86
100
|
if (minimumRepeats !== undefined && (!Number.isInteger(minimumRepeats) || minimumRepeats < 1 || minimumRepeats > 10)) {
|
|
87
101
|
errors.push("releaseGate.minimumRepeats must be between 1 and 10");
|
|
88
102
|
}
|
|
103
|
+
const maximumInfrastructureRetries = input.releaseGate.maximumInfrastructureRetries;
|
|
104
|
+
if (maximumInfrastructureRetries !== undefined && (!Number.isInteger(maximumInfrastructureRetries) || maximumInfrastructureRetries < 0 || maximumInfrastructureRetries > 1_000)) {
|
|
105
|
+
errors.push("releaseGate.maximumInfrastructureRetries must be between 0 and 1000");
|
|
106
|
+
}
|
|
89
107
|
const maximumRatio = input.releaseGate.maximumFreshTokenRatioUpper95;
|
|
90
108
|
if (maximumRatio !== undefined && (!Number.isFinite(maximumRatio) || maximumRatio <= 0 || maximumRatio > 10)) {
|
|
91
109
|
errors.push("releaseGate.maximumFreshTokenRatioUpper95 must be greater than 0 and at most 10");
|
|
92
110
|
}
|
|
111
|
+
const maximumBandRatio = input.releaseGate.maximumBandFreshTokenRatio;
|
|
112
|
+
if (maximumBandRatio !== undefined && (!Number.isFinite(maximumBandRatio) || maximumBandRatio <= 0 || maximumBandRatio > 10)) {
|
|
113
|
+
errors.push("releaseGate.maximumBandFreshTokenRatio must be greater than 0 and at most 10");
|
|
114
|
+
}
|
|
115
|
+
const maximumFamilyRatio = input.releaseGate.maximumFamilyFreshTokenRatio;
|
|
116
|
+
if (maximumFamilyRatio !== undefined && (!Number.isFinite(maximumFamilyRatio) || maximumFamilyRatio <= 0 || maximumFamilyRatio > 10)) {
|
|
117
|
+
errors.push("releaseGate.maximumFamilyFreshTokenRatio must be greater than 0 and at most 10");
|
|
118
|
+
}
|
|
119
|
+
const maximumDurationRatio = input.releaseGate.maximumDurationRatioUpper95;
|
|
120
|
+
if (maximumDurationRatio !== undefined && (!Number.isFinite(maximumDurationRatio) || maximumDurationRatio <= 0 || maximumDurationRatio > 10)) {
|
|
121
|
+
errors.push("releaseGate.maximumDurationRatioUpper95 must be greater than 0 and at most 10");
|
|
122
|
+
}
|
|
123
|
+
for (const field of ["maximumBandDurationRatio", "maximumFamilyDurationRatio"]) {
|
|
124
|
+
const value = input.releaseGate[field];
|
|
125
|
+
if (value !== undefined && (!Number.isFinite(value) || value <= 0 || value > 10)) {
|
|
126
|
+
errors.push(`releaseGate.${field} must be greater than 0 and at most 10`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
for (const field of [
|
|
130
|
+
"maximumNormalizedCostRatioUpper95", "maximumBandNormalizedCostRatio", "maximumFamilyNormalizedCostRatio"
|
|
131
|
+
]) {
|
|
132
|
+
const value = input.releaseGate[field];
|
|
133
|
+
if (value !== undefined && (!Number.isFinite(value) || value <= 0 || value > 10)) {
|
|
134
|
+
errors.push(`releaseGate.${field} must be greater than 0 and at most 10`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
93
137
|
if (input.releaseGate.requireEfficiencyClaim !== undefined && typeof input.releaseGate.requireEfficiencyClaim !== "boolean") {
|
|
94
138
|
errors.push("releaseGate.requireEfficiencyClaim must be a boolean");
|
|
95
139
|
}
|
|
140
|
+
if (input.releaseGate.primaryEfficiencyEstimand !== undefined
|
|
141
|
+
&& !PRIMARY_EFFICIENCY_ESTIMANDS.has(input.releaseGate.primaryEfficiencyEstimand)) {
|
|
142
|
+
errors.push("releaseGate.primaryEfficiencyEstimand is invalid");
|
|
143
|
+
}
|
|
144
|
+
if (input.releaseGate.primaryEfficiencyEstimand === "fixed-workload-family-ratio") {
|
|
145
|
+
for (const field of ["maximumBandFreshTokenRatio", "maximumFamilyFreshTokenRatio"]) {
|
|
146
|
+
if (input.releaseGate[field] !== undefined) {
|
|
147
|
+
errors.push(`releaseGate.${field} is incompatible with fixed-workload-family-ratio; use the full-suite primary confidence gate`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (input.releaseGate.requireFullSuiteForClaim !== undefined && typeof input.releaseGate.requireFullSuiteForClaim !== "boolean") {
|
|
152
|
+
errors.push("releaseGate.requireFullSuiteForClaim must be a boolean");
|
|
153
|
+
}
|
|
154
|
+
if (input.releaseGate.requireStableProviderWireSurface !== undefined && typeof input.releaseGate.requireStableProviderWireSurface !== "boolean") {
|
|
155
|
+
errors.push("releaseGate.requireStableProviderWireSurface must be a boolean");
|
|
156
|
+
}
|
|
157
|
+
if (input.releaseGate.requireNormalizedCostClaim !== undefined && typeof input.releaseGate.requireNormalizedCostClaim !== "boolean") {
|
|
158
|
+
errors.push("releaseGate.requireNormalizedCostClaim must be a boolean");
|
|
159
|
+
}
|
|
160
|
+
if (input.releaseGate.requireHostReadinessForClaim !== undefined && typeof input.releaseGate.requireHostReadinessForClaim !== "boolean") {
|
|
161
|
+
errors.push("releaseGate.requireHostReadinessForClaim must be a boolean");
|
|
162
|
+
}
|
|
163
|
+
if (input.releaseGate.requireCausalContextReceipt !== undefined && typeof input.releaseGate.requireCausalContextReceipt !== "boolean") {
|
|
164
|
+
errors.push("releaseGate.requireCausalContextReceipt must be a boolean");
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (input.pricingSnapshot !== undefined) {
|
|
169
|
+
errors.push(...benchmarkPricingSnapshotValidationErrors(input.pricingSnapshot));
|
|
170
|
+
if (plainObject(input.executionContract) && input.pricingSnapshot?.model !== input.executionContract.model) {
|
|
171
|
+
errors.push("pricingSnapshot.model must match executionContract.model");
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (input.executionContract !== undefined) {
|
|
175
|
+
if (!plainObject(input.executionContract)) errors.push("executionContract must be an object");
|
|
176
|
+
else {
|
|
177
|
+
for (const field of Object.keys(input.executionContract)) {
|
|
178
|
+
if (!EXECUTION_CONTRACT_FIELDS.has(field)) errors.push(`executionContract has unsupported field ${field}`);
|
|
179
|
+
}
|
|
180
|
+
const contract = input.executionContract;
|
|
181
|
+
if (!Array.isArray(contract.surfaces)
|
|
182
|
+
|| contract.surfaces.length !== 2
|
|
183
|
+
|| contract.surfaces[0] !== "piagent"
|
|
184
|
+
|| contract.surfaces[1] !== "codex-cli") {
|
|
185
|
+
errors.push("executionContract.surfaces must be exactly piagent,codex-cli");
|
|
186
|
+
}
|
|
187
|
+
requiredString(contract.model, "executionContract.model", errors);
|
|
188
|
+
if (typeof contract.model === "string" && !/^[^/\s]+\/[^/\s]+$/.test(contract.model)) {
|
|
189
|
+
errors.push("executionContract.model must use provider/model form");
|
|
190
|
+
}
|
|
191
|
+
if (!THINKING_LEVELS.has(contract.thinking)) errors.push("executionContract.thinking is invalid");
|
|
192
|
+
if (contract.codexMode !== "controlled") errors.push("executionContract.codexMode must be controlled");
|
|
96
193
|
}
|
|
97
194
|
}
|
|
98
195
|
if (input.schemaVersion === 2 && (!plainObject(input.assurance) || !plainObject(input.releaseGate))) {
|
|
@@ -101,6 +198,35 @@ export function benchmarkSuiteValidationErrors(input) {
|
|
|
101
198
|
if (input.schemaVersion === 2 && input.releaseGate?.requireEfficiencyClaim === true && !Number.isInteger(input.releaseGate?.minimumComparableEfficiencyScenarios)) {
|
|
102
199
|
errors.push("schemaVersion 2 efficiency claims require releaseGate.minimumComparableEfficiencyScenarios");
|
|
103
200
|
}
|
|
201
|
+
if (input.schemaVersion === 2 && input.releaseGate?.requireEfficiencyClaim === true
|
|
202
|
+
&& (!Number.isFinite(input.releaseGate?.maximumFreshTokenRatioUpper95) || input.releaseGate.maximumFreshTokenRatioUpper95 > 0.8)) {
|
|
203
|
+
errors.push("schemaVersion 2 token-saving claims require releaseGate.maximumFreshTokenRatioUpper95 at or below 0.8");
|
|
204
|
+
}
|
|
205
|
+
if (input.schemaVersion === 2 && input.releaseGate?.requireEfficiencyClaim === true && input.releaseGate?.requireFullSuiteForClaim !== true) {
|
|
206
|
+
errors.push("schemaVersion 2 token-saving claims require releaseGate.requireFullSuiteForClaim true");
|
|
207
|
+
}
|
|
208
|
+
if (input.schemaVersion === 2 && input.releaseGate?.requireEfficiencyClaim === true && input.releaseGate?.requireStableProviderWireSurface !== true) {
|
|
209
|
+
errors.push("schemaVersion 2 token-saving claims require releaseGate.requireStableProviderWireSurface true");
|
|
210
|
+
}
|
|
211
|
+
if (input.schemaVersion === 2 && input.releaseGate?.requireEfficiencyClaim === true && input.releaseGate?.requireCausalContextReceipt !== true) {
|
|
212
|
+
errors.push("schemaVersion 2 token-saving claims require releaseGate.requireCausalContextReceipt true");
|
|
213
|
+
}
|
|
214
|
+
if (input.schemaVersion === 2 && input.releaseGate?.requireNormalizedCostClaim === true) {
|
|
215
|
+
if (!plainObject(input.pricingSnapshot)) errors.push("schemaVersion 2 normalized-cost claims require pricingSnapshot");
|
|
216
|
+
if (!Number.isFinite(input.releaseGate.maximumNormalizedCostRatioUpper95)
|
|
217
|
+
|| input.releaseGate.maximumNormalizedCostRatioUpper95 > 0.8) {
|
|
218
|
+
errors.push("schemaVersion 2 normalized-cost claims require releaseGate.maximumNormalizedCostRatioUpper95 at or below 0.8");
|
|
219
|
+
}
|
|
220
|
+
if (!Number.isFinite(input.releaseGate.maximumBandNormalizedCostRatio)) {
|
|
221
|
+
errors.push("schemaVersion 2 normalized-cost claims require releaseGate.maximumBandNormalizedCostRatio");
|
|
222
|
+
}
|
|
223
|
+
if (!Number.isFinite(input.releaseGate.maximumFamilyNormalizedCostRatio)) {
|
|
224
|
+
errors.push("schemaVersion 2 normalized-cost claims require releaseGate.maximumFamilyNormalizedCostRatio");
|
|
225
|
+
}
|
|
226
|
+
if (input.releaseGate.requireEfficiencyClaim !== true) {
|
|
227
|
+
errors.push("schemaVersion 2 normalized-cost claims require releaseGate.requireEfficiencyClaim true");
|
|
228
|
+
}
|
|
229
|
+
}
|
|
104
230
|
if (!Array.isArray(input.scenarios) || input.scenarios.length === 0 || input.scenarios.length > 50) {
|
|
105
231
|
errors.push("scenarios must contain between 1 and 50 entries");
|
|
106
232
|
return errors;
|