From 4a0bbf04cb28d9af45ccfc564e7590036ec78349 Mon Sep 17 00:00:00 2001 From: luis manrique <166242911+lluisinthedesert@users.noreply.github.com> Date: Tue, 4 Aug 2026 04:33:29 -0700 Subject: [PATCH 1/8] add campaign admission contract --- ...derstudy.campaign_admission.v1.schema.json | 84 + src/campaign-admission/index.ts | 232 +++ src/commands/campaigns.ts | 51 + src/index.ts | 17 + tests/campaign-admission-cli.test.mjs | 53 + tests/campaign-admission.test.mjs | 123 ++ .../fixtures/campaign-admission/request.json | 1 + .../fixtures/campaign-admission/response.json | 1 + tests/fixtures/campaign-admission/tools.json | 1 + .../uv-project/pyproject.toml | 10 + .../campaign-admission/uv-project/uv.lock | 1693 +++++++++++++++++ .../verifiers-0.2.1-one-task-trace.json | 16 + 12 files changed, 2282 insertions(+) create mode 100644 schemas/understudy.campaign_admission.v1.schema.json create mode 100644 src/campaign-admission/index.ts create mode 100644 src/commands/campaigns.ts create mode 100644 tests/campaign-admission-cli.test.mjs create mode 100644 tests/campaign-admission.test.mjs create mode 100644 tests/fixtures/campaign-admission/request.json create mode 100644 tests/fixtures/campaign-admission/response.json create mode 100644 tests/fixtures/campaign-admission/tools.json create mode 100644 tests/fixtures/campaign-admission/uv-project/pyproject.toml create mode 100644 tests/fixtures/campaign-admission/uv-project/uv.lock create mode 100644 tests/fixtures/campaign-admission/verifiers-0.2.1-one-task-trace.json diff --git a/schemas/understudy.campaign_admission.v1.schema.json b/schemas/understudy.campaign_admission.v1.schema.json new file mode 100644 index 00000000..0e8bd3db --- /dev/null +++ b/schemas/understudy.campaign_admission.v1.schema.json @@ -0,0 +1,84 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://understudylabs.com/schemas/understudy.campaign_admission.v1.schema.json", + "title": "understudy.campaign_admission.v1", + "description": "Public, fail-closed campaign admission evidence. References and hashes only; never embeds customer prompts, traces, credentials, or answer keys.", + "type": "object", + "additionalProperties": false, + "required": ["schema_version", "campaign_id", "environment", "transport_fingerprints", "mutation_smoke", "spend"], + "properties": { + "schema_version": { "const": "understudy.campaign_admission.v1" }, + "campaign_id": { "type": "string", "minLength": 1 }, + "environment": { "$ref": "#/$defs/environment" }, + "transport_fingerprints": { "$ref": "#/$defs/fingerprints" }, + "mutation_smoke": { "$ref": "#/$defs/mutation_smoke" }, + "spend": { "$ref": "#/$defs/spend" } + }, + "$defs": { + "sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, + "image_digest": { "type": "string", "pattern": "^sha256:[a-f0-9]{64}$" }, + "exact_version": { "type": "string", "pattern": "^[0-9][0-9A-Za-z.!+_-]*$" }, + "environment": { + "type": "object", "additionalProperties": false, + "required": ["pyproject_sha256", "uv_lock_sha256", "uv_lock_check_command", "uv_lock_check_exit_code", "uv_version", "python_version", "python_executable_sha256", "resolved_packages", "container_image_digest"], + "properties": { + "pyproject_sha256": { "$ref": "#/$defs/sha256" }, + "uv_lock_sha256": { "$ref": "#/$defs/sha256" }, + "uv_lock_check_command": { "const": "uv lock --check" }, + "uv_lock_check_exit_code": { "const": 0 }, + "uv_version": { "$ref": "#/$defs/exact_version" }, + "python_version": { "$ref": "#/$defs/exact_version" }, + "python_executable_sha256": { "$ref": "#/$defs/sha256" }, + "container_image_digest": { "$ref": "#/$defs/image_digest" }, + "resolved_packages": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/package_pin" } } + } + }, + "package_pin": { + "type": "object", "additionalProperties": false, "required": ["name", "version"], + "properties": { + "name": { "type": "string", "minLength": 1 }, + "version": { "$ref": "#/$defs/exact_version" }, + "git_revision": { "type": ["string", "null"], "pattern": "^[a-f0-9]{40}$" } + } + }, + "fingerprints": { + "type": "object", "additionalProperties": false, + "required": ["raw_request_sha256", "semantic_request_sha256", "raw_response_sha256", "semantic_response_sha256", "raw_tools_sha256", "semantic_tools_sha256"], + "properties": { + "raw_request_sha256": { "$ref": "#/$defs/sha256" }, "semantic_request_sha256": { "$ref": "#/$defs/sha256" }, + "raw_response_sha256": { "$ref": "#/$defs/sha256" }, "semantic_response_sha256": { "$ref": "#/$defs/sha256" }, + "raw_tools_sha256": { "$ref": "#/$defs/sha256" }, "semantic_tools_sha256": { "$ref": "#/$defs/sha256" } + } + }, + "mutation_smoke": { + "type": "object", "additionalProperties": false, + "required": ["runtime", "verifiers_version", "task_count", "calls", "nodes", "assertion_fraction", "seed_candidate_sha256", "mutated_candidate_sha256", "eval_exit_code", "trace_artifact_sha256", "mutating_effects"], + "properties": { + "runtime": { "const": "standard-verifiers" }, "verifiers_version": { "const": "0.2.1" }, "task_count": { "const": 1 }, + "calls": { "type": "integer", "minimum": 1 }, "nodes": { "type": "integer", "minimum": 1 }, + "assertion_fraction": { "type": "number", "exclusiveMinimum": 0, "maximum": 1 }, + "seed_candidate_sha256": { "$ref": "#/$defs/sha256" }, "mutated_candidate_sha256": { "$ref": "#/$defs/sha256" }, + "eval_exit_code": { "const": 0 }, "trace_artifact_sha256": { "$ref": "#/$defs/sha256" }, + "mutating_effects": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["tool", "applied"], "properties": { "tool": { "type": "string", "minLength": 1 }, "applied": { "const": true } } } + } + }, + "allocation": { "type": "object", "additionalProperties": false, "required": ["cap_usd"], "properties": { "cap_usd": { "type": "number", "minimum": 0 } } }, + "transfer": { + "type": "object", "additionalProperties": false, "required": ["transfer_id", "from", "to", "amount_usd", "authority_id", "immutable_receipt_sha256"], + "properties": { "transfer_id": { "type": "string", "minLength": 1 }, "from": { "enum": ["optimizer", "endpoint", "training"] }, "to": { "enum": ["optimizer", "endpoint", "training"] }, "amount_usd": { "type": "number", "exclusiveMinimum": 0 }, "authority_id": { "type": "string", "minLength": 1 }, "immutable_receipt_sha256": { "$ref": "#/$defs/sha256" } } + }, + "charge": { + "type": "object", "additionalProperties": false, "required": ["charge_id", "lane", "amount_usd", "immutable_receipt_sha256"], + "properties": { "charge_id": { "type": "string", "minLength": 1 }, "lane": { "enum": ["optimizer", "endpoint", "training"] }, "amount_usd": { "type": "number", "minimum": 0 }, "immutable_receipt_sha256": { "$ref": "#/$defs/sha256" } } + }, + "spend": { + "type": "object", "additionalProperties": false, "required": ["campaign_total_usd", "allocations", "transfers", "charges"], + "properties": { + "campaign_total_usd": { "type": "number", "minimum": 0 }, + "allocations": { "type": "object", "additionalProperties": false, "required": ["optimizer", "endpoint", "training"], "properties": { "optimizer": { "$ref": "#/$defs/allocation" }, "endpoint": { "$ref": "#/$defs/allocation" }, "training": { "$ref": "#/$defs/allocation" } }, + "transfers": { "type": "array", "items": { "$ref": "#/$defs/transfer" } }, + "charges": { "type": "array", "items": { "$ref": "#/$defs/charge" } } + } + } + } +} diff --git a/src/campaign-admission/index.ts b/src/campaign-admission/index.ts new file mode 100644 index 00000000..3566241a --- /dev/null +++ b/src/campaign-admission/index.ts @@ -0,0 +1,232 @@ +import { createHash } from "node:crypto"; +import { readFileSync } from "node:fs"; + +export const CAMPAIGN_ADMISSION_SCHEMA_VERSION = "understudy.campaign_admission.v1" as const; +export const SPEND_LANES = ["optimizer", "endpoint", "training"] as const; + +export type SpendLane = (typeof SPEND_LANES)[number]; +type JsonObject = Record; + +export type TransportArtifacts = { + request: Buffer; + response: Buffer; + tools: Buffer; + trace: Buffer; +}; + +export type TransportFingerprints = { + raw_request_sha256: string; + semantic_request_sha256: string; + raw_response_sha256: string; + semantic_response_sha256: string; + raw_tools_sha256: string; + semantic_tools_sha256: string; +}; + +export type AdmissionResult = { + admitted: boolean; + errors: string[]; + fingerprints: TransportFingerprints; + effective_spend_caps_usd: Record; +}; + +export type ResolvedPackagePin = { name: string; version: string; git_revision?: string }; + +const SHA256 = /^[a-f0-9]{64}$/; +// Exact PEP 440-ish resolved versions may have one or two numeric segments, +// epochs, post releases, or local suffixes; specifier operators/wildcards do +// not belong in an attested resolved lock. +const EXACT_VERSION = /^[0-9][0-9A-Za-z.!+_-]*$/; +const GIT_REVISION = /^[a-f0-9]{40}$/; +const IMAGE_DIGEST = /^sha256:[a-f0-9]{64}$/; + +export function sha256Bytes(value: Uint8Array): string { + return createHash("sha256").update(value).digest("hex"); +} + +function canonicalize(value: unknown): string { + if (value === null || typeof value !== "object") return JSON.stringify(value); + if (Array.isArray(value)) return `[${value.map(canonicalize).join(",")}]`; + return `{${Object.entries(value as JsonObject) + .sort(([left], [right]) => left.localeCompare(right)) + .map(([key, item]) => `${JSON.stringify(key)}:${canonicalize(item)}`) + .join(",")}}`; +} + +export function semanticJsonSha256(bytes: Uint8Array, label: string): string { + let parsed: unknown; + try { + parsed = JSON.parse(Buffer.from(bytes).toString("utf8")); + } catch { + throw new Error(`${label} must contain valid JSON`); + } + return sha256Bytes(Buffer.from(canonicalize(parsed))); +} + +export function fingerprintTransport(artifacts: TransportArtifacts): TransportFingerprints { + return { + raw_request_sha256: sha256Bytes(artifacts.request), + semantic_request_sha256: semanticJsonSha256(artifacts.request, "request"), + raw_response_sha256: sha256Bytes(artifacts.response), + semantic_response_sha256: semanticJsonSha256(artifacts.response, "response"), + raw_tools_sha256: sha256Bytes(artifacts.tools), + semantic_tools_sha256: semanticJsonSha256(artifacts.tools, "tools"), + }; +} + +export function parseUvLockPins(lockText: string): ResolvedPackagePin[] { + return lockText.split(/^\[\[package\]\]\s*$/m).slice(1).map((block) => { + const name = block.match(/^name = "([^"]+)"$/m)?.[1]; + const version = block.match(/^version = "([^"]+)"$/m)?.[1]; + if (!name || !version) throw new Error("uv.lock contains a package without an exact name/version"); + const gitRevision = block.match(/^source = \{ git = "[^"]+#([a-f0-9]{40})" \}$/m)?.[1]; + return { name, version, ...(gitRevision ? { git_revision: gitRevision } : {}) }; + }).sort((left, right) => left.name.localeCompare(right.name) || left.version.localeCompare(right.version)); +} + +function object(value: unknown): JsonObject { + return value !== null && typeof value === "object" && !Array.isArray(value) ? value as JsonObject : {}; +} + +function number(value: unknown): number | null { + return typeof value === "number" && Number.isFinite(value) ? value : null; +} + +function requireSha(errors: string[], value: unknown, path: string): void { + if (typeof value !== "string" || !SHA256.test(value)) errors.push(`${path} must be a lowercase sha256`); +} + +function validateEnvironment(manifest: JsonObject, errors: string[]): void { + const environment = object(manifest.environment); + requireSha(errors, environment.pyproject_sha256, "environment.pyproject_sha256"); + requireSha(errors, environment.uv_lock_sha256, "environment.uv_lock_sha256"); + if (environment.uv_lock_check_command !== "uv lock --check") errors.push("environment.uv_lock_check_command must equal 'uv lock --check'"); + if (environment.uv_lock_check_exit_code !== 0) errors.push("environment.uv_lock_check_exit_code must equal 0"); + if (typeof environment.uv_version !== "string" || !EXACT_VERSION.test(environment.uv_version)) errors.push("environment.uv_version must be exact"); + if (typeof environment.python_version !== "string" || !EXACT_VERSION.test(environment.python_version)) errors.push("environment.python_version must be exact"); + requireSha(errors, environment.python_executable_sha256, "environment.python_executable_sha256"); + if (typeof environment.container_image_digest !== "string" || !IMAGE_DIGEST.test(environment.container_image_digest)) errors.push("environment.container_image_digest must be an immutable sha256 digest"); + + const pins = Array.isArray(environment.resolved_packages) ? environment.resolved_packages.map(object) : []; + if (pins.length === 0) errors.push("environment.resolved_packages must not be empty"); + const names = new Set(); + for (const [index, pin] of pins.entries()) { + const prefix = `environment.resolved_packages[${index}]`; + if (typeof pin.name !== "string" || pin.name.length === 0) errors.push(`${prefix}.name is required`); + else if (names.has(pin.name)) errors.push(`${prefix}.name is duplicated`); + else names.add(pin.name); + if (typeof pin.version !== "string" || !EXACT_VERSION.test(pin.version)) errors.push(`${prefix}.version must be exact`); + if (pin.git_revision !== null && pin.git_revision !== undefined && (typeof pin.git_revision !== "string" || !GIT_REVISION.test(pin.git_revision))) errors.push(`${prefix}.git_revision must be a full 40-character commit`); + } + if (!pins.some((pin) => pin.name === "verifiers" && pin.version === "0.2.1" && typeof pin.git_revision === "string" && GIT_REVISION.test(pin.git_revision))) { + errors.push("environment.resolved_packages must pin verifiers 0.2.1 to a full git revision"); + } +} + +function validateSmoke(manifest: JsonObject, traceBytes: Uint8Array, errors: string[]): void { + const smoke = object(manifest.mutation_smoke); + if (smoke.runtime !== "standard-verifiers") errors.push("mutation_smoke.runtime must equal standard-verifiers"); + if (smoke.verifiers_version !== "0.2.1") errors.push("mutation_smoke.verifiers_version must equal 0.2.1"); + if (smoke.task_count !== 1) errors.push("mutation_smoke.task_count must equal 1"); + if (!(number(smoke.calls) !== null && Number(smoke.calls) > 0)) errors.push("mutation_smoke.calls must be > 0"); + if (!(number(smoke.nodes) !== null && Number(smoke.nodes) > 0)) errors.push("mutation_smoke.nodes must be > 0"); + const fraction = number(smoke.assertion_fraction); + if (fraction === null || fraction <= 0 || fraction > 1) errors.push("mutation_smoke.assertion_fraction must be finite and in (0, 1]"); + requireSha(errors, smoke.seed_candidate_sha256, "mutation_smoke.seed_candidate_sha256"); + requireSha(errors, smoke.mutated_candidate_sha256, "mutation_smoke.mutated_candidate_sha256"); + if (smoke.seed_candidate_sha256 === smoke.mutated_candidate_sha256) errors.push("mutation smoke candidate must be a real mutation"); + if (smoke.eval_exit_code !== 0) errors.push("mutation_smoke.eval_exit_code must equal 0"); + if (smoke.trace_artifact_sha256 !== sha256Bytes(traceBytes)) errors.push("mutation_smoke.trace_artifact_sha256 does not match the supplied trace"); + const effects = Array.isArray(smoke.mutating_effects) ? smoke.mutating_effects.map(object) : []; + if (!effects.some((effect) => typeof effect.tool === "string" && effect.tool.length > 0 && effect.applied === true)) errors.push("mutation_smoke.mutating_effects must contain an applied tool effect"); + + let parsed: unknown; + try { parsed = JSON.parse(Buffer.from(traceBytes).toString("utf8")); } + catch { errors.push("mutation smoke trace must be valid JSON"); return; } + const traces = Array.isArray(parsed) ? parsed : [parsed]; + if (traces.length !== 1) { errors.push("mutation smoke trace must contain exactly one task"); return; } + const trace = object(traces[0]); + if (trace.runtime !== "standard-verifiers" || trace.verifiers_version !== "0.2.1") errors.push("mutation smoke trace is not standard-Verifiers 0.2.1 evidence"); + const calls = Array.isArray(trace.calls) ? trace.calls : []; + const nodes = Array.isArray(trace.nodes) ? trace.nodes.map(object) : []; + if (calls.length !== smoke.calls || calls.length === 0) errors.push("mutation_smoke.calls does not match a non-empty trace calls array"); + if (nodes.length !== smoke.nodes || nodes.length === 0) errors.push("mutation_smoke.nodes does not match a non-empty trace nodes array"); + const traceFraction = number(object(trace.metrics).assertion_fraction) ?? number(object(trace.rewards).assertion_fraction); + if (traceFraction !== fraction) errors.push("mutation_smoke.assertion_fraction does not match the trace"); + const appliedTools = new Set(nodes.flatMap((node) => { + const message = object(node.message); + if (message.role !== "tool") return []; + let content: JsonObject = {}; + try { content = object(typeof message.content === "string" ? JSON.parse(message.content) : message.content); } catch { return []; } + const name = typeof message.name === "string" ? message.name.replace(/^world_toolset_/, "") : ""; + return content.applied === true && name ? [name] : []; + })); + for (const effect of effects) if (effect.applied === true && typeof effect.tool === "string" && !appliedTools.has(effect.tool)) errors.push(`declared mutating effect ${effect.tool} is absent from the trace`); +} + +function validateSpend(manifest: JsonObject, errors: string[]): Record { + const spend = object(manifest.spend); + const total = number(spend.campaign_total_usd); + if (total === null || total < 0) errors.push("spend.campaign_total_usd must be non-negative"); + const allocations = object(spend.allocations); + const caps = Object.fromEntries(SPEND_LANES.map((lane) => [lane, number(object(allocations[lane]).cap_usd) ?? -1])) as Record; + for (const lane of SPEND_LANES) if (caps[lane] < 0) errors.push(`spend.allocations.${lane}.cap_usd must be non-negative`); + if (total !== null && SPEND_LANES.reduce((sum, lane) => sum + Math.max(0, caps[lane]), 0) > total + 1e-9) errors.push("sum of lane caps exceeds campaign total"); + + const effective = { ...caps }; + const transferIds = new Set(); + for (const [index, raw] of (Array.isArray(spend.transfers) ? spend.transfers : []).entries()) { + const transfer = object(raw); + const prefix = `spend.transfers[${index}]`; + if (typeof transfer.transfer_id !== "string" || transfer.transfer_id.length === 0 || transferIds.has(transfer.transfer_id)) errors.push(`${prefix}.transfer_id must be unique`); + else transferIds.add(transfer.transfer_id); + const from = transfer.from as SpendLane; + const to = transfer.to as SpendLane; + const amount = number(transfer.amount_usd); + if (!SPEND_LANES.includes(from) || !SPEND_LANES.includes(to) || from === to) errors.push(`${prefix} must name distinct valid lanes`); + if (amount === null || amount <= 0) errors.push(`${prefix}.amount_usd must be positive`); + if (typeof transfer.authority_id !== "string" || transfer.authority_id.length === 0) errors.push(`${prefix}.authority_id is required`); + requireSha(errors, transfer.immutable_receipt_sha256, `${prefix}.immutable_receipt_sha256`); + if (SPEND_LANES.includes(from) && SPEND_LANES.includes(to) && amount !== null && amount > 0) { + effective[from] -= amount; + effective[to] += amount; + } + } + for (const lane of SPEND_LANES) if (effective[lane] < -1e-9) errors.push(`authorized transfers overdraw ${lane} allocation`); + + const charged = Object.fromEntries(SPEND_LANES.map((lane) => [lane, 0])) as Record; + const chargeIds = new Set(); + for (const [index, raw] of (Array.isArray(spend.charges) ? spend.charges : []).entries()) { + const charge = object(raw); + const prefix = `spend.charges[${index}]`; + const lane = charge.lane as SpendLane; + const amount = number(charge.amount_usd); + if (typeof charge.charge_id !== "string" || charge.charge_id.length === 0 || chargeIds.has(charge.charge_id)) errors.push(`${prefix}.charge_id must be unique`); + else chargeIds.add(charge.charge_id); + if (!SPEND_LANES.includes(lane)) errors.push(`${prefix}.lane is invalid`); + if (amount === null || amount < 0) errors.push(`${prefix}.amount_usd must be non-negative`); + requireSha(errors, charge.immutable_receipt_sha256, `${prefix}.immutable_receipt_sha256`); + if (SPEND_LANES.includes(lane) && amount !== null && amount >= 0) charged[lane] += amount; + } + for (const lane of SPEND_LANES) if (charged[lane] > effective[lane] + 1e-9) errors.push(`${lane} charges exceed its immutable allocation`); + return effective; +} + +export function validateCampaignAdmission(manifest: unknown, artifacts: TransportArtifacts): AdmissionResult { + const value = object(manifest); + const errors: string[] = []; + if (value.schema_version !== CAMPAIGN_ADMISSION_SCHEMA_VERSION) errors.push(`schema_version must equal ${CAMPAIGN_ADMISSION_SCHEMA_VERSION}`); + validateEnvironment(value, errors); + const fingerprints = fingerprintTransport(artifacts); + const declared = object(value.transport_fingerprints); + for (const [key, actual] of Object.entries(fingerprints)) { + if (declared[key] !== actual) errors.push(`transport_fingerprints.${key} does not match the supplied artifact`); + } + validateSmoke(value, artifacts.trace, errors); + const effective_spend_caps_usd = validateSpend(value, errors); + return { admitted: errors.length === 0, errors, fingerprints, effective_spend_caps_usd }; +} + +export function readTransportArtifacts(paths: { request: string; response: string; tools: string; trace: string }): TransportArtifacts { + return { request: readFileSync(paths.request), response: readFileSync(paths.response), tools: readFileSync(paths.tools), trace: readFileSync(paths.trace) }; +} diff --git a/src/commands/campaigns.ts b/src/commands/campaigns.ts new file mode 100644 index 00000000..8f84b597 --- /dev/null +++ b/src/commands/campaigns.ts @@ -0,0 +1,51 @@ +import { execFileSync } from "node:child_process"; +import { createHash } from "node:crypto"; +import { readFileSync } from "node:fs"; +import { join, resolve } from "node:path"; +import type { Command } from "commander"; + +import { parseUvLockPins, readTransportArtifacts, validateCampaignAdmission } from "../campaign-admission/index.js"; + +function fileSha256(path: string): string { + return createHash("sha256").update(readFileSync(path)).digest("hex"); +} + +export function registerCampaignsCommand(program: Command): void { + const campaigns = program.command("campaigns").description("Validate provider-free campaign admission evidence"); + campaigns.command("admit") + .description("Fail closed unless environment, transport, mutation-smoke, and spend evidence is complete") + .requiredOption("--manifest ", "Campaign admission manifest") + .requiredOption("--project ", "Locked uv project directory") + .requiredOption("--request ", "Raw JSON request artifact") + .requiredOption("--response ", "Raw JSON response artifact") + .requiredOption("--tools ", "Raw JSON tool catalog artifact") + .requiredOption("--trace ", "Exactly-one-task standard-Verifiers trace artifact") + .action((options: { manifest: string; project: string; request: string; response: string; tools: string; trace: string }) => { + try { + const project = resolve(options.project); + const manifest = JSON.parse(readFileSync(resolve(options.manifest), "utf8")) as Record; + const environment = manifest.environment as Record; + const pyproject = join(project, "pyproject.toml"); + const lock = join(project, "uv.lock"); + if (environment.pyproject_sha256 !== fileSha256(pyproject)) throw new Error("pyproject.toml hash does not match manifest"); + if (environment.uv_lock_sha256 !== fileSha256(lock)) throw new Error("uv.lock hash does not match manifest"); + const uvVersion = execFileSync("uv", ["--version"], { encoding: "utf8" }).trim().match(/^uv\s+(\S+)/)?.[1]; + if (!uvVersion) throw new Error("could not parse uv version"); + if (environment.uv_version !== uvVersion) throw new Error(`uv version mismatch: expected ${String(environment.uv_version)}, got ${uvVersion}`); + execFileSync("uv", ["lock", "--check", "--project", project], { stdio: "pipe" }); + const declaredPins = JSON.stringify(environment.resolved_packages); + const lockedPins = JSON.stringify(parseUvLockPins(readFileSync(lock, "utf8"))); + if (declaredPins !== lockedPins) throw new Error("resolved package pins do not exactly match uv.lock"); + const python = execFileSync("uv", ["python", "find", String(environment.python_version)], { encoding: "utf8" }).trim(); + const pythonVersion = execFileSync(python, ["-c", "import platform; print(platform.python_version())"], { encoding: "utf8" }).trim(); + if (pythonVersion !== environment.python_version) throw new Error(`python version mismatch: expected ${String(environment.python_version)}, got ${pythonVersion}`); + if (fileSha256(python) !== environment.python_executable_sha256) throw new Error("python executable hash does not match manifest"); + const result = validateCampaignAdmission(manifest, readTransportArtifacts({ request: resolve(options.request), response: resolve(options.response), tools: resolve(options.tools), trace: resolve(options.trace) })); + process.stdout.write(`${JSON.stringify(result, null, 2)}\n`); + if (!result.admitted) process.exitCode = 1; + } catch (error) { + process.stderr.write(`${JSON.stringify({ admitted: false, errors: [error instanceof Error ? error.message : String(error)] })}\n`); + process.exitCode = 1; + } + }); +} diff --git a/src/index.ts b/src/index.ts index f75eaaa7..1a7c1edc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -59,6 +59,7 @@ import { registerInstrumentCommand } from "./commands/instrument.js"; import { registerOptimizeWorkloadCommand } from "./commands/optimize-workload.js"; import { registerWorkloadsCommand } from "./commands/workloads.js"; import { registerExperimentsCommands, registerNextCommand } from "./commands/experiments.js"; +import { registerCampaignsCommand } from "./commands/campaigns.js"; import { daemonStatus } from "./internal/daemon.js"; import { readCliVersion, readManifestVersions } from "./internal/version.js"; import { installedPackageRoot } from "./internal/package-root.js"; @@ -115,6 +116,21 @@ export { type Hooks as OutcomeExecutorHooks, type StoredCall, } from "./outcome-executors/index.js"; +export { + CAMPAIGN_ADMISSION_SCHEMA_VERSION, + SPEND_LANES, + fingerprintTransport, + parseUvLockPins, + readTransportArtifacts, + semanticJsonSha256, + sha256Bytes as sha256CampaignAdmissionBytes, + validateCampaignAdmission, + type AdmissionResult, + type SpendLane, + type TransportArtifacts, + type TransportFingerprints, + type ResolvedPackagePin, +} from "./campaign-admission/index.js"; export const repoRoot = installedPackageRoot(); @@ -920,6 +936,7 @@ export function buildProgram(): Command { registerRuntimeCommand(program); registerTrustCommand(program); registerTrainingCommand(program); + registerCampaignsCommand(program); const understand = program .command("capture-evidence") diff --git a/tests/campaign-admission-cli.test.mjs b/tests/campaign-admission-cli.test.mjs new file mode 100644 index 00000000..0d3c27be --- /dev/null +++ b/tests/campaign-admission-cli.test.mjs @@ -0,0 +1,53 @@ +import assert from "node:assert/strict"; +import { execFileSync, spawnSync } from "node:child_process"; +import { createHash } from "node:crypto"; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join, resolve } from "node:path"; +import { it } from "node:test"; + +const fixture = resolve("tests/fixtures/campaign-admission"); +const sha = (value) => createHash("sha256").update(value).digest("hex"); + +it("campaigns admit verifies the locked project and public synthetic evidence", async (t) => { + if (spawnSync("uv", ["--version"]).status !== 0) return t.skip("uv is unavailable"); + const mod = await import("../dist/campaign-admission/index.js"); + const project = join(fixture, "uv-project"); + const request = join(fixture, "request.json"); + const response = join(fixture, "response.json"); + const tools = join(fixture, "tools.json"); + const trace = join(fixture, "verifiers-0.2.1-one-task-trace.json"); + const python = execFileSync("uv", ["python", "find", "3.12"], { encoding: "utf8" }).trim(); + const pythonVersion = execFileSync(python, ["-c", "import platform; print(platform.python_version())"], { encoding: "utf8" }).trim(); + const artifacts = { request: readFileSync(request), response: readFileSync(response), tools: readFileSync(tools), trace: readFileSync(trace) }; + const lock = readFileSync(join(project, "uv.lock")); + const manifest = { + schema_version: "understudy.campaign_admission.v1", + campaign_id: "public-synthetic-cli", + environment: { + pyproject_sha256: sha(readFileSync(join(project, "pyproject.toml"))), uv_lock_sha256: sha(lock), + uv_lock_check_command: "uv lock --check", uv_lock_check_exit_code: 0, + uv_version: execFileSync("uv", ["--version"], { encoding: "utf8" }).trim().match(/^uv\s+(\S+)/)[1], + python_version: pythonVersion, python_executable_sha256: sha(readFileSync(python)), + container_image_digest: `sha256:${"c".repeat(64)}`, + resolved_packages: mod.parseUvLockPins(lock.toString("utf8")), + }, + transport_fingerprints: mod.fingerprintTransport(artifacts), + mutation_smoke: { + runtime: "standard-verifiers", verifiers_version: "0.2.1", task_count: 1, calls: 1, nodes: 4, assertion_fraction: 1, + seed_candidate_sha256: "d".repeat(64), mutated_candidate_sha256: "e".repeat(64), eval_exit_code: 0, + trace_artifact_sha256: sha(artifacts.trace), mutating_effects: [{ tool: "set-record", applied: true }], + }, + spend: { campaign_total_usd: 3, allocations: { optimizer: { cap_usd: 1 }, endpoint: { cap_usd: 1 }, training: { cap_usd: 1 } }, transfers: [], charges: [] }, + }; + const temp = mkdtempSync(join(tmpdir(), "campaign-admission-cli-")); + try { + const manifestPath = join(temp, "manifest.json"); + writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`); + const run = spawnSync("node", [resolve("dist/bin.js"), "campaigns", "admit", "--manifest", manifestPath, "--project", project, "--request", request, "--response", response, "--tools", tools, "--trace", trace], { encoding: "utf8" }); + assert.equal(run.status, 0, `${run.stderr}\n${run.stdout}`); + assert.equal(JSON.parse(run.stdout).admitted, true); + } finally { + rmSync(temp, { recursive: true, force: true }); + } +}); diff --git a/tests/campaign-admission.test.mjs b/tests/campaign-admission.test.mjs new file mode 100644 index 00000000..82199ad8 --- /dev/null +++ b/tests/campaign-admission.test.mjs @@ -0,0 +1,123 @@ +import assert from "node:assert/strict"; +import { createHash } from "node:crypto"; +import { readFileSync } from "node:fs"; +import { join, resolve } from "node:path"; +import { describe, it } from "node:test"; + +const fixture = resolve("tests/fixtures/campaign-admission"); +const bytes = (name) => readFileSync(join(fixture, name)); +const sha = (value) => createHash("sha256").update(value).digest("hex"); + +function baseManifest(mod) { + const artifacts = { request: bytes("request.json"), response: bytes("response.json"), tools: bytes("tools.json"), trace: bytes("verifiers-0.2.1-one-task-trace.json") }; + const trace = JSON.parse(bytes("verifiers-0.2.1-one-task-trace.json")); + return { + artifacts, + manifest: { + schema_version: "understudy.campaign_admission.v1", + campaign_id: "public-synthetic-campaign", + environment: { + pyproject_sha256: sha(bytes("uv-project/pyproject.toml")), + uv_lock_sha256: sha(bytes("uv-project/uv.lock")), + uv_lock_check_command: "uv lock --check", + uv_lock_check_exit_code: 0, + uv_version: "0.8.0", + python_version: "3.12.11", + python_executable_sha256: "1".repeat(64), + container_image_digest: `sha256:${"2".repeat(64)}`, + resolved_packages: mod.parseUvLockPins(bytes("uv-project/uv.lock").toString("utf8")), + }, + transport_fingerprints: mod.fingerprintTransport(artifacts), + mutation_smoke: { + runtime: trace.runtime, + verifiers_version: trace.verifiers_version, + task_count: 1, + calls: trace.calls.length, + nodes: trace.nodes.length, + assertion_fraction: trace.metrics.assertion_fraction, + seed_candidate_sha256: "4".repeat(64), + mutated_candidate_sha256: "5".repeat(64), + eval_exit_code: 0, + trace_artifact_sha256: sha(bytes("verifiers-0.2.1-one-task-trace.json")), + mutating_effects: [{ tool: "set-record", applied: true }], + }, + spend: { + campaign_total_usd: 100, + allocations: { optimizer: { cap_usd: 20 }, endpoint: { cap_usd: 50 }, training: { cap_usd: 30 } }, + transfers: [], + charges: [ + { charge_id: "optimizer-1", lane: "optimizer", amount_usd: 2, immutable_receipt_sha256: "6".repeat(64) }, + { charge_id: "endpoint-1", lane: "endpoint", amount_usd: 3, immutable_receipt_sha256: "7".repeat(64) }, + { charge_id: "training-1", lane: "training", amount_usd: 4, immutable_receipt_sha256: "8".repeat(64) }, + ], + }, + }, + }; +} + +describe("campaign admission", () => { + it("admits complete provider-free standard-Verifiers 0.2.1 evidence", async () => { + const mod = await import("../dist/campaign-admission/index.js"); + const { manifest, artifacts } = baseManifest(mod); + const result = mod.validateCampaignAdmission(manifest, artifacts); + assert.equal(result.admitted, true, result.errors.join("\n")); + assert.deepEqual(result.effective_spend_caps_usd, { optimizer: 20, endpoint: 50, training: 30 }); + }); + + it("distinguishes raw-byte hashes from canonical semantic hashes", async () => { + const mod = await import("../dist/campaign-admission/index.js"); + const compact = Buffer.from('{"b":2,"a":1}'); + const formatted = Buffer.from('{\n "a": 1,\n "b": 2\n}'); + assert.notEqual(mod.sha256Bytes(compact), mod.sha256Bytes(formatted)); + assert.equal(mod.semanticJsonSha256(compact, "compact"), mod.semanticJsonSha256(formatted, "formatted")); + }); + + it("fails closed for no-op or non-Verifiers mutation evidence", async () => { + const mod = await import("../dist/campaign-admission/index.js"); + const { manifest, artifacts } = baseManifest(mod); + manifest.mutation_smoke.runtime = "mock"; + manifest.mutation_smoke.calls = 0; + manifest.mutation_smoke.nodes = 0; + manifest.mutation_smoke.assertion_fraction = 0; + manifest.mutation_smoke.mutated_candidate_sha256 = manifest.mutation_smoke.seed_candidate_sha256; + manifest.mutation_smoke.mutating_effects = []; + const result = mod.validateCampaignAdmission(manifest, artifacts); + assert.equal(result.admitted, false); + assert.match(result.errors.join("\n"), /standard-verifiers/); + assert.match(result.errors.join("\n"), /real mutation/); + assert.match(result.errors.join("\n"), /applied tool effect/); + }); + + it("requires explicit immutable transfer authority and enforces adjusted lane caps", async () => { + const mod = await import("../dist/campaign-admission/index.js"); + const { manifest, artifacts } = baseManifest(mod); + manifest.spend.transfers.push({ transfer_id: "move-1", from: "training", to: "endpoint", amount_usd: 10, authority_id: "approval-public-1", immutable_receipt_sha256: "9".repeat(64) }); + manifest.spend.charges.push({ charge_id: "endpoint-2", lane: "endpoint", amount_usd: 55, immutable_receipt_sha256: "a".repeat(64) }); + let result = mod.validateCampaignAdmission(manifest, artifacts); + assert.equal(result.admitted, true, result.errors.join("\n")); + assert.deepEqual(result.effective_spend_caps_usd, { optimizer: 20, endpoint: 60, training: 20 }); + delete manifest.spend.transfers[0].authority_id; + result = mod.validateCampaignAdmission(manifest, artifacts); + assert.equal(result.admitted, false); + assert.match(result.errors.join("\n"), /authority_id/); + }); + + it("rejects campaign-total and lane overspend independently", async () => { + const mod = await import("../dist/campaign-admission/index.js"); + const { manifest, artifacts } = baseManifest(mod); + manifest.spend.campaign_total_usd = 99; + manifest.spend.charges.push({ charge_id: "optimizer-2", lane: "optimizer", amount_usd: 19, immutable_receipt_sha256: "b".repeat(64) }); + const result = mod.validateCampaignAdmission(manifest, artifacts); + assert.equal(result.admitted, false); + assert.match(result.errors.join("\n"), /sum of lane caps/); + assert.match(result.errors.join("\n"), /optimizer charges/); + }); + + it("rejects transport evidence when supplied bytes change", async () => { + const mod = await import("../dist/campaign-admission/index.js"); + const { manifest, artifacts } = baseManifest(mod); + const result = mod.validateCampaignAdmission(manifest, { ...artifacts, request: Buffer.from(`${artifacts.request.toString()} `) }); + assert.equal(result.admitted, false); + assert.match(result.errors.join("\n"), /raw_request_sha256/); + }); +}); diff --git a/tests/fixtures/campaign-admission/request.json b/tests/fixtures/campaign-admission/request.json new file mode 100644 index 00000000..f263f610 --- /dev/null +++ b/tests/fixtures/campaign-admission/request.json @@ -0,0 +1 @@ +{"messages":[{"role":"user","content":"Set synthetic record alpha to ready."}],"model":"synthetic-local"} diff --git a/tests/fixtures/campaign-admission/response.json b/tests/fixtures/campaign-admission/response.json new file mode 100644 index 00000000..1a63a99d --- /dev/null +++ b/tests/fixtures/campaign-admission/response.json @@ -0,0 +1 @@ +{"choices":[{"finish_reason":"tool_calls","message":{"role":"assistant","tool_calls":[{"id":"call-public-1","type":"function","function":{"name":"set-record","arguments":"{\"id\":\"alpha\",\"status\":\"ready\"}"}}]}}]} diff --git a/tests/fixtures/campaign-admission/tools.json b/tests/fixtures/campaign-admission/tools.json new file mode 100644 index 00000000..97fd5e9c --- /dev/null +++ b/tests/fixtures/campaign-admission/tools.json @@ -0,0 +1 @@ +[{"type":"function","function":{"name":"set-record","description":"Mutate a public synthetic record.","parameters":{"type":"object","additionalProperties":false,"required":["id","status"],"properties":{"id":{"type":"string"},"status":{"enum":["ready"]}}}}}] diff --git a/tests/fixtures/campaign-admission/uv-project/pyproject.toml b/tests/fixtures/campaign-admission/uv-project/pyproject.toml new file mode 100644 index 00000000..5bc5b84d --- /dev/null +++ b/tests/fixtures/campaign-admission/uv-project/pyproject.toml @@ -0,0 +1,10 @@ +[project] +name = "understudy-campaign-admission-smoke" +version = "0.0.0" +requires-python = "==3.12.*" +dependencies = [ + "verifiers @ git+https://github.com/PrimeIntellect-ai/verifiers.git@ab65b6e8d34b03d162408d4bcb854430a86809e6", +] + +[tool.uv] +override-dependencies = ["mcp==1.29.0"] diff --git a/tests/fixtures/campaign-admission/uv-project/uv.lock b/tests/fixtures/campaign-admission/uv-project/uv.lock new file mode 100644 index 00000000..2f0a31c6 --- /dev/null +++ b/tests/fixtures/campaign-admission/uv-project/uv.lock @@ -0,0 +1,1693 @@ +version = 1 +revision = 3 +requires-python = "==3.12.*" +resolution-markers = [ + "sys_platform == 'win32'", + "sys_platform == 'emscripten'", + "sys_platform != 'emscripten' and sys_platform != 'win32'", +] + +[manifest] +overrides = [{ name = "mcp", specifier = "==1.29.0" }] + +[[package]] +name = "aiofiles" +version = "25.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/41/c3/534eac40372d8ee36ef40df62ec129bee4fdb5ad9706e58a29be53b2c970/aiofiles-25.1.0.tar.gz", hash = "sha256:a8d728f0a29de45dc521f18f07297428d56992a742f0cd2701ba86e44d23d5b2", size = 46354, upload-time = "2025-10-09T20:51:04.358Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl", hash = "sha256:abe311e527c862958650f9438e859c1fa7568a141b22abcd015e120e86a85695", size = 14668, upload-time = "2025-10-09T20:51:03.174Z" }, +] + +[[package]] +name = "aiohappyeyeballs" +version = "2.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ce/f4/eec0465c2f67b2664688d0240b3212d5196fd89e741df67ddb81f8d35658/aiohappyeyeballs-2.7.1.tar.gz", hash = "sha256:065665c041c42a5938ed220bdcd7230f22527fbec085e1853d2402c8a3615d9d", size = 24757, upload-time = "2026-07-01T17:11:55.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl", hash = "sha256:9243213661e29250eb41368e5daa826fc017156c3b8a11440826b2e3ed376472", size = 15038, upload-time = "2026-07-01T17:11:54.055Z" }, +] + +[[package]] +name = "aiohttp" +version = "3.14.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "propcache" }, + { name = "typing-extensions" }, + { name = "yarl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/d9/22ce5786ac0c1653ae8b6c23bded02c1686d11f0dbb45b31ce128e0df985/aiohttp-3.14.3.tar.gz", hash = "sha256:9491196535a88924a60afd5b5f434b5b203b6cc616250878dbdb223a8f7844bc", size = 7971213, upload-time = "2026-07-23T01:57:27.037Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/d4/eb96299230e20acf2efae207cb8d69051f1f68e357e5ea5e479bf6fb097a/aiohttp-3.14.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:39aded8c7f3b935b54aab1d8d73c70ec0ee2d3ec3b943e0e86611bc150ba47f5", size = 754690, upload-time = "2026-07-23T01:53:47.332Z" }, + { url = "https://files.pythonhosted.org/packages/88/11/e7a70a209eb9a067c0d3212b518a0134e3484f5178c7533878b6b514d469/aiohttp-3.14.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5bcb6ff3fdab1258a192679ff1a05d44f59626430aa05cd1a9d2447423599228", size = 509484, upload-time = "2026-07-23T01:53:51.159Z" }, + { url = "https://files.pythonhosted.org/packages/30/07/4bbc222cc8dbe31d4c3e8a5baad2286e4d42026ac0c570027b89afce6344/aiohttp-3.14.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:617105e2c3018ee38d0c8ce5ee3c84f621a6d8b9f723202aacaff28449ca91ee", size = 511949, upload-time = "2026-07-23T01:53:55.083Z" }, + { url = "https://files.pythonhosted.org/packages/54/b9/42e74c46b7b7c794b995bbc1f573fb48950c38b19d8600c62a6804ee2d67/aiohttp-3.14.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f631fe87a6f30df5fbe6d79640b25e4cffb38c31c7fb6f10871517b84b0f8c1a", size = 1765282, upload-time = "2026-07-23T01:53:59.662Z" }, + { url = "https://files.pythonhosted.org/packages/6b/ed/62bc4d74363ad346d518e0720363a949f63e2e23439a79eb5813d4d29bb3/aiohttp-3.14.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a94dbaae5ae27bd849c93570669bff91e0510f33a80805738e3de72a7be0447b", size = 1741511, upload-time = "2026-07-23T01:54:04.063Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9f/181e8a8bc79e47d13c7fc4540bd7a3b729d9505609c61f392a8dd2fbfe55/aiohttp-3.14.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8f2f1c4c032c7cedd7d8da6f54c97b70266c6570c3108d3fdffee7188bb70529", size = 1810680, upload-time = "2026-07-23T01:54:09.882Z" }, + { url = "https://files.pythonhosted.org/packages/5c/9a/dec94d6ad694552fe3424e3f1928d7a606a5d9d9433a04e7ecdd9d38ae7f/aiohttp-3.14.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ea05e1f97ceea523942d9b2a7d7c0359d781d683d6b043f5943a602b14da4787", size = 1905646, upload-time = "2026-07-23T01:54:13.475Z" }, + { url = "https://files.pythonhosted.org/packages/52/b7/7cd31f29d6055bd711ae6e669367fba6f5ae9de463910a793e30556a8db7/aiohttp-3.14.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:543906c127fb1d929b95076db19b83fa2d46751006ff1e23b093aa5ac4d8db42", size = 1792122, upload-time = "2026-07-23T01:54:15.752Z" }, + { url = "https://files.pythonhosted.org/packages/66/73/10b1ef93afa61f4963c746257b70ced619cf31a4798671de5fdb2608501d/aiohttp-3.14.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0a5ff2dfbb9ce645fa5b8ef3e02c6c0b9cc3f6030ff863d0c51fffc50cb5541b", size = 1591127, upload-time = "2026-07-23T01:54:19.489Z" }, + { url = "https://files.pythonhosted.org/packages/49/ed/3b203fa6de1b338c14acdc06bf6ca9b043b7944f005966958c2ced932cde/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:041badb8f84396357c4d3ad26de6afd7a32b112f43d3c63045c0c8278cfd2043", size = 1725210, upload-time = "2026-07-23T01:54:24.129Z" }, + { url = "https://files.pythonhosted.org/packages/28/b7/1c2aab8c706436dcc28598452488ac9cd7c409da815237c28c27d58993e6/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:530125ee1163c4219af35dc3aa1206e541e7b31b6efc1a3f93b70a136f65d427", size = 1764848, upload-time = "2026-07-23T01:54:27.973Z" }, + { url = "https://files.pythonhosted.org/packages/54/50/94c28f08b131c4bf10984ea2c7a536c9920608bb2d6e7f95642c30cc87b7/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c8653fd547c93a61aadc612007790f5555cdd18946fa48cf45e26d8ea4ea473d", size = 1777102, upload-time = "2026-07-23T01:54:31.775Z" }, + { url = "https://files.pythonhosted.org/packages/13/d4/e7d09ba7d345fb2d74440fd2fa033c5e079fac05552927705986f41a364f/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:89176250f686cb9853c0fb7ead90e639e915b84a6f43eedc2a4e7ec21f1037f0", size = 1580205, upload-time = "2026-07-23T01:54:34.518Z" }, + { url = "https://files.pythonhosted.org/packages/a3/84/072a91d68e1e1eb587985b54baab94221277f877e8ef274fc213a0ceae28/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3a26434dafe408229ff3403458ca58de24fb51936504decac49ce6755f77e59d", size = 1797219, upload-time = "2026-07-23T01:54:36.995Z" }, + { url = "https://files.pythonhosted.org/packages/e0/eb/aad34e897e668424d6e995da5dff8a4a09af93363d3392488772957a63aa/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d1558173930a5a8d3069cee5c92fc91c87c4dbcb099debbb3622053717145a19", size = 1768629, upload-time = "2026-07-23T01:54:40.103Z" }, + { url = "https://files.pythonhosted.org/packages/b6/2b/6bb88ddba0fecd9122aa3ebcad25996cf6c083a4a7040dbb3a4f97972af6/aiohttp-3.14.3-cp312-cp312-win32.whl", hash = "sha256:16100ad3ab8d649fdfbee87602d9d2dcdca9df0b9eda8a1b5fdc0d41f96da559", size = 451481, upload-time = "2026-07-23T01:54:42.547Z" }, + { url = "https://files.pythonhosted.org/packages/76/9b/f2f8f108da17ecef2cc3efc424e8b7ad3782b1a8360f7b8eae8ced84f6ea/aiohttp-3.14.3-cp312-cp312-win_amd64.whl", hash = "sha256:33a2d7c28d33797a2e99923dffa63f83d908a19b6bf26cfe80fa790aa5e1a75a", size = 476845, upload-time = "2026-07-23T01:54:44.853Z" }, + { url = "https://files.pythonhosted.org/packages/3e/44/28dac80a8941b604f4da10ce21097614ca1bf905ce93dca28d8d7de9c1e7/aiohttp-3.14.3-cp312-cp312-win_arm64.whl", hash = "sha256:362a3fd481769cac1a824514bcd86fda51c65e8fe6e051099e008fddde6db17c", size = 448050, upload-time = "2026-07-23T01:54:47.087Z" }, +] + +[[package]] +name = "aiolimiter" +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/23/b52debf471f7a1e42e362d959a3982bdcb4fe13a5d46e63d28868807a79c/aiolimiter-1.2.1.tar.gz", hash = "sha256:e02a37ea1a855d9e832252a105420ad4d15011505512a1a1d814647451b5cca9", size = 7185, upload-time = "2024-12-08T15:31:51.496Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/ba/df6e8e1045aebc4778d19b8a3a9bc1808adb1619ba94ca354d9ba17d86c3/aiolimiter-1.2.1-py3-none-any.whl", hash = "sha256:d3f249e9059a20badcb56b61601a83556133655c11d1eb3dd3e04ff069e5f3c7", size = 6711, upload-time = "2024-12-08T15:31:49.874Z" }, +] + +[[package]] +name = "aiosignal" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "frozenlist" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, +] + +[[package]] +name = "annotated-doc" +version = "0.0.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/8e/38aa427ed5402449e226975b649c5dc73ccadfefeb95e6aecb8f8ea4b6b6/annotated_doc-0.0.5.tar.gz", hash = "sha256:c7e58ce09192557605d8bbd92836d7e1d520ac9580096042c0bfd197efacf1bb", size = 10758, upload-time = "2026-07-28T13:50:58.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl", hash = "sha256:117bac03a25ede5df5440e855b32d556049ca169ead221505badf432fed4b101", size = 5302, upload-time = "2026-07-28T13:50:57.239Z" }, +] + +[[package]] +name = "annotated-types" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5f/56/a8120250d128bed162cd73c76d45f6ef9991f3e068f62a8ee060afa3104a/annotated_types-0.8.0.tar.gz", hash = "sha256:13b2beaad985e05e2d6407ee4c4f35590b11f8d693a258a561055cac8f64cab7", size = 15893, upload-time = "2026-07-23T20:16:13.995Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl", hash = "sha256:f072f4d804ea359e4eaf198b1af7a8b0943881a87f31bb764f8bf219bb9419e0", size = 13427, upload-time = "2026-07-23T20:16:12.938Z" }, +] + +[[package]] +name = "anthropic" +version = "0.120.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "docstring-parser" }, + { name = "httpx" }, + { name = "jiter" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d7/10/4ca013cb166f226bd89e0aeb0fcaff94f45ddf716d4925ce89475d3c587b/anthropic-0.120.2.tar.gz", hash = "sha256:9722efc10c27a30a69f5338ddacdb35bc6a64297a4e4ba729bf83af873d5fb3a", size = 1008421, upload-time = "2026-07-28T17:38:26.986Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/af/0f5db57b9397a0f3b7fc204cbef143401a7cadaf982330f97f1ce3d39f34/anthropic-0.120.2-py3-none-any.whl", hash = "sha256:0f0bc2b381dc0eb41c8d886b815d79c2041cd2374f83aed36f574b6dc9c579c1", size = 1022851, upload-time = "2026-07-28T17:38:25.466Z" }, +] + +[[package]] +name = "antlr4-python3-runtime" +version = "4.13.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/33/5f/2cdf6f7aca3b20d3f316e9f505292e1f256a32089bd702034c29ebde6242/antlr4_python3_runtime-4.13.2.tar.gz", hash = "sha256:909b647e1d2fc2b70180ac586df3933e38919c85f98ccc656a96cd3f25ef3916", size = 117467, upload-time = "2024-08-03T19:00:12.757Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/03/a851e84fcbb85214dc637b6378121ef9a0dd61b4c65264675d8a5c9b1ae7/antlr4_python3_runtime-4.13.2-py3-none-any.whl", hash = "sha256:fe3835eb8d33daece0e799090eda89719dbccee7aa39ef94eed3818cafa5a7e8", size = 144462, upload-time = "2024-08-03T19:00:11.134Z" }, +] + +[[package]] +name = "anyio" +version = "4.14.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/cc/a381afa6efea9f496eff839d4a6a1aed3bfafc7b3ab4b0d1b243a12573dd/anyio-4.14.2.tar.gz", hash = "sha256:cfa139f3ed1a23ee8f88a145ddb5ac7605b8bbfd8592baacd7ce3d8bb4313c7f", size = 260176, upload-time = "2026-07-12T20:29:07.082Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size = 125813, upload-time = "2026-07-12T20:29:05.763Z" }, +] + +[[package]] +name = "attrs" +version = "26.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" }, +] + +[[package]] +name = "certifi" +version = "2026.7.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/c2/24167ea9858356b47a87a50d39908bfdb72ceeefe0041586e704e5376b3a/certifi-2026.7.22.tar.gz", hash = "sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55", size = 138112, upload-time = "2026-07-22T03:35:12.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl", hash = "sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775", size = 136983, upload-time = "2026-07-22T03:35:11.276Z" }, +] + +[[package]] +name = "cffi" +version = "2.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9e/ef/008a1939e372c06329a3fce4279c02f328488f3526744906eeec3da7ad5f/cffi-2.1.1.tar.gz", hash = "sha256:dd31f52ea1086513bb9df30f8fcee9b8918323ae067a3d5b78bc826a000712be", size = 530807, upload-time = "2026-08-03T21:21:18.939Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/69/43965eccfdead3b9220015fd1320e117be8c6ed01a62ffab76eeb752f5d5/cffi-2.1.1-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:c8c69575568085ba0b1b10c0249d779a214aea6f6522e949a0fc9fb0fcb449d0", size = 184821, upload-time = "2026-08-03T21:19:44.887Z" }, + { url = "https://files.pythonhosted.org/packages/54/7d/16e5a096677b5e313ca80cd5e5170efa3ea44624a82bb111925522da64b1/cffi-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f81b3b8f3d4e343550fa4baa0e479bba9f2d29ce9c2e9b51d1ce1718d7442fcf", size = 184719, upload-time = "2026-08-03T21:19:46.129Z" }, + { url = "https://files.pythonhosted.org/packages/56/e6/8941622732edec876dd17d0453dce07317ae96db34f2ec1436c9d3785986/cffi-2.1.1-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:811bd1e21d32de12efca32393a0ab3f5133b54fce9bd44b8bd77ab07da14bf6a", size = 214799, upload-time = "2026-08-03T21:19:47.218Z" }, + { url = "https://files.pythonhosted.org/packages/44/de/f98430906df1545ffde0d543dd124a7a439bc2cd32b36b9c53f805df7333/cffi-2.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:68e62fe11f30d5ca8289242866f0a5291402d8529ca2178ab8afc5c9694ae890", size = 222389, upload-time = "2026-08-03T21:19:48.331Z" }, + { url = "https://files.pythonhosted.org/packages/6a/5b/717f1526b9957b34456313c31645c5b82b8fb5c3fe9e4752999be7128bfc/cffi-2.1.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:4a7c934f7360e8cd64fe9efadcbd10c7c6364f531e432b9a4bf5ccbc9e0e8b50", size = 210249, upload-time = "2026-08-03T21:19:49.543Z" }, + { url = "https://files.pythonhosted.org/packages/64/b3/f8aa4f3e34986c7e4ec45072d1b1b9dd295b6b18007b45518d79726dd725/cffi-2.1.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:3143d81e29e1e20a9ce10901ec369012947876596f75a222235965f2b7ae832e", size = 208775, upload-time = "2026-08-03T21:19:50.918Z" }, + { url = "https://files.pythonhosted.org/packages/b1/db/dceb9dd5b231e1da801793f8acc9f3c52a7e1afe40bb1aae37e02b0faad5/cffi-2.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c1453022f490d2459a11819d83ad1d586e9ff65a12ac3e705ffebd46d3685dcf", size = 221822, upload-time = "2026-08-03T21:19:52.054Z" }, + { url = "https://files.pythonhosted.org/packages/a0/d2/6cd24ae3be000a634109c247d1475d62e5616d0dc78c82770942ec384248/cffi-2.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:208f941bb9d18e768138677f0a6d2ce01f590df56043dda1df1535ac57c88517", size = 225232, upload-time = "2026-08-03T21:19:53.109Z" }, + { url = "https://files.pythonhosted.org/packages/cb/52/3fa190537004dd7f0ab860a6dc7c0175b8667f68d1e618a46f5498d30250/cffi-2.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:210019b6c7cf07f081b4c54635c8cf744377001350e29cc0f81c4377b4797735", size = 223597, upload-time = "2026-08-03T21:19:54.515Z" }, + { url = "https://files.pythonhosted.org/packages/80/fb/0bb75b7039588c074b37ae99f40d9bfddf990ecb2fbc346ebccd2e56b9be/cffi-2.1.1-cp312-cp312-win32.whl", hash = "sha256:046bfc24911b37851ee1b51aab8bffe713d89c68c6a057b09484ce9fd5f69b4e", size = 175292, upload-time = "2026-08-03T21:19:55.566Z" }, + { url = "https://files.pythonhosted.org/packages/d9/79/615cc094e2fb508cade7de88d3b4f6c4ec2bab695c97bce9153dc65aadf5/cffi-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:f53e442b08449d42821fa4a4fba000095af9f62742a500f978a9f557ec44339a", size = 185919, upload-time = "2026-08-03T21:19:56.89Z" }, + { url = "https://files.pythonhosted.org/packages/70/c6/d0ea84713fe46b243a436a18fcd47d639732747e21635c8a27191b06dc30/cffi-2.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:7bde5e4cc5c10140859842b9d383af292b22639a4dffb725314baf45968cef80", size = 180093, upload-time = "2026-08-03T21:19:58.155Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/2a/23f34ec9d04624958e137efdc394888716353190e75f25dd22c7a2c7a8aa/charset_normalizer-3.4.9.tar.gz", hash = "sha256:673611bbd43f0810bec0b0f028ddeaaa501190339cac411f347ac76917c3ae7b", size = 152439, upload-time = "2026-07-07T14:34:58.454Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/4a/ecbd131485c07fcdfad54e28946d513e3da22ef3b4bd854dcafae54ec739/charset_normalizer-3.4.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:45b0cc4e3556cd875e09102988d1ab8356c998b596c9fced84547c8138b487a0", size = 319300, upload-time = "2026-07-07T14:33:15.666Z" }, + { url = "https://files.pythonhosted.org/packages/ec/96/5d9364e3342d69f3a045e1777bc47c85c383e6e9466d561b33fdb419d1f9/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b2aff1c7b3884512b9512c3eaadd9bab39fb45042ffaaa1dd08ff2b9f8109d9", size = 215802, upload-time = "2026-07-07T14:33:17.031Z" }, + { url = "https://files.pythonhosted.org/packages/4b/4c/5361f9aa7f2cb58d94f2ab831b3d493f69efb1d239654b4744e3c09527cb/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9104ed0bd76a429d46f9ec0dbc9b08ad1d2dcdf2b00a5a0daa1c145329b35b44", size = 237171, upload-time = "2026-07-07T14:33:18.576Z" }, + { url = "https://files.pythonhosted.org/packages/50/78/ce342ca4ff30b2eb49fe6d9578df85974f90c67d294113e94efdd9664cbd/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7b86a2b16095d250c6f58b3d9b2eee6f4147754344f3dab0922f7c9bf7d226c9", size = 233075, upload-time = "2026-07-07T14:33:20.084Z" }, + { url = "https://files.pythonhosted.org/packages/01/c4/4fa4c8b3097a11f3c5f09a35b72ed6855fb1d332469504962ab7bafcc702/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e226f6218febc71f6c1fc2fafb91c226f75bdc1d8fb12d66823716e891608fd", size = 224256, upload-time = "2026-07-07T14:33:21.747Z" }, + { url = "https://files.pythonhosted.org/packages/87/3a/ad914516df7e358a81aae018caa5e0470ba827fa6d763b1d2e87d920a5f6/charset_normalizer-3.4.9-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:90c44bc373b7687f6948b693cceaea1348ae0975d7474746559494468e3c1d84", size = 208784, upload-time = "2026-07-07T14:33:23.313Z" }, + { url = "https://files.pythonhosted.org/packages/d7/74/3c12f9755717dfe5c5c87da63f35d765fa0c00382ec26bf23f7fae34f2ba/charset_normalizer-3.4.9-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cdef90ae47919cae358d8ab15797a800ed41da7aba5d72419fb510729e2ed4b", size = 219928, upload-time = "2026-07-07T14:33:24.814Z" }, + { url = "https://files.pythonhosted.org/packages/33/9a/895095b83e7907abd6d3d99aad3a38ad0d9686cc186cb0c94c24320fe63e/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:60f44ade2cf573dad7a277e6f8ca9a51a21dda572b13bd7d8539bb3cd5dbedde", size = 218489, upload-time = "2026-07-07T14:33:26.42Z" }, + { url = "https://files.pythonhosted.org/packages/a1/34/ef5c05f412f42520d7709b7d3784d19640839eb7366ded1755511585429f/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a1786910334ed46ab1dd73222f2cd1e05c2c3bb39f6dddb4f8b36fc382058a39", size = 210267, upload-time = "2026-07-07T14:33:27.952Z" }, + { url = "https://files.pythonhosted.org/packages/83/dc/9b29fa4412b318bf3bfea985c35d67eb55e04b59a7c3f2237168b0e0be6f/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:03d07803992c6c7bbc976327f34b18b6160327fc81cb82c9d504720ac0be3b62", size = 226030, upload-time = "2026-07-07T14:33:29.397Z" }, + { url = "https://files.pythonhosted.org/packages/0e/42/6dbc00b8cd16011691203e33570fa42ed5746599a2e878112d16eab403a3/charset_normalizer-3.4.9-cp312-cp312-win32.whl", hash = "sha256:78841cccf1af7b40f6f716338d50c0902dbe88d9f800b3c973b7a9a0a693a642", size = 151185, upload-time = "2026-07-07T14:33:30.781Z" }, + { url = "https://files.pythonhosted.org/packages/80/cc/f920afd1a23c58ccd53c1d36085a71893a4737ff5e66e0371efab6809850/charset_normalizer-3.4.9-cp312-cp312-win_amd64.whl", hash = "sha256:4b3dac63058cc36820b0dd072f89898604e2d39686fe05321729d00d8ac185a0", size = 162557, upload-time = "2026-07-07T14:33:32.176Z" }, + { url = "https://files.pythonhosted.org/packages/f0/e6/0386d43a261ff4e4b30c5857af7df877254b46bec7b9d1b74b6bf969a90b/charset_normalizer-3.4.9-cp312-cp312-win_arm64.whl", hash = "sha256:78fa18e436a1a0e58dbd7e02fc4473f3f32cceb12df9dfca542d075961c307d2", size = 152665, upload-time = "2026-07-07T14:33:33.711Z" }, + { url = "https://files.pythonhosted.org/packages/98/2b/f97f1c193fb855c345d678f5077d6926034db0722df74c8f057020e05a25/charset_normalizer-3.4.9-py3-none-any.whl", hash = "sha256:68e5f26a1ad57ded6d1cfb85331d1c1a195314756471d97758c48498bb4dcdf5", size = 64538, upload-time = "2026-07-07T14:34:56.993Z" }, +] + +[[package]] +name = "click" +version = "8.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/76/d4/81420972a676e8ffea40450d8c8c92943e7218a78fe9b64359836cc9876b/click-8.4.2.tar.gz", hash = "sha256:9a6cea6e60b17ebe0a44c5cc636d94f09bd66142c1cd7d8b4cd731c4917a15f6", size = 338000, upload-time = "2026-06-24T17:45:15.148Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl", hash = "sha256:e6f9f66136c816745b9d65817da91d61d957fb16e02e4dcd0552553c5a197b76", size = 119243, upload-time = "2026-06-24T17:45:13.73Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "connect-python" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, + { name = "pyqwest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/fc/0e4798c53e2754f5de36ecf4d198706cb23711d603df6c008f6e7b5b21ae/connect_python-0.9.0.tar.gz", hash = "sha256:a188ec843b0f5953b7e1b88061af50ad91c9aaa2e982d7a89a63ae5c1fff932e", size = 46094, upload-time = "2026-03-19T02:40:42.279Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/15/5b42df2d9d34e5103f2b69e4f6a4aeb47c52589eaac8d53eb5b0a40eabaa/connect_python-0.9.0-py3-none-any.whl", hash = "sha256:896171fa7236d4e1557e3f7eee76daa8c9dd762f2c21662515f2060f1b542574", size = 63381, upload-time = "2026-03-19T02:40:40.743Z" }, +] + +[[package]] +name = "cryptography" +version = "50.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/41/6cbdcf9142d00fe82836fbb51e503e58088575cf7a0fe1dbff6695bf0840/cryptography-50.0.0.tar.gz", hash = "sha256:eeac2acb5a20ed25e0ad6d1df9891a520b78b404266b6d11778f25d5d691a6c9", size = 880201, upload-time = "2026-07-31T14:25:10.11Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl", hash = "sha256:031e2d5dd4bb9caa3ca9c82e5a197fd8ae680232cee62603d1a813f3f07e3d03", size = 4001252, upload-time = "2026-07-31T14:23:33.331Z" }, + { url = "https://files.pythonhosted.org/packages/57/ef/8f2df13c7216bcad3e1c74e07f6e193d93e998e114f524a53877c9af27ad/cryptography-50.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fd9192b7b70c573d7f214eb1ae35e00d359f6f5e4b27c7e21e30de1fc6204645", size = 4719554, upload-time = "2026-07-31T14:23:35.611Z" }, + { url = "https://files.pythonhosted.org/packages/d9/41/029086c34d91052fc3b88bcc8056f709a7c915c7a23b235a54eb800b1c97/cryptography-50.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:06a32a980526a6ab9a4b9bf8f7385800791e2bb960903cb6b530e4817509a3b7", size = 4702130, upload-time = "2026-07-31T14:23:37.635Z" }, + { url = "https://files.pythonhosted.org/packages/7d/ff/b6ce0954962e7f7b969f850a883744197bb3910bdfd7b6da162eab7d9f68/cryptography-50.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:a1b30560f2acc95aa8b2e06e716a13dbfc97314747b80d9707e307f77b40d6b3", size = 4725244, upload-time = "2026-07-31T14:23:39.471Z" }, + { url = "https://files.pythonhosted.org/packages/06/1e/63a1027cb7fec360a182208e1b7767d5aa1fe57be3d6aa856e69a321edc0/cryptography-50.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:8d89f3976b10b4ce31118de72329025f70d2c6ead14a8217c5514dd2c6d5a78f", size = 5342265, upload-time = "2026-07-31T14:23:41.286Z" }, + { url = "https://files.pythonhosted.org/packages/6b/72/a1116d683a6d7ece94590013882515de087edf9ef0e6292aae615a44df73/cryptography-50.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:b42a28c1844fd9de8f3f7d540e36b66f3a9c83fceac7170ebc7a6a19edd9dcae", size = 4734609, upload-time = "2026-07-31T14:23:43.139Z" }, + { url = "https://files.pythonhosted.org/packages/15/37/36a9c479bbe49acea2636c7fd3360d20f7b7e079c300352011c44850b181/cryptography-50.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:900131fafd8aead39ac7dd3a7e833be754c17a95cfd91221636949fe4eb0aa8a", size = 4356517, upload-time = "2026-07-31T14:23:44.939Z" }, + { url = "https://files.pythonhosted.org/packages/32/98/8a151d64367204cbc63ec65d37502f1d9c53cf4bfc6ec3c532614dbec60d/cryptography-50.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:07949c449a1abcf60d1ee6e88956d89404c7df3c8258f46589e912988e551987", size = 4724529, upload-time = "2026-07-31T14:23:46.93Z" }, + { url = "https://files.pythonhosted.org/packages/22/f6/ec13b470172126464a86bf54d2294a46d29837fc51ba3e45d4047946fb5e/cryptography-50.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:f89831ef99dd7dd169ab06d63a831adb9e20a87aac6d380266bbda5823349169", size = 5299852, upload-time = "2026-07-31T14:23:48.851Z" }, + { url = "https://files.pythonhosted.org/packages/da/3a/f05e32c99d440c9bb891ea0e36c9091891e36be5a9a87ab2ee6ea20729f6/cryptography-50.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:82148ec5bddac30b51a5b3c1945075f896fa022cb93f8e4a01e9f6ee95292c5f", size = 4734462, upload-time = "2026-07-31T14:23:50.861Z" }, + { url = "https://files.pythonhosted.org/packages/ca/dc/bd72b26be8953f80625f63151efd38eee71c76ca6cf591c08ff34615a79e/cryptography-50.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1489e263a8048bb8b6a8bac662eb2d402ea5d2b7b4699b72f385f1e2772db105", size = 4852708, upload-time = "2026-07-31T14:23:52.715Z" }, + { url = "https://files.pythonhosted.org/packages/27/20/c930314a2ab476d15dec966ec87e2e9637bb02b06106b12c0396c57bb603/cryptography-50.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7cec5b856506da6defb290f30c9ee687d5f5e8cb0bd3f6459dde43b0b4fa40ef", size = 5004179, upload-time = "2026-07-31T14:23:54.887Z" }, + { url = "https://files.pythonhosted.org/packages/32/2e/c9db68a0c4bfa28e310707527c0ee3a2bd254104d2e02e68f368e197aa4c/cryptography-50.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:bd1c592e4d5974f0d08d4888e432157adba757c66da0246918e43677fafa2d30", size = 3840395, upload-time = "2026-07-31T14:23:56.677Z" }, + { url = "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:ccdc4a71a4dabae05de219404f9f4abc38e3b58422177ff93d0da05967dafa07", size = 4036009, upload-time = "2026-07-31T14:24:24.122Z" }, + { url = "https://files.pythonhosted.org/packages/ff/c6/7a6202a534e32103a285b7834a120869557fe198d51d7cfe59754c8bda9c/cryptography-50.0.0-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:910e1d2668e7de9648f2bcee30e180db2a6b15c30f887d7c4c93ddf96e3992e3", size = 4745252, upload-time = "2026-07-31T14:24:26.118Z" }, + { url = "https://files.pythonhosted.org/packages/85/4f/0fa8c2f4428198f15d9ff8d63400e27afbf94ce833f6108da1eb3753f945/cryptography-50.0.0-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a91296cb61e8df6f86d0c19cc4068228da256bf59bf86049fbd821084565327f", size = 4728939, upload-time = "2026-07-31T14:24:27.994Z" }, + { url = "https://files.pythonhosted.org/packages/d1/63/54dd723490ba2dc09b299682c10b38db38f159728bcaae8c591b8af2f22d/cryptography-50.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e722f16708d854fe924790e051061f6704a472c3bac347b6fd88033ea8dd0dc5", size = 4748483, upload-time = "2026-07-31T14:24:30.254Z" }, + { url = "https://files.pythonhosted.org/packages/1d/dd/7c77d26285cc7f6991efce64a0f5b4f9383bfa5dd8c5033003eaf7db4cdb/cryptography-50.0.0-cp39-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:d764dcf130c428ef66786f866dd750f53182bc608813489915e9fc106bb0c82f", size = 5367599, upload-time = "2026-07-31T14:24:32.457Z" }, + { url = "https://files.pythonhosted.org/packages/46/c9/f60aed34c013f317f92817b6c171c2d22a78270fa41109bd4b08af26b194/cryptography-50.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:105110f43a471dbd0060b9c9516cb8a6a79233631a04cc2ba16f28323ac6e025", size = 4762647, upload-time = "2026-07-31T14:24:34.599Z" }, + { url = "https://files.pythonhosted.org/packages/be/f3/f9a0173b139372c3a48ed98154b45cc6b9de17c789d5ab552e621c293609/cryptography-50.0.0-cp39-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:828743d939e9629bc267b8e2d08d8bb67cd4319c771a33d4b18b22dd8fb7440a", size = 4385197, upload-time = "2026-07-31T14:24:36.647Z" }, + { url = "https://files.pythonhosted.org/packages/d8/36/83bb81f6e569bc38e1e4a7bc80f29b46bb9601920bc455fc8e888f5d5742/cryptography-50.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:2a8183b489dc1f7f80f135780fadc1108f14b31b8a40411c7a5b17425f65f28b", size = 4748095, upload-time = "2026-07-31T14:24:39.493Z" }, + { url = "https://files.pythonhosted.org/packages/6b/16/d3008eff98c764979865834c3d386d4fd041b5f52e7f34fc29ac1a5eb515/cryptography-50.0.0-cp39-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:6e7d61120573a7f2cd94cc095f9e81f6967c61ccdf194285aa143ecec8e0b708", size = 5325948, upload-time = "2026-07-31T14:24:41.556Z" }, + { url = "https://files.pythonhosted.org/packages/9c/f8/d97f9603efda3888187bfdb893f26c41be4735c10631d05d284ee6b047c4/cryptography-50.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:37fdb0d0111f1e2ff07139dfb79f1b49531f8e213c46f1163dd7642979b58c47", size = 4762400, upload-time = "2026-07-31T14:24:43.636Z" }, + { url = "https://files.pythonhosted.org/packages/64/a2/4615c8f7d81a00b1d6e6afe19f694e1543582349fb5f4076f6cb5dc36485/cryptography-50.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87f62a3d3b9888ed0fdde100ec06aa61ca9cd44bad9057d1dff9a516b5f5bb9", size = 4878208, upload-time = "2026-07-31T14:24:45.522Z" }, + { url = "https://files.pythonhosted.org/packages/d2/1a/efcfb02f91407149a0dacffffab791f7e19bf6385f63b3666dc8b5e5c9c8/cryptography-50.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:65c2c3add92b45fd0709db8594536aea39c2a67af0e27ffcf049c498501140b7", size = 5037050, upload-time = "2026-07-31T14:24:47.697Z" }, + { url = "https://files.pythonhosted.org/packages/57/30/4a22984d4f1bdfb8c054f07a92bc176b97a3134cc1d6c4b3bffb1f3688b4/cryptography-50.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:d24fead1d4d076e1bfb006dcec392074a3cd8d7b4fc8a595aa64073b2b7a96ba", size = 3874135, upload-time = "2026-07-31T14:24:50.085Z" }, +] + +[[package]] +name = "datasets" +version = "5.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dill" }, + { name = "filelock" }, + { name = "fsspec", extra = ["http"] }, + { name = "httpx" }, + { name = "huggingface-hub" }, + { name = "multiprocess" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pandas" }, + { name = "pyarrow" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "tqdm" }, + { name = "xxhash" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0a/5b/836516269d4f618efe621661cfb6f9acc57e6f95265db3efaee48a5ffe04/datasets-5.0.1.tar.gz", hash = "sha256:ce22bb851efd7494f08aad33b940803784434f6e77763d00679a0dc45fcf686a", size = 641498, upload-time = "2026-07-28T11:09:12.016Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/0b/98fc6eb83333508ca5f44c52b3e287ea8137a0ad582714e2cbc67a02154b/datasets-5.0.1-py3-none-any.whl", hash = "sha256:9fbf73688f8c18f7529b4fe592abd04015f81d1e58001e4bac73ffb2b39d7cc4", size = 559079, upload-time = "2026-07-28T11:09:10.266Z" }, +] + +[[package]] +name = "dill" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/81/e1/56027a71e31b02ddc53c7d65b01e68edf64dea2932122fe7746a516f75d5/dill-0.4.1.tar.gz", hash = "sha256:423092df4182177d4d8ba8290c8a5b640c66ab35ec7da59ccfa00f6fa3eea5fa", size = 187315, upload-time = "2026-01-19T02:36:56.85Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl", hash = "sha256:1e1ce33e978ae97fcfcff5638477032b801c46c7c65cf717f95fbc2248f79a9d", size = 120019, upload-time = "2026-01-19T02:36:55.663Z" }, +] + +[[package]] +name = "distro" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, +] + +[[package]] +name = "docstring-parser" +version = "0.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/4d/f332313098c1de1b2d2ff91cf2674415cc7cddab2ca1b01ae29774bd5fdf/docstring_parser-0.18.0.tar.gz", hash = "sha256:292510982205c12b1248696f44959db3cdd1740237a968ea1e2e7a900eeb2015", size = 29341, upload-time = "2026-04-14T04:09:19.867Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl", hash = "sha256:b3fcbed555c47d8479be0796ef7e19c2670d428d72e96da63f3a40122860374b", size = 22484, upload-time = "2026-04-14T04:09:18.638Z" }, +] + +[[package]] +name = "filelock" +version = "3.32.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/57/3ba6e6cb097f85b855b00163d169f35365f44277df044dcf96d55b8f62a3/filelock-3.32.2.tar.gz", hash = "sha256:c33351e1f49cae33414acbc6d56784e6ecee82514ec90795da1161fc4836b5b8", size = 217172, upload-time = "2026-07-29T22:46:04.895Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/e8/72f8cef9fdfeffe06213fe8508039396ee48daa0e3259457ed766173bfd6/filelock-3.32.2-py3-none-any.whl", hash = "sha256:87dd94cf281e586d135fa51132b8e3d9a598b316e90377a288663c9321036c82", size = 98830, upload-time = "2026-07-29T22:46:03.52Z" }, +] + +[[package]] +name = "frozenlist" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/29/948b9aa87e75820a38650af445d2ef2b6b8a6fab1a23b6bb9e4ef0be2d59/frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1", size = 87782, upload-time = "2025-10-06T05:36:06.649Z" }, + { url = "https://files.pythonhosted.org/packages/64/80/4f6e318ee2a7c0750ed724fa33a4bdf1eacdc5a39a7a24e818a773cd91af/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b", size = 50594, upload-time = "2025-10-06T05:36:07.69Z" }, + { url = "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4", size = 50448, upload-time = "2025-10-06T05:36:08.78Z" }, + { url = "https://files.pythonhosted.org/packages/6a/bd/d91c5e39f490a49df14320f4e8c80161cfcce09f1e2cde1edd16a551abb3/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383", size = 242411, upload-time = "2025-10-06T05:36:09.801Z" }, + { url = "https://files.pythonhosted.org/packages/8f/83/f61505a05109ef3293dfb1ff594d13d64a2324ac3482be2cedc2be818256/frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4", size = 243014, upload-time = "2025-10-06T05:36:11.394Z" }, + { url = "https://files.pythonhosted.org/packages/d8/cb/cb6c7b0f7d4023ddda30cf56b8b17494eb3a79e3fda666bf735f63118b35/frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8", size = 234909, upload-time = "2025-10-06T05:36:12.598Z" }, + { url = "https://files.pythonhosted.org/packages/31/c5/cd7a1f3b8b34af009fb17d4123c5a778b44ae2804e3ad6b86204255f9ec5/frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b", size = 250049, upload-time = "2025-10-06T05:36:14.065Z" }, + { url = "https://files.pythonhosted.org/packages/c0/01/2f95d3b416c584a1e7f0e1d6d31998c4a795f7544069ee2e0962a4b60740/frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52", size = 256485, upload-time = "2025-10-06T05:36:15.39Z" }, + { url = "https://files.pythonhosted.org/packages/ce/03/024bf7720b3abaebcff6d0793d73c154237b85bdf67b7ed55e5e9596dc9a/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29", size = 237619, upload-time = "2025-10-06T05:36:16.558Z" }, + { url = "https://files.pythonhosted.org/packages/69/fa/f8abdfe7d76b731f5d8bd217827cf6764d4f1d9763407e42717b4bed50a0/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3", size = 250320, upload-time = "2025-10-06T05:36:17.821Z" }, + { url = "https://files.pythonhosted.org/packages/f5/3c/b051329f718b463b22613e269ad72138cc256c540f78a6de89452803a47d/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143", size = 246820, upload-time = "2025-10-06T05:36:19.046Z" }, + { url = "https://files.pythonhosted.org/packages/0f/ae/58282e8f98e444b3f4dd42448ff36fa38bef29e40d40f330b22e7108f565/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608", size = 250518, upload-time = "2025-10-06T05:36:20.763Z" }, + { url = "https://files.pythonhosted.org/packages/8f/96/007e5944694d66123183845a106547a15944fbbb7154788cbf7272789536/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa", size = 239096, upload-time = "2025-10-06T05:36:22.129Z" }, + { url = "https://files.pythonhosted.org/packages/66/bb/852b9d6db2fa40be96f29c0d1205c306288f0684df8fd26ca1951d461a56/frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf", size = 39985, upload-time = "2025-10-06T05:36:23.661Z" }, + { url = "https://files.pythonhosted.org/packages/b8/af/38e51a553dd66eb064cdf193841f16f077585d4d28394c2fa6235cb41765/frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746", size = 44591, upload-time = "2025-10-06T05:36:24.958Z" }, + { url = "https://files.pythonhosted.org/packages/a7/06/1dc65480ab147339fecc70797e9c2f69d9cea9cf38934ce08df070fdb9cb/frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd", size = 40102, upload-time = "2025-10-06T05:36:26.333Z" }, + { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, +] + +[[package]] +name = "fsspec" +version = "2026.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/10/a1/ae4e3e5003468d6391d2c77b6fa1cd73bd5d13511d81c642d7b28ac90ed4/fsspec-2026.6.0.tar.gz", hash = "sha256:f5bac145310fe30e16e1471bd6840b2d990d609e872251d7e674241822abf01a", size = 313646, upload-time = "2026-06-16T01:57:28.105Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/22/4222d7ddf3da30f363edaa98e329c2bce6c65497c9cb2810931c8b2c0fbc/fsspec-2026.6.0-py3-none-any.whl", hash = "sha256:02e0b71817df9b2169dc30a16832045764def1191b43dcff5bb85bdee212d2a1", size = 203949, upload-time = "2026-06-16T01:57:26.358Z" }, +] + +[package.optional-dependencies] +http = [ + { name = "aiohttp" }, +] + +[[package]] +name = "gepa" +version = "0.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/95/56/925779e5690971f1b022f7d107caf015c33ec09560261273ec137e23a8f2/gepa-0.1.4.tar.gz", hash = "sha256:6dd153a676ae5481764860d19286a9c0e8ddb5ef70d7f13044faf24978bdb6b8", size = 351343, upload-time = "2026-07-15T14:53:59.929Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/77/5b3a281cfd9caaa9e68349b434cf27f1ca448003ee0067a1ae2184dc52d1/gepa-0.1.4-py3-none-any.whl", hash = "sha256:12b971039599625c156d2231f6d72a29c31a22e9c237689459b5f1a3c353f532", size = 290167, upload-time = "2026-07-15T14:53:58.422Z" }, +] + +[[package]] +name = "griffelib" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/33/e4/8d187ea29c2e30b3a09505c567513077d6117861bde1fbd997a167f262ec/griffelib-2.1.0.tar.gz", hash = "sha256:762a186d2c6fd6794d4ea20d428d597ffb857cb56b66421651cbba15bdd5e813", size = 216234, upload-time = "2026-06-19T12:05:42.278Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/d3/5268aeabf2ad82658c4e2ff3a060648d0f02f3926cb53247c0e4d0dab49e/griffelib-2.1.0-py3-none-any.whl", hash = "sha256:cc7b3d2d2865ad0b909fcc38086e3f554b5ea7acbaa7bbb7ecaa3f5dfb7d9f00", size = 142560, upload-time = "2026-06-19T12:05:38.742Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "hf-xet" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/ab/522a2ab67f27971a9d48ca666d4fca85ef7d5282d142e31fd087e27b1bbe/hf_xet-1.6.0.tar.gz", hash = "sha256:2e58454a340b3556dfa4972d5451aff4fba8dd42a236600ba1a1d2b1514f0fef", size = 920527, upload-time = "2026-08-03T22:33:13.243Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/50/7afa2c9c787405864fc47a0d1bbc02c62e9101947ed43c1f43899fc7d91d/hf_xet-1.6.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:633dc0cd71d32da58ab8c03ad38e2fac452c15c2b0a2866ebf6ededfe0a5061d", size = 4071729, upload-time = "2026-08-03T22:33:00.721Z" }, + { url = "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:f0906082d9932ae0c0057fa194041c22b4e2cdb46b2592ef3b91f020d62a081a", size = 3876287, upload-time = "2026-08-03T22:33:02.251Z" }, + { url = "https://files.pythonhosted.org/packages/67/4e/a28359bf1c1ecf11eba22123168c138698f7cb576ac678f5a2e16cd5da08/hf_xet-1.6.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d62671bb130879cef0ee4c9ebe47a14af6c66ec53e6d84dc15936e5ffdfac82f", size = 4464663, upload-time = "2026-08-03T22:33:03.802Z" }, + { url = "https://files.pythonhosted.org/packages/9a/69/1f0cbc2fb22ae6082d094f743d1b8945a3f36f6089cb95f42b7ee348cda7/hf_xet-1.6.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:0e6e21fa3cdfcdcd76748564bf593870a5e013f47d97cf10aed63aa222cff5b7", size = 4262538, upload-time = "2026-08-03T22:33:05.287Z" }, + { url = "https://files.pythonhosted.org/packages/d1/3a/4f4f2301ade26e404462d3336fa11f7958d914cabbabdd6e03c3c5d5658c/hf_xet-1.6.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4fc74352a17015bd0ee90038bc9efe38db894cde45f268b6712b04fce8cd0acb", size = 4460520, upload-time = "2026-08-03T22:33:06.81Z" }, + { url = "https://files.pythonhosted.org/packages/ab/5f/311725e2a905534dfee2dcb5b08414f249147f1f12252bfc2bd24caa075c/hf_xet-1.6.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8fb4f71cba6129110c3374a33f919001ff130488fc23553698e34cc1c2a1198c", size = 4675937, upload-time = "2026-08-03T22:33:08.616Z" }, + { url = "https://files.pythonhosted.org/packages/98/b7/8c59a66d15205024662f1d66968136f13893f96df1ddc5087e2e281fc95f/hf_xet-1.6.0-cp38-abi3-win_amd64.whl", hash = "sha256:fb4fadde1b2b70bf4c0c14a6dccbe7194b1c28947fefd5bbe3fed9d940676c3b", size = 4033128, upload-time = "2026-08-03T22:33:10.171Z" }, + { url = "https://files.pythonhosted.org/packages/73/63/ca511b6f802f28cf3489b280fe77475bcca8de85e81a6299d7916b5b5555/hf_xet-1.6.0-cp38-abi3-win_arm64.whl", hash = "sha256:3dc3e35441ba395006af5aaacc40ef2e603c51ef46c3530b9156185f00935ea3", size = 3859359, upload-time = "2026-08-03T22:33:11.725Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "httpx-sse" +version = "0.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/4c/751061ffa58615a32c31b2d82e8482be8dd4a89154f003147acee90f2be9/httpx_sse-0.4.3.tar.gz", hash = "sha256:9b1ed0127459a66014aec3c56bebd93da3c1bc8bb6618c8082039a44889a755d", size = 15943, upload-time = "2025-10-10T21:48:22.271Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl", hash = "sha256:0ac1c9fe3c0afad2e0ebb25a934a59f4c7823b60792691f779fad2c5568830fc", size = 8960, upload-time = "2025-10-10T21:48:21.158Z" }, +] + +[[package]] +name = "huggingface-hub" +version = "1.26.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "filelock" }, + { name = "fsspec" }, + { name = "hf-xet", marker = "platform_machine == 'AMD64' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" }, + { name = "httpx" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/82/db/3582597f8be0d34bd6881365a26d390854f12893eabdd62dd36de9df5a47/huggingface_hub-1.26.0.tar.gz", hash = "sha256:c8cd4e2df1ba9402f77fce9b509ec1d52debb502551789473f34016acc14e361", size = 936665, upload-time = "2026-07-30T14:12:04.156Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/97/bb/63a644c75b545f3ff394b822e9bd1c4a9586489c618b77a4d8a44a33a23b/huggingface_hub-1.26.0-py3-none-any.whl", hash = "sha256:e8cca670caa5d8dfa7e45bf45e86b466698198cd8150c021bcdb4a86b9252364", size = 780357, upload-time = "2026-07-30T14:12:01.998Z" }, +] + +[[package]] +name = "idna" +version = "3.18" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711, upload-time = "2026-06-02T14:34:07.794Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "jiter" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/1f/10936e16d8860c70698a1aa939a46aa0224813b782bce4e000e637da0b2d/jiter-0.16.0.tar.gz", hash = "sha256:7b24c3492c5f4f84a37946ad9cf504910cf6a782d6a4e0689b6673c5894b4a1c", size = 176431, upload-time = "2026-06-29T13:05:13.657Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/2b/52ace16ed031354f0539749a49e4bf33797d82bea5137910835fa4b09793/jiter-0.16.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:67c3bc1760f8c99d805dcab4e644027142a53b1d5d861f18780ebdbd5d40b72a", size = 306943, upload-time = "2026-06-29T13:03:14.035Z" }, + { url = "https://files.pythonhosted.org/packages/94/2e/34957c2c1b661c252ba9bcc60ae0bddc27e0f7202c6073326a13c5390eec/jiter-0.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5af7780e4a26bd7d0d989592bf9ef12ebf806b74ab709223ecca37c749872ea9", size = 307779, upload-time = "2026-06-29T13:03:15.418Z" }, + { url = "https://files.pythonhosted.org/packages/88/6c/59bd309cab4460c54cf1079f3eb7fe7af6a4c895c5c957a53378693bad2b/jiter-0.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5bf78d0e05e45cfdd66558893938d59afe3d1b1a824a202039b20e607d25a72", size = 335826, upload-time = "2026-06-29T13:03:17.11Z" }, + { url = "https://files.pythonhosted.org/packages/3b/8c/f5ef7b65f0df47afa16596969defb281ebb86e96df346d62be6fd853d620/jiter-0.16.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f4444a83f946605990c98f625cdd3d2725bfb818158760c5748c653170a20e0e", size = 362573, upload-time = "2026-06-29T13:03:18.781Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0b/ace4354da061ee38844a0c27dc2c21eecd27aea119e8da324bea987522d0/jiter-0.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3a23f0e4f957e1be65752d2dfac9a5a06b1917af8dc85deb639c3b9d02e31290", size = 457979, upload-time = "2026-06-29T13:03:20.293Z" }, + { url = "https://files.pythonhosted.org/packages/55/40/c0253d3772eb9dcd8e6606ee9b2d53ec8e5b814589c47f140aa585f21eaa/jiter-0.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c22a488f7b9218e245a0025a9ba6b100e2e54700831cf4cf16833a27fba3ad01", size = 372302, upload-time = "2026-06-29T13:03:21.739Z" }, + { url = "https://files.pythonhosted.org/packages/a8/d2/4839422241aa12860ce597b20068727094ba0bc480723c74924ca5bad483/jiter-0.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46add52f4ad47a08bfb1219f3e673da972191489a33016edefdb5ea55bfa8c48", size = 343805, upload-time = "2026-06-29T13:03:23.384Z" }, + { url = "https://files.pythonhosted.org/packages/e2/59/e196888a05befdda7dbe299b722d56f2f6eec65402bc34c0a3306d595feb/jiter-0.16.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:9c8a956fd72c2cf1e730d01ea080341f13aa0a97a4a33b51abebe725b7ae9ca9", size = 351107, upload-time = "2026-06-29T13:03:24.815Z" }, + { url = "https://files.pythonhosted.org/packages/ec/74/4cd9e0fca65232136400354b630fbfcd2de634e22ccbb96567725981b548/jiter-0.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:561926e0573ffe4a32498420a76d64b16c513e1ab413b9d28158a8764ac701e5", size = 388441, upload-time = "2026-06-29T13:03:26.266Z" }, + { url = "https://files.pythonhosted.org/packages/d9/8c/554691e48bc711299c0a293dd8a6179e24b2d66a54dc295421fcf64569c0/jiter-0.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:44d019fa8cdaf89bf29c71b39e3712143fdd0ac76725c6ef954f9957a5ea8730", size = 516354, upload-time = "2026-06-29T13:03:28.02Z" }, + { url = "https://files.pythonhosted.org/packages/a4/cb/01e9d69dc2cc6759d4f91e230b34489c4fdb2518992650633f9e20bece89/jiter-0.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0df91907609837f33341b8e6fe73b95991fdaa57caf1a0fbd343dffe826f386f", size = 547880, upload-time = "2026-06-29T13:03:29.534Z" }, + { url = "https://files.pythonhosted.org/packages/79/70/2953195f1c6ad00f49fa67e13df7e60acb3dd4f387101bc15abccddd905e/jiter-0.16.0-cp312-cp312-win32.whl", hash = "sha256:51d7b836acb0108d7c77df1742332cac2a1fa04a74d6dacec46e7091f0e91274", size = 203473, upload-time = "2026-06-29T13:03:31.025Z" }, + { url = "https://files.pythonhosted.org/packages/2d/05/2909a8b10699a4d560f8c502b6b2c5f3991b682b1922c1eedda242b225bd/jiter-0.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:1878349266f8ee36ecb1375cc5ba2f115f35fd9f0a1a4119e725e379126647f7", size = 196905, upload-time = "2026-06-29T13:03:32.472Z" }, + { url = "https://files.pythonhosted.org/packages/e9/a9/6b82bb1c8d7790d602489b967b982a909e5d092875a6c2ade96444c8dfc5/jiter-0.16.0-cp312-cp312-win_arm64.whl", hash = "sha256:2ed5738ae4af18271a51a528b8811b0cbfa4a1858de9d83359e4169855d6a331", size = 190618, upload-time = "2026-06-29T13:03:34.672Z" }, + { url = "https://files.pythonhosted.org/packages/98/ab/664fd8c4be028b2bedd3d2ff08769c4ede23d0dbc87a77c62384a0515b5d/jiter-0.16.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:f17d61a28b4b3e0e3e2ba98490c70501403b4d196f78732439160e7fd3678127", size = 303106, upload-time = "2026-06-29T13:05:07.118Z" }, + { url = "https://files.pythonhosted.org/packages/1a/07/421f1d5b65493a76e16027b848aba6a7d28073ae75944fa4289cc914d39f/jiter-0.16.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:96e38eea538c8ddf853a35727c7be0741c76c13f04148ac5c116222f50ece3b3", size = 304658, upload-time = "2026-06-29T13:05:08.708Z" }, + { url = "https://files.pythonhosted.org/packages/0a/db/bba1155f01a01c3c37a89425d571da751bbedf5c54247b831a04cb971798/jiter-0.16.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d284fb8d94d5855d60c44fefcab4bf966f1da6fada73992b01f6f0c9bc0c6702", size = 339719, upload-time = "2026-06-29T13:05:10.41Z" }, + { url = "https://files.pythonhosted.org/packages/78/f7/18a1afcd64f35314b68c1f23afcd9994d0bc13e65cc77517afff4e83986d/jiter-0.16.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64d613743df53199b1aa256a7d328340da6d7078aac7705a7db9d7a791e9cfd2", size = 343885, upload-time = "2026-06-29T13:05:12.087Z" }, +] + +[[package]] +name = "jsonschema" +version = "4.26.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload-time = "2026-01-07T13:41:05.306Z" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2025.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, +] + +[[package]] +name = "latex2sympy2-extended" +version = "1.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "antlr4-python3-runtime" }, + { name = "sympy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/30/75/456da2da05f6380ea96e6ea804ab2c03e41fc3ed80052307fe8efe6ea20e/latex2sympy2_extended-1.11.0.tar.gz", hash = "sha256:9695657c81b50abba2636638638618db59f4663ed2a4a12d62cef74a40e28fec", size = 207023, upload-time = "2026-01-10T01:43:21.319Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/61/f75cd1fa54d8434276126034aed54dd120747de9a8fa013cdd79545ccbeb/latex2sympy2_extended-1.11.0-py3-none-any.whl", hash = "sha256:aebb77d52ce269e25028e4bea89ddb14d242ba36bcf7b636496fb5fd9728d234", size = 209050, upload-time = "2026-01-10T01:43:19.458Z" }, +] + +[[package]] +name = "loguru" +version = "0.7.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "win32-setctime", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3a/05/a1dae3dffd1116099471c643b8924f5aa6524411dc6c63fdae648c4f1aca/loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6", size = 63559, upload-time = "2024-12-06T11:20:56.608Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c", size = 61595, upload-time = "2024-12-06T11:20:54.538Z" }, +] + +[[package]] +name = "markdown-it-py" +version = "4.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687, upload-time = "2026-05-07T12:08:27.182Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, +] + +[[package]] +name = "math-verify" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "latex2sympy2-extended" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4f/12/b8d13b581e110ac2f724a2351a8361a70fa36d057eb945d6379e8747c256/math_verify-0.9.0.tar.gz", hash = "sha256:45ac6c61344ba056b9e99a660a4bc8d044ed408f730aed68c60435aa5eec4645", size = 60329, upload-time = "2026-01-10T01:48:33.056Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/76/6b4969bccc842b6567f7e6ee015684b9428a9b7fcbdf479e73716f43597f/math_verify-0.9.0-py3-none-any.whl", hash = "sha256:3703e7c4885354027fa84409d762a596a2906d1fd4deb78361876bd905a76194", size = 29967, upload-time = "2026-01-10T01:48:31.674Z" }, +] + +[[package]] +name = "mcp" +version = "1.29.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "httpx" }, + { name = "httpx-sse" }, + { name = "jsonschema" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "pyjwt", extra = ["crypto"] }, + { name = "python-multipart" }, + { name = "pywin32", marker = "sys_platform == 'win32'" }, + { name = "sse-starlette" }, + { name = "starlette" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, + { name = "uvicorn", marker = "sys_platform != 'emscripten'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/30/d3/f9acc21dfc886e4f78e2add1a47db46ce16884346afde53f8a064c02c891/mcp-1.29.0.tar.gz", hash = "sha256:52d01f334de1868cc3bb2d6604931126a67631f99a6c5d3b82ba47290315ec36", size = 643148, upload-time = "2026-07-28T13:41:41.939Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl", hash = "sha256:f5a075bb611f23d6f4d080c6a1699fa62772eebc562ba9e66b306ddde1c755f7", size = 223436, upload-time = "2026-07-28T13:41:40.337Z" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + +[[package]] +name = "mpmath" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, +] + +[[package]] +name = "msgpack" +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/31/f9/c0a1c127f9049db9155afc316952ea571720dd01833ff5e4d7e8e6352dbb/msgpack-1.2.1.tar.gz", hash = "sha256:04c721c2c7448767e9e3f2520a475663d8ee0f09c31890f6d2bd70fd636a9647", size = 183960, upload-time = "2026-06-18T16:13:52.594Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/dd/9e8cbd8f5582ca4b590336f2b91ee5662f6a6ca562b565abaf696a0f81ff/msgpack-1.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2ef59c659f289eddf8aa6623823f19fa2f40a4029266889eac7a2505dd210c35", size = 83531, upload-time = "2026-06-18T16:12:58.249Z" }, + { url = "https://files.pythonhosted.org/packages/50/2e/ebdb85a8da151397a2790363676b7ed7c125924fe618e4c6d8befb0cc62c/msgpack-1.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d3567748a5107cb40cdf66a275430c2f87c07777698f4bfd25c35f44d533258c", size = 82657, upload-time = "2026-06-18T16:12:59.396Z" }, + { url = "https://files.pythonhosted.org/packages/26/aa/753ad8b007b464e1d8aa0c8e650b9c5f4f725e658fc5ac8a7635c55b7f6e/msgpack-1.2.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60926b75d00c8e816ef98f3034f484a8bc64242d66839cef4cf7e503142316a0", size = 410634, upload-time = "2026-06-18T16:13:00.383Z" }, + { url = "https://files.pythonhosted.org/packages/6a/fd/6adabd4f6d5e686f97dd02ce7fce3fe4cf672cbac36b8f67ff4040e8ad8b/msgpack-1.2.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:020e881a764b20d8d7ca1a54fc01b8175519d108e3c3f194fddc200bda95951a", size = 419989, upload-time = "2026-06-18T16:13:01.776Z" }, + { url = "https://files.pythonhosted.org/packages/5a/cc/85039b7b0eb168aaad7383a23c97e291a11f08351cb45a606ce865e4e3f1/msgpack-1.2.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4202c74688ca06591f78cb18988228bd4cca2cc75d57b60008372892d2f1e6e6", size = 377544, upload-time = "2026-06-18T16:13:03.637Z" }, + { url = "https://files.pythonhosted.org/packages/ed/bf/35963899493b32030c85fc513b723ae66144ac70c11ebc52e889e16e3d99/msgpack-1.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8b267ce94efb76fbd1b3373511420074ee3187f0f7811bf394531de13294735a", size = 400842, upload-time = "2026-06-18T16:13:05.012Z" }, + { url = "https://files.pythonhosted.org/packages/a6/df/8e2ac970c8f99264cd9997d1c73df5466bc19da3301d7dc5500862a9b089/msgpack-1.2.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e4f1d0f8f98ade9634e01fb704a408f9336c0a8f1117b369f5db83dc7551d8b1", size = 374108, upload-time = "2026-06-18T16:13:06.232Z" }, + { url = "https://files.pythonhosted.org/packages/17/dd/fa8bd265110dfa51c20cb529f9e6d240a16fafe7e645004c6af2d01353ba/msgpack-1.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f02cf17a6ca1abe29b5f980644f7551f94d71f2011509b26d8625ce038f0df64", size = 414939, upload-time = "2026-06-18T16:13:07.478Z" }, + { url = "https://files.pythonhosted.org/packages/2e/b9/8377a5ad8953fc0437c70cc98d9ae29f27fe5ac5109fbec0812085865735/msgpack-1.2.1-cp312-cp312-win32.whl", hash = "sha256:0c0d9802354507bcba62af19c17918e3eb437cc25e6f50657d511b5856a77aac", size = 64504, upload-time = "2026-06-18T16:13:08.822Z" }, + { url = "https://files.pythonhosted.org/packages/57/7f/ce1e377df7e62461fefd9eb23bfb93a4a523f40a517b377b8f844d836828/msgpack-1.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:5c24aa15d5963051e1a5c62b12c50cd705992502b5ec1f3bece6046f33c9fc24", size = 71421, upload-time = "2026-06-18T16:13:09.828Z" }, + { url = "https://files.pythonhosted.org/packages/8f/32/ebfe84c9929f08f188d56c7a2fd913406a9ddad76a634697c1c43b8112e6/msgpack-1.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:4227224aaec8f7fbcbfbd4272319347b2bb4030366502600f8c45588c5187b07", size = 64775, upload-time = "2026-06-18T16:13:11.056Z" }, +] + +[[package]] +name = "multidict" +version = "6.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010, upload-time = "2026-01-26T02:46:45.979Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/9c/f20e0e2cf80e4b2e4b1c365bf5fe104ee633c751a724246262db8f1a0b13/multidict-6.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a90f75c956e32891a4eda3639ce6dd86e87105271f43d43442a3aedf3cddf172", size = 76893, upload-time = "2026-01-26T02:43:52.754Z" }, + { url = "https://files.pythonhosted.org/packages/fe/cf/18ef143a81610136d3da8193da9d80bfe1cb548a1e2d1c775f26b23d024a/multidict-6.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fccb473e87eaa1382689053e4a4618e7ba7b9b9b8d6adf2027ee474597128cd", size = 45456, upload-time = "2026-01-26T02:43:53.893Z" }, + { url = "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0fa96985700739c4c7853a43c0b3e169360d6855780021bfc6d0f1ce7c123e7", size = 43872, upload-time = "2026-01-26T02:43:55.041Z" }, + { url = "https://files.pythonhosted.org/packages/cf/3b/d6bd75dc4f3ff7c73766e04e705b00ed6dbbaccf670d9e05a12b006f5a21/multidict-6.7.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cb2a55f408c3043e42b40cc8eecd575afa27b7e0b956dfb190de0f8499a57a53", size = 251018, upload-time = "2026-01-26T02:43:56.198Z" }, + { url = "https://files.pythonhosted.org/packages/fd/80/c959c5933adedb9ac15152e4067c702a808ea183a8b64cf8f31af8ad3155/multidict-6.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb0ce7b2a32d09892b3dd6cc44877a0d02a33241fafca5f25c8b6b62374f8b75", size = 258883, upload-time = "2026-01-26T02:43:57.499Z" }, + { url = "https://files.pythonhosted.org/packages/86/85/7ed40adafea3d4f1c8b916e3b5cc3a8e07dfcdcb9cd72800f4ed3ca1b387/multidict-6.7.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c3a32d23520ee37bf327d1e1a656fec76a2edd5c038bf43eddfa0572ec49c60b", size = 242413, upload-time = "2026-01-26T02:43:58.755Z" }, + { url = "https://files.pythonhosted.org/packages/d2/57/b8565ff533e48595503c785f8361ff9a4fde4d67de25c207cd0ba3befd03/multidict-6.7.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9c90fed18bffc0189ba814749fdcc102b536e83a9f738a9003e569acd540a733", size = 268404, upload-time = "2026-01-26T02:44:00.216Z" }, + { url = "https://files.pythonhosted.org/packages/e0/50/9810c5c29350f7258180dfdcb2e52783a0632862eb334c4896ac717cebcb/multidict-6.7.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:da62917e6076f512daccfbbde27f46fed1c98fee202f0559adec8ee0de67f71a", size = 269456, upload-time = "2026-01-26T02:44:02.202Z" }, + { url = "https://files.pythonhosted.org/packages/f3/8d/5e5be3ced1d12966fefb5c4ea3b2a5b480afcea36406559442c6e31d4a48/multidict-6.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde23ef6ed9db7eaee6c37dcec08524cb43903c60b285b172b6c094711b3961", size = 256322, upload-time = "2026-01-26T02:44:03.56Z" }, + { url = "https://files.pythonhosted.org/packages/31/6e/d8a26d81ac166a5592782d208dd90dfdc0a7a218adaa52b45a672b46c122/multidict-6.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3758692429e4e32f1ba0df23219cd0b4fc0a52f476726fff9337d1a57676a582", size = 253955, upload-time = "2026-01-26T02:44:04.845Z" }, + { url = "https://files.pythonhosted.org/packages/59/4c/7c672c8aad41534ba619bcd4ade7a0dc87ed6b8b5c06149b85d3dd03f0cd/multidict-6.7.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:398c1478926eca669f2fd6a5856b6de9c0acf23a2cb59a14c0ba5844fa38077e", size = 251254, upload-time = "2026-01-26T02:44:06.133Z" }, + { url = "https://files.pythonhosted.org/packages/7b/bd/84c24de512cbafbdbc39439f74e967f19570ce7924e3007174a29c348916/multidict-6.7.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c102791b1c4f3ab36ce4101154549105a53dc828f016356b3e3bcae2e3a039d3", size = 252059, upload-time = "2026-01-26T02:44:07.518Z" }, + { url = "https://files.pythonhosted.org/packages/fa/ba/f5449385510825b73d01c2d4087bf6d2fccc20a2d42ac34df93191d3dd03/multidict-6.7.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a088b62bd733e2ad12c50dad01b7d0166c30287c166e137433d3b410add807a6", size = 263588, upload-time = "2026-01-26T02:44:09.382Z" }, + { url = "https://files.pythonhosted.org/packages/d7/11/afc7c677f68f75c84a69fe37184f0f82fce13ce4b92f49f3db280b7e92b3/multidict-6.7.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3d51ff4785d58d3f6c91bdbffcb5e1f7ddfda557727043aa20d20ec4f65e324a", size = 259642, upload-time = "2026-01-26T02:44:10.73Z" }, + { url = "https://files.pythonhosted.org/packages/2b/17/ebb9644da78c4ab36403739e0e6e0e30ebb135b9caf3440825001a0bddcb/multidict-6.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc5907494fccf3e7d3f94f95c91d6336b092b5fc83811720fae5e2765890dfba", size = 251377, upload-time = "2026-01-26T02:44:12.042Z" }, + { url = "https://files.pythonhosted.org/packages/ca/a4/840f5b97339e27846c46307f2530a2805d9d537d8b8bd416af031cad7fa0/multidict-6.7.1-cp312-cp312-win32.whl", hash = "sha256:28ca5ce2fd9716631133d0e9a9b9a745ad7f60bac2bccafb56aa380fc0b6c511", size = 41887, upload-time = "2026-01-26T02:44:14.245Z" }, + { url = "https://files.pythonhosted.org/packages/80/31/0b2517913687895f5904325c2069d6a3b78f66cc641a86a2baf75a05dcbb/multidict-6.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcee94dfbd638784645b066074b338bc9cc155d4b4bffa4adce1615c5a426c19", size = 46053, upload-time = "2026-01-26T02:44:15.371Z" }, + { url = "https://files.pythonhosted.org/packages/0c/5b/aba28e4ee4006ae4c7df8d327d31025d760ffa992ea23812a601d226e682/multidict-6.7.1-cp312-cp312-win_arm64.whl", hash = "sha256:ba0a9fb644d0c1a2194cf7ffb043bd852cea63a57f66fbd33959f7dae18517bf", size = 43307, upload-time = "2026-01-26T02:44:16.852Z" }, + { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" }, +] + +[[package]] +name = "multiprocess" +version = "0.70.19" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dill" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a2/f2/e783ac7f2aeeed14e9e12801f22529cc7e6b7ab80928d6dcce4e9f00922d/multiprocess-0.70.19.tar.gz", hash = "sha256:952021e0e6c55a4a9fe4cd787895b86e239a40e76802a789d6305398d3975897", size = 2079989, upload-time = "2026-01-19T06:47:39.744Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/45/8004d1e6b9185c1a444d6b55ac5682acf9d98035e54386d967366035a03a/multiprocess-0.70.19-py310-none-any.whl", hash = "sha256:97404393419dcb2a8385910864eedf47a3cadf82c66345b44f036420eb0b5d87", size = 134948, upload-time = "2026-01-19T06:47:32.325Z" }, + { url = "https://files.pythonhosted.org/packages/86/c2/dec9722dc3474c164a0b6bcd9a7ed7da542c98af8cabce05374abab35edd/multiprocess-0.70.19-py311-none-any.whl", hash = "sha256:928851ae7973aea4ce0eaf330bbdafb2e01398a91518d5c8818802845564f45c", size = 144457, upload-time = "2026-01-19T06:47:33.711Z" }, + { url = "https://files.pythonhosted.org/packages/71/70/38998b950a97ea279e6bd657575d22d1a2047256caf707d9a10fbce4f065/multiprocess-0.70.19-py312-none-any.whl", hash = "sha256:3a56c0e85dd5025161bac5ce138dcac1e49174c7d8e74596537e729fd5c53c28", size = 150281, upload-time = "2026-01-19T06:47:35.037Z" }, + { url = "https://files.pythonhosted.org/packages/7e/82/69e539c4c2027f1e1697e09aaa2449243085a0edf81ae2c6341e84d769b6/multiprocess-0.70.19-py39-none-any.whl", hash = "sha256:0d4b4397ed669d371c81dcd1ef33fd384a44d6c3de1bd0ca7ac06d837720d3c5", size = 133477, upload-time = "2026-01-19T06:47:38.619Z" }, +] + +[[package]] +name = "numpy" +version = "2.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/22/fd/89965aa4ac08c74998539fcbf24fa3540f3e15237fbeb6bcf9c908f4aade/numpy-2.5.1.tar.gz", hash = "sha256:a48a113e6afea91f5608793bafa7ef2ad481fefbda87ec5069f483de61cb9fa3", size = 20755553, upload-time = "2026-07-04T17:08:00.933Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/7b/14687aa674250e5e546f616f486b0d56d3631cd5b2415739141ce40bdcea/numpy-2.5.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2c889b56fe48b1018f764b0eec8df59ab654e9148aa91faa12596043500de277", size = 16801574, upload-time = "2026-07-04T17:06:12.423Z" }, + { url = "https://files.pythonhosted.org/packages/e1/19/cc5bb2a3f2913d27d6dbb2c78d25921fabaedc6741d4a5a615a11f3c5bf3/numpy-2.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ab451b59c5643c570974c43aef780703ef1d3b4965d2be07afd530615a9358d1", size = 11772250, upload-time = "2026-07-04T17:06:15.726Z" }, + { url = "https://files.pythonhosted.org/packages/42/77/fdf34a71dd30f54979b18603bee915e0aaf825b07afe79acd60b04b691e2/numpy-2.5.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:78798bd5b9ad744056af8efa90e3b9ddaa53272a0848a483084a1cc0a13b2dc0", size = 5331516, upload-time = "2026-07-04T17:06:17.913Z" }, + { url = "https://files.pythonhosted.org/packages/ce/e2/eb7efa015b4cce41e2517bf182a7fce0d7d5b9d9ed76a29bfa0f4fe4505c/numpy-2.5.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:2ae0ca40bcb22d6ba59c1dfd5446f49940b0f2d821fde133f10dda11f816b84e", size = 6664863, upload-time = "2026-07-04T17:06:20.02Z" }, + { url = "https://files.pythonhosted.org/packages/a9/4b/a2b32dd94ee9ffbeecb28152240042a3949db33b1c834d44090b80e1b3b8/numpy-2.5.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:61ac47e772e6b8ea489e1d2f441a34c5c3ac17327e7ce294cbdf535795ad4e75", size = 15167977, upload-time = "2026-07-04T17:06:21.621Z" }, + { url = "https://files.pythonhosted.org/packages/b8/a9/6e73d68500f80773f65f0654ea932019d6694329a0eb0ed0533de38df376/numpy-2.5.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:59fda5e192b570217ec2580c96f00e9a7e12ef6866a900eb089b62c1a32545ca", size = 16672469, upload-time = "2026-07-04T17:06:24.064Z" }, + { url = "https://files.pythonhosted.org/packages/24/7d/ad3e59015135f5261c95fd4cafeff159c955febd83a99a1d9250c4233815/numpy-2.5.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f7119ebff1a9829e9f431a4f9d28e703023bb6b9fe7c8f724467dbfc27c94ab3", size = 16527531, upload-time = "2026-07-04T17:06:26.69Z" }, + { url = "https://files.pythonhosted.org/packages/83/d0/a39b2fbcde9cb17a1dac678f254b33a6336298af9df338824c685425d5e8/numpy-2.5.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e824c2acf8862052246be5a44c15da1777940c60d010dd2aab897824d9c430f9", size = 18431940, upload-time = "2026-07-04T17:06:29.521Z" }, + { url = "https://files.pythonhosted.org/packages/04/12/cff070947791c1ed425ff76413189adbdc2fbe215eba7ce7fa454a03c7f8/numpy-2.5.1-cp312-cp312-win32.whl", hash = "sha256:08d60c810432eb83360958dea0999ac4cfb94531ea8efcbf0b7f277c2068aeb2", size = 6066764, upload-time = "2026-07-04T17:06:32.571Z" }, + { url = "https://files.pythonhosted.org/packages/65/66/53f31807a48a750f9d748da273bc3fcedd12b27ff1f3e373bfec55ef2dc0/numpy-2.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:f7d60026c0bdb1380e83bfa7a0419c4577ee4b9a08880afcb6dadeb74c649fa2", size = 12430966, upload-time = "2026-07-04T17:06:34.926Z" }, + { url = "https://files.pythonhosted.org/packages/2b/2a/d1a88066b1c14186f5d3c0d18c94f17b064511982bab0578d49ee9d43c29/numpy-2.5.1-cp312-cp312-win_arm64.whl", hash = "sha256:17a25e09640602e10bc8de0e6fa2b3fd68eedd84ba6d7842dc8f32f9ab87bd0b", size = 10350488, upload-time = "2026-07-04T17:06:37.785Z" }, +] + +[[package]] +name = "openai" +version = "2.53.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "httpx" }, + { name = "jiter" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/cf/36e3e7235fdf6d125c052acc0970924611b17a20a4fe580596faf4566a65/openai-2.53.0.tar.gz", hash = "sha256:baf5802ad08980e1d9d561e1b996e800c8bcd14af5847c6d0e7a5cc59e4d4116", size = 1099435, upload-time = "2026-08-03T21:42:01.664Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/0f/cc6afea3542a5142c5d8fc8211c5e059a8375105d004a41dfa2c7948dbb0/openai-2.53.0-py3-none-any.whl", hash = "sha256:c694ffc747a3c4d1663ef2b07b811315a476164ee5efa3a993967349ebca7618", size = 1659829, upload-time = "2026-08-03T21:41:59.581Z" }, +] + +[[package]] +name = "openai-agents" +version = "0.19.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "griffelib" }, + { name = "mcp" }, + { name = "openai" }, + { name = "pydantic" }, + { name = "requests" }, + { name = "typing-extensions" }, + { name = "websockets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bf/ae/0424f85df059ae94f6bad55dcd3841177ddb8b40c15cd1e236e422c4b1bd/openai_agents-0.19.3.tar.gz", hash = "sha256:738a05c20d1d3f985e4f0fb28f155513829fb3fef636108b6a770bde136b1cb1", size = 5752641, upload-time = "2026-08-04T07:18:31.805Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/56/fc626c963029ffbba70c05090a6cb5be830bd6afc35eb527f579f5d80145/openai_agents-0.19.3-py3-none-any.whl", hash = "sha256:f86c3a8fff9e2cf50ebdc17dfd656bbdfb9c8ed465041185439244f27cd358d7", size = 962587, upload-time = "2026-08-04T07:18:29.149Z" }, +] + +[[package]] +name = "openai-harmony" +version = "0.0.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3e/92/2d038d096f29179c7c9571b431f9e739f87a487121901725e23fe338dd9d/openai_harmony-0.0.8.tar.gz", hash = "sha256:6e43f98e6c242fa2de6f8ea12eab24af63fa2ed3e89c06341fb9d92632c5cbdf", size = 284777, upload-time = "2025-11-05T19:07:06.727Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/c6/2502f416d46be3ec08bb66d696cccffb57781a499e3ff2e4d7c174af4e8f/openai_harmony-0.0.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:029ec25ca74abe48fdb58eb9fdd2a8c1618581fc33ce8e5653f8a1ffbfbd9326", size = 2627806, upload-time = "2025-11-05T19:06:57.063Z" }, + { url = "https://files.pythonhosted.org/packages/d3/d2/ce6953ca87db9cae3e775024184da7d1c5cb88cead19a2d75b42f00a959c/openai_harmony-0.0.8-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4f709815924ec325b9a890e6ab2bbb0ceec8e319a4e257328eb752cf36b2efc", size = 2948463, upload-time = "2025-11-05T19:06:48.17Z" }, + { url = "https://files.pythonhosted.org/packages/fa/4c/b553c9651662d6ce102ca7f3629d268b23df1abe5841e24bed81e8a8e949/openai_harmony-0.0.8-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5cfcfd963b50a41fc656c84d3440ca6eecdccd6c552158ce790b8f2e33dfb5a9", size = 2704083, upload-time = "2025-11-05T19:06:50.205Z" }, + { url = "https://files.pythonhosted.org/packages/9b/af/4eec8f9ab9c27bcdb444460c72cf43011d176fc44c79d6e113094ca1e152/openai_harmony-0.0.8-cp38-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a3a16972aa1cee38ea958470cd04ac9a2d5ac38fdcf77ab686611246220c158", size = 2959765, upload-time = "2025-11-05T19:06:53.62Z" }, + { url = "https://files.pythonhosted.org/packages/11/3c/33f3374e4624e0e776f6b13b73c45a7ead7f9c4529f8369ed5bfcaa30cac/openai_harmony-0.0.8-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4d5cfa168e74d08f8ba6d58a7e49bc7daef4d58951ec69b66b0d56f4927a68d", size = 3427031, upload-time = "2025-11-05T19:06:51.829Z" }, + { url = "https://files.pythonhosted.org/packages/25/3f/1a192b93bb47c6b44cd98ba8cc1d3d2a9308f1bb700c3017e6352da11bda/openai_harmony-0.0.8-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c007d277218a50db8839e599ed78e0fffe5130f614c3f6d93ae257f282071a29", size = 2953260, upload-time = "2025-11-05T19:06:55.406Z" }, + { url = "https://files.pythonhosted.org/packages/5b/f8/93b582cad3531797c3db7c2db5400fd841538ccddfd9f5e3df61be99a630/openai_harmony-0.0.8-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:8565d4f5a0638da1bffde29832ed63c9e695c558611053add3b2dc0b56c92dbc", size = 3127044, upload-time = "2025-11-05T19:06:59.553Z" }, + { url = "https://files.pythonhosted.org/packages/1d/10/4327dbf87f75ae813405fd9a9b4a5cde63d506ffed0a096a440a4cabd89c/openai_harmony-0.0.8-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:cbaa3bda75ef0d8836e1f8cc84af62f971b1d756d740efc95c38c3e04c0bfde2", size = 2932931, upload-time = "2025-11-05T19:07:01.437Z" }, + { url = "https://files.pythonhosted.org/packages/8a/c8/1774eec4f6f360ef57618fb8f52e3d3af245b2491bd0297513aa09eec04b/openai_harmony-0.0.8-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:772922a9bd24e133950fad71eb1550836f415a88e8c77870e12d0c3bd688ddc2", size = 2996140, upload-time = "2025-11-05T19:07:03.438Z" }, + { url = "https://files.pythonhosted.org/packages/60/c3/3d1e01e2dba517a91760e4a03e4f20ffc75039a6fe584d0e6f9b5c78fd15/openai_harmony-0.0.8-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:007b0476a1f331f8130783f901f1da6f5a7057af1a4891f1b6a31dec364189b5", size = 3205080, upload-time = "2025-11-05T19:07:05.078Z" }, + { url = "https://files.pythonhosted.org/packages/14/63/119de431572d7c70a7bf1037034a9be6ed0a7502a7498ba7302bca5b3242/openai_harmony-0.0.8-cp38-abi3-win32.whl", hash = "sha256:a9b5f893326b28d9e935ade14b4f655f5a840942473bc89b201c25f7a15af9cf", size = 2082457, upload-time = "2025-11-05T19:07:09.631Z" }, + { url = "https://files.pythonhosted.org/packages/40/1f/c83cf5a206c263ee70448a5ae4264682555f4d0b5bed0d2cc6ca1108103d/openai_harmony-0.0.8-cp38-abi3-win_amd64.whl", hash = "sha256:39d44f0d8f466bd56698e7ead708bead3141e27b9b87e3ab7d5a6d0e4a869ee5", size = 2438369, upload-time = "2025-11-05T19:07:08.1Z" }, +] + +[[package]] +name = "opentelemetry-api" +version = "1.44.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ee/8b/aa9e2d8b8dfa7c946f7dec5d1f8f6ba8eca062f43509a06bdb5ce93d26c0/opentelemetry_api-1.44.0.tar.gz", hash = "sha256:67647e5e9566edcf421166fdf022b3537f818635daa852b289e34604dc6fb33a", size = 72406, upload-time = "2026-07-16T15:25:32.678Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl", hash = "sha256:94b98c893a91b88657eaac1e3ba89618cdb85be6918196705354f34728b2cdef", size = 60018, upload-time = "2026-07-16T15:25:11.657Z" }, +] + +[[package]] +name = "packaging" +version = "26.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, +] + +[[package]] +name = "pandas" +version = "3.0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "python-dateutil" }, + { name = "tzdata", marker = "sys_platform == 'emscripten' or sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/be/4f/5f3422a2afec5ffc46308b79e53291365a93748b498ac2e58bead0197916/pandas-3.0.5.tar.gz", hash = "sha256:dca3734d6ab7c906e6730f0788b0a1dbb9f2467731f9711f77995c8e9d62d712", size = 4658219, upload-time = "2026-07-22T22:19:28.819Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1c/54/1dc810ea558d1320b597aa140a514f2fdf1d2ea09c38cf556f13ea712ec9/pandas-3.0.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fa290c16964d4963fbfbc358928239cf3bd755b20e988ce944877def2f44471d", size = 10411717, upload-time = "2026-07-22T22:18:08.307Z" }, + { url = "https://files.pythonhosted.org/packages/68/56/fbe81c09195924d8b7b8d4461a20458fe80a6a5ed6b24f0314da684277e1/pandas-3.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c2e26bb46934b8a2ca0c3de1d3d606fc5f6746584791b2db264d58cf370e08dc", size = 9957095, upload-time = "2026-07-22T22:18:10.6Z" }, + { url = "https://files.pythonhosted.org/packages/e0/51/fac252f4a913ed5eabf3c11b880a9e8d5a6c10f0b2129d0462212d238b4d/pandas-3.0.5-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:73fa87b08a7ef706f8aafda39ddaccf2a99047bea62d8c88a0361bcafb2237bc", size = 10485458, upload-time = "2026-07-22T22:18:12.834Z" }, + { url = "https://files.pythonhosted.org/packages/12/98/e976540c1addf70442be7842a18cf70884a964abbf69442504f4d2939989/pandas-3.0.5-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d373ce03ffd84010ed9839fa73672a9c8256990532e158440c0085db7d914b34", size = 10998091, upload-time = "2026-07-22T22:18:15.209Z" }, + { url = "https://files.pythonhosted.org/packages/a4/8c/1f29b5be8d3fc47dd7567eb167fabba2085879b31e0287ce7cba6d3d2ff4/pandas-3.0.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2a29c53d85ea98c5e792c59ef82ee9fbe6ca902c0d0adb6b23f45ef894cd7bf6", size = 11499501, upload-time = "2026-07-22T22:18:17.689Z" }, + { url = "https://files.pythonhosted.org/packages/9d/e2/bd9c98ad2df7b38bde002adde4cdf353519da51881634323b126c55997f9/pandas-3.0.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a5ad3b02ed6bc7d7ae9b70804b2c6aa31827489d150f8e623ce82491b82085d7", size = 12060559, upload-time = "2026-07-22T22:18:20.147Z" }, + { url = "https://files.pythonhosted.org/packages/f3/9a/ffbd852d58bd74a617fe2f8ee6a58a96982271ce41cf981eab22190b4a4b/pandas-3.0.5-cp312-cp312-pyemscripten_2024_0_wasm32.whl", hash = "sha256:b2acb4650527eec6822c3dadb2b771277b65e7dae7a267d4bccf65fd1bb3fbce", size = 7197652, upload-time = "2026-07-22T22:18:22.502Z" }, + { url = "https://files.pythonhosted.org/packages/70/b5/d2d3e9ae73362ba4229651b0ee1455cf78073a1ce585f6ff693782ce263e/pandas-3.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:80a611068e8a3ac23f7398c6c14eb46dc974e5cc9997f653e2dcfd1da74edd41", size = 9831691, upload-time = "2026-07-22T22:18:24.534Z" }, + { url = "https://files.pythonhosted.org/packages/52/51/dea1e89d6a6796b9c43f85a09b484ee03edb8a4c4842e73e200a8c11301c/pandas-3.0.5-cp312-cp312-win_arm64.whl", hash = "sha256:25ff585b972a18ef1fe9ffa3ac6544d9950508aa76832e5147640b6022821e49", size = 9105796, upload-time = "2026-07-22T22:18:27.064Z" }, +] + +[[package]] +name = "prime-pydantic-config" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3c/37/e240dd598e687af74523f4497acb122b6d484975dac35e38932b58733753/prime_pydantic_config-0.4.2.tar.gz", hash = "sha256:7e85ac624c63edc1995ef512398fa5cd4610724b48a65c595f7742b7514153a4", size = 75997, upload-time = "2026-07-20T19:39:54.631Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/f7/12d3b54d0db5812d4fb9e8b9df987f805e687df2f0d11359c2d066df513c/prime_pydantic_config-0.4.2-py3-none-any.whl", hash = "sha256:092f7da638f625747a136983b579f5c929ead1b243df22f69fad6cf16b044ab0", size = 27414, upload-time = "2026-07-20T19:39:53.716Z" }, +] + +[package.optional-dependencies] +toml = [ + { name = "tomli" }, +] + +[[package]] +name = "prime-sandboxes" +version = "0.2.34" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiofiles" }, + { name = "connect-python" }, + { name = "httpx" }, + { name = "protobuf" }, + { name = "pydantic" }, + { name = "tenacity" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d8/85/3bf9aaba1485058ea30821bc26296a0869cd8416f633b10483c8fe897dd5/prime_sandboxes-0.2.34.tar.gz", hash = "sha256:d95e0b320e372f557785d216a572a2af3287136c0e355d6a9728b242897331e7", size = 81225, upload-time = "2026-07-28T20:08:44.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/1e/79149754046add7070dbdc53242a836f6539fbc1da8bbca0c086c2998703/prime_sandboxes-0.2.34-py3-none-any.whl", hash = "sha256:75e0dccd0d310aca759d5de64ccbd732634ca267cf47a12ae0bfc01bc46bfec8", size = 42773, upload-time = "2026-07-28T20:08:42.74Z" }, +] + +[[package]] +name = "prime-tunnel" +version = "0.1.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httpx" }, + { name = "pydantic" }, + { name = "tenacity" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bf/26/7324b5b9ec117c21fc9320214bf04ecbe9144ee87ef48c7d6d6c3e3d3f7f/prime_tunnel-0.1.10.tar.gz", hash = "sha256:8bf575af659bcc107a98b0b5ec1ba3e958ea72ead535ced03c443134a1ad07ea", size = 15305, upload-time = "2026-06-17T00:01:02.392Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/b9/d767b4f6c7ce72b54aaba834b97f97c3c494f1865a37f8b5b9acfb1b2a68/prime_tunnel-0.1.10-py3-none-any.whl", hash = "sha256:6a1cb49a14cfc9622db5cae90665ebe7e7e8cd5d84e963e8c3572bce85288400", size = 16319, upload-time = "2026-06-17T00:01:01.095Z" }, +] + +[[package]] +name = "propcache" +version = "0.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/44/c87281c333769159c50594f22610f77398a47ccbfbbf23074e744e86f87c/propcache-0.5.2.tar.gz", hash = "sha256:01c4fc7480cd0598bb4b57022df55b9ca296da7fc5a8760bd8451a7e63a7d427", size = 50208, upload-time = "2026-05-08T21:02:12.199Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4a/cb/e27bc2b2737a0bb49962b275efa051e8f1c35a936df7d5139b6b658b7dc9/propcache-0.5.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:806719138ecd720339a12410fb9614ac9b2b2d3a5fdf8235d56981c36f4039ba", size = 95887, upload-time = "2026-05-08T21:00:11.277Z" }, + { url = "https://files.pythonhosted.org/packages/e6/13/b8ae04c59392f8d11c6cd9fb4011d1dc7c86b81225c770280300e259ffe1/propcache-0.5.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:db2b80ea58eab4f86b2beec3cc8b39e8ff9276ac20e96b7cce43c8ae84cd6b5a", size = 54654, upload-time = "2026-05-08T21:00:12.604Z" }, + { url = "https://files.pythonhosted.org/packages/2c/7d/49777a3e20b55863d4794384a38acd460c04157b0a00f8602b0d508b8431/propcache-0.5.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e5cbfac9f61484f7e9f3597775500cd3ebe8274e9b050c38f9525c77c97520bf", size = 55190, upload-time = "2026-05-08T21:00:13.935Z" }, + { url = "https://files.pythonhosted.org/packages/44/c7/085d0cd63062e84044e3f05797749c3f8e3938ff3aeb0eb2f69d43fafc91/propcache-0.5.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5dbc581d2814337da56222fab8dc5f161cd798a434e49bac27930aaef798e144", size = 59995, upload-time = "2026-05-08T21:00:15.526Z" }, + { url = "https://files.pythonhosted.org/packages/9c/42/32cf8e3009e92b2645cf1e944f701e8ea4e924dffde1ee26db860bcbf7e4/propcache-0.5.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:857187f381f88c8e2fa2fe56ab94879d011b883d5a2ee5a1b60a8cd2a06846d9", size = 63422, upload-time = "2026-05-08T21:00:16.824Z" }, + { url = "https://files.pythonhosted.org/packages/9e/1b/f112433f99fc979431b87a39ef169e3f8df070d99a72792c56d6937ac48b/propcache-0.5.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:178b4a2cdaac1818e2bf1c5a99b94383fa73ea5382e032a48dec07dc5668dc42", size = 64342, upload-time = "2026-05-08T21:00:18.362Z" }, + { url = "https://files.pythonhosted.org/packages/14/15/5574111ae50dd6e879456888c0eadd4c5a869959775854e18e18a6b345f3/propcache-0.5.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f328175a2cde1f0ff2c4ed8ce968b9dcfb55f3a7153f39e2957ed994da13476", size = 61639, upload-time = "2026-05-08T21:00:19.692Z" }, + { url = "https://files.pythonhosted.org/packages/cc/da/4d775080b1490c0ae604acda868bd71aabe3a89ed16f2aa4339eb8a283e7/propcache-0.5.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5671d09a36b06d0fd4a3da0fccbcae360e9b1570924171a15e9e0997f0249fba", size = 61588, upload-time = "2026-05-08T21:00:21.155Z" }, + { url = "https://files.pythonhosted.org/packages/04/ac/f076982cbe2195ee9cf32de5a1e46951d9fb399fc207f390562dd0fd8fb2/propcache-0.5.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:80168e2ebe4d3ec6599d10ad8f520304ae1cad9b6c5a95372aef1b66b7bfb53a", size = 60029, upload-time = "2026-05-08T21:00:22.713Z" }, + { url = "https://files.pythonhosted.org/packages/70/60/189be62e0dd898dce3b331e1b8c7a543cd3a405ac0c81fe8ee8a9d5d77e1/propcache-0.5.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:45f11346f884bc47444f6e6647131055844134c3175b629f84952e2b5cd62b64", size = 56774, upload-time = "2026-05-08T21:00:24.001Z" }, + { url = "https://files.pythonhosted.org/packages/ea/9e/93377b9c7939c1ffae98f878dee955efadfd638078bc86dbc21f9d52f651/propcache-0.5.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8e778ebd44ef4f66ed60a0416b06b489687db264a9c0b3620362f26489492913", size = 63532, upload-time = "2026-05-08T21:00:25.545Z" }, + { url = "https://files.pythonhosted.org/packages/14/f9/590ef6cfb9b8028d516d287812ece32bb0bc5f11fbb9c8bf6b2e6313fec8/propcache-0.5.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:c0cb9ed24c8964e172768d455a38254c2dd8a552905729ce006cad3d3dda59b1", size = 61592, upload-time = "2026-05-08T21:00:27.186Z" }, + { url = "https://files.pythonhosted.org/packages/b4/5e/70958b3034c297a630bba2f17ca7abc2d5f39a803ad7e370ab79d1ecd022/propcache-0.5.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1d1ad32d9d4355e2be65574fd0bfd3677e7066b009cd5b9b2dee8aa6a6393b33", size = 64788, upload-time = "2026-05-08T21:00:28.8Z" }, + { url = "https://files.pythonhosted.org/packages/12/fd/77fe5936d8c3086ca9048f7f415f122ed82e53884a9ec193646b42deef06/propcache-0.5.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c80f4ba3e8f00189165999a742ee526ebeccedf6c3f7beb0c7df821e9772435a", size = 62514, upload-time = "2026-05-08T21:00:30.098Z" }, + { url = "https://files.pythonhosted.org/packages/cf/74/66bd798b5b3be70aa1b391f5cc9d6a0a5532d7fd3b19ec0b213e72e6ad9d/propcache-0.5.2-cp312-cp312-win32.whl", hash = "sha256:8c7972d8f193740d9175f0998ab38717e6cd322d5935c5b0fef8c0d323fd9031", size = 39018, upload-time = "2026-05-08T21:00:31.622Z" }, + { url = "https://files.pythonhosted.org/packages/61/7c/5c0d34aa3024694d6dcb9271cdbdd08c4e47c1c0ad95ec7e7bc74cdea145/propcache-0.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:d9ee8826a7d47863a08ac44e1a5f611a462eefc3a194b492da242128bec75b42", size = 42322, upload-time = "2026-05-08T21:00:32.918Z" }, + { url = "https://files.pythonhosted.org/packages/4d/91/875812f1a3feb20ceba818ef39fbe4d92f1081e04ac815c822496d0d038b/propcache-0.5.2-cp312-cp312-win_arm64.whl", hash = "sha256:2800a4a8ead6b28cccd1ec54b59346f0def7922ee1c7598e8499c733cfbb7c84", size = 38172, upload-time = "2026-05-08T21:00:35.124Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ed/1cdcab6ba3d6ab7feca11fc14f0eeea80755bb53ef4e892079f31b10a25f/propcache-0.5.2-py3-none-any.whl", hash = "sha256:be1ddfcbb376e3de5d2e2db1d58d6d67463e6b4f9f040c000de8e300295465fe", size = 14036, upload-time = "2026-05-08T21:02:10.673Z" }, +] + +[[package]] +name = "protobuf" +version = "7.35.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/da/01/9ef0afd7999eb9badb3a768b4aedd78c86d4c65cfaf1958ab276199e76b4/protobuf-7.35.1.tar.gz", hash = "sha256:ce115a26fe0c39a2c29973d914d327e516a6455464489fe3cd1e51a1b354f81a", size = 458717, upload-time = "2026-06-11T21:55:40.257Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/03/8aeeb7458d22546bf64b5250ca1daeb5ff757d900e8e4a7476c6f0db843e/protobuf-7.35.1-cp310-abi3-macosx_10_9_universal2.whl", hash = "sha256:24f857477359a85c0c235261b8ba905fd51b2562f4a64ca1df5473f29850cbf6", size = 433226, upload-time = "2026-06-11T21:55:31.719Z" }, + { url = "https://files.pythonhosted.org/packages/37/4b/dfb89eb0e652a1ff073c39a59fb5e3a83cfe9b57a2c83fa6d78270101767/protobuf-7.35.1-cp310-abi3-manylinux2014_aarch64.whl", hash = "sha256:11d6b0ec246892d85215b0a13ca6e0233cf5284b68f0ac02646427f4ff88a799", size = 328847, upload-time = "2026-06-11T21:55:34.035Z" }, + { url = "https://files.pythonhosted.org/packages/0f/58/dc12f2cd484951524af6e3382c785869b9b3fb5e52ee95ae23add53ee8f9/protobuf-7.35.1-cp310-abi3-manylinux2014_s390x.whl", hash = "sha256:b73f9489a4b8b1c9cb1f8ed951c736392592edb24b9d6819f36d2e10b171d5b4", size = 344030, upload-time = "2026-06-11T21:55:34.941Z" }, + { url = "https://files.pythonhosted.org/packages/e4/be/5b3cfe508bfab6761414ff944e3366eb13be4fd71efcd69450f89ba39f43/protobuf-7.35.1-cp310-abi3-manylinux2014_x86_64.whl", hash = "sha256:74758715c53d7158fb76caf4f0cfdacc5329a4b1bb994f865d6cf302d413a1c4", size = 327130, upload-time = "2026-06-11T21:55:35.921Z" }, + { url = "https://files.pythonhosted.org/packages/d8/bc/6d6c7ba8709c85f8f2c390b2b118d6fb08a783676a572271851bf45a7d22/protobuf-7.35.1-cp310-abi3-win32.whl", hash = "sha256:353652e4efd0bca5b5fc2656abf8307ef351f0cf938c9eba09f0e09c20a25c30", size = 428945, upload-time = "2026-06-11T21:55:37.034Z" }, + { url = "https://files.pythonhosted.org/packages/0a/19/8d0cb6f20a1ef7b18f1c8986ad5783f22f84cce39c6ce9a6e645ea55192e/protobuf-7.35.1-cp310-abi3-win_amd64.whl", hash = "sha256:230a75ddfc2de4806e56696ce9640c1cdfdb6543b7cfce98d42a4c0a0e7bdb87", size = 439996, upload-time = "2026-06-11T21:55:38.123Z" }, + { url = "https://files.pythonhosted.org/packages/19/c7/5f7c636ec43e0c545e28d1f1db71990108306f7bdcb89f069ba97e428e7f/protobuf-7.35.1-py3-none-any.whl", hash = "sha256:4bc97768d8fe4ad6743c8a19403e314511ed9f6d13205b687e52421c023ac1b9", size = 171659, upload-time = "2026-06-11T21:55:39.155Z" }, +] + +[[package]] +name = "pyarrow" +version = "25.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/27/f3/95428098d1fa7d04432fb750eed06b41304c2f6a5d3319985e64db2d9d41/pyarrow-25.0.0.tar.gz", hash = "sha256:d2d697008b5ec06d75952ef260c2e9a8a0f6ccfce24266c04c9c8ade927cb3b4", size = 1199181, upload-time = "2026-07-10T08:29:50.116Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/44/fdd3a4377807b7dcabe2d4b5aa99dbbc98e2e5df3f1ca4e7f0aec492d987/pyarrow-25.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:149730a3d1f0fb59d663a0b8aa210adfd9c17c27cd94a0d143e60daea8320d4e", size = 35850884, upload-time = "2026-07-10T08:26:47.357Z" }, + { url = "https://files.pythonhosted.org/packages/bf/71/9f053177a7709b8c90abb00a2375b916286f9f0d6cfb21a5cadd4ef811e8/pyarrow-25.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:0721332c30fdd453fdd1fc203b2ac1f4c9db5aea28fa38d41f2574c4b068b9ec", size = 37616197, upload-time = "2026-07-10T08:26:53.564Z" }, + { url = "https://files.pythonhosted.org/packages/95/1a/22bfb6597dcdc861fa83c39c06e1457cb56f698940eff42fbb25de30e8e5/pyarrow-25.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:fa1482b3da10cac2d4db6e26b81da543e237616af2ef6d466018b31ca586496f", size = 46841966, upload-time = "2026-07-10T08:27:07.685Z" }, + { url = "https://files.pythonhosted.org/packages/55/0e/cd705c042bc4fe7022478db577fcab4abdcfabb9bc37ab7a75556b3fcb2b/pyarrow-25.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:5d1dbf24e151042f2fa3c129563f65d66674128868496fb008c4272b16bdf778", size = 50088993, upload-time = "2026-07-10T08:27:14.268Z" }, + { url = "https://files.pythonhosted.org/packages/98/ee/d822e1ee31fe31ec5d057210e0605c950b975dcd8d9a332976cc859a9df8/pyarrow-25.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:20887a762dd61dcc530f93a140840ab1f6aa7836b33270e42d627ab3cf11e537", size = 49941005, upload-time = "2026-07-10T08:27:21.274Z" }, + { url = "https://files.pythonhosted.org/packages/33/1b/207a90cc64619a095eb75a263ae069735f2810056d43c667befd573ec083/pyarrow-25.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:58d1ab556b0cea1c93fdb799b24ad58adb2f2a2788dbce782a94f64ae1a5cc9b", size = 53112355, upload-time = "2026-07-10T08:27:27.911Z" }, + { url = "https://files.pythonhosted.org/packages/7e/fe/81d1e5f8beed15c01e98649d5c6e2167b67fd395884a2488f18bf1cf0dba/pyarrow-25.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:3f356afe61186395c861d5cd63dc21ff7d5fa335012a4668d979257df7fea0f5", size = 27945954, upload-time = "2026-07-10T08:27:32.903Z" }, +] + +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + +[[package]] +name = "pydantic" +version = "2.13.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/18/a5/b60d21ac674192f8ab0ba4e9fd860690f9b4a6e51ca5df118733b487d8d6/pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6", size = 844775, upload-time = "2026-05-06T13:43:05.343Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl", hash = "sha256:45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba", size = 472262, upload-time = "2026-05-06T13:43:02.641Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.46.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464, upload-time = "2026-05-06T13:37:06.98Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/8c/af022f0af448d7747c5154288d46b5f2bc5f17366eaa0e23e9aa04d59f3b/pydantic_core-2.46.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3245406455a5d98187ec35530fd772b1d799b26667980872c8d4614991e2c4a2", size = 2106158, upload-time = "2026-05-06T13:38:57.215Z" }, + { url = "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:962ccbab7b642487b1d8b7df90ef677e03134cf1fd8880bf698649b22a69371f", size = 1951724, upload-time = "2026-05-06T13:37:02.697Z" }, + { url = "https://files.pythonhosted.org/packages/8e/bc/f47d1ff9cbb1620e1b5b697eef06010035735f07820180e74178226b27b3/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8233f2947cf85404441fd7e0085f53b10c93e0ee78611099b5c7237e36aacbf7", size = 1975742, upload-time = "2026-05-06T13:37:09.448Z" }, + { url = "https://files.pythonhosted.org/packages/5b/11/9b9a5b0306345664a2da6410877af6e8082481b5884b3ddd78d47c6013ce/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a233125ac121aa3ffba9a2b59edfc4a985a76092dc8279586ab4b71390875e7", size = 2052418, upload-time = "2026-05-06T13:37:38.234Z" }, + { url = "https://files.pythonhosted.org/packages/f1/b7/a65fec226f5d78fc39f4a13c4cc0c768c22b113438f60c14adc9d2865038/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b712b53160b79a5850310b912a5ef8e57e56947c8ad690c227f5c9d7e561712", size = 2232274, upload-time = "2026-05-06T13:38:27.753Z" }, + { url = "https://files.pythonhosted.org/packages/68/f0/92039db98b907ef49269a8271f67db9cb78ae2fc68062ef7e4e77adb5f61/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9401557acd873c3a7f3eb9383edef8ac4968f9510e340f4808d427e75667e7b4", size = 2309940, upload-time = "2026-05-06T13:38:05.353Z" }, + { url = "https://files.pythonhosted.org/packages/5f/97/2aab507d3d00ca626e8e57c1eac6a79e4e5fbcc63eb99733ff55d1717f65/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:926c9541b14b12b1681dca8a0b75feb510b06c6341b70a8e500c2fdcff837cce", size = 2094516, upload-time = "2026-05-06T13:39:10.577Z" }, + { url = "https://files.pythonhosted.org/packages/22/37/a8aca44d40d737dde2bc05b3c6c07dff0de07ce6f82e9f3167aeaf4d5dea/pydantic_core-2.46.4-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:56cb4851bcaf3d117eddcef4fe66afd750a50274b0da8e22be256d10e5611987", size = 2136854, upload-time = "2026-05-06T13:40:22.59Z" }, + { url = "https://files.pythonhosted.org/packages/24/99/fcef1b79238c06a8cbec70819ac722ba76e02bc8ada9b0fd66eba40da01b/pydantic_core-2.46.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c68fcd102d71ea85c5b2dfac3f4f8476eff42a9e078fd5faefff6d145063536b", size = 2180306, upload-time = "2026-05-06T13:40:10.666Z" }, + { url = "https://files.pythonhosted.org/packages/ae/6c/fc44000918855b42779d007ae63b0532794739027b2f417321cddbc44f6a/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b2f69dec1725e79a012d920df1707de5caf7ed5e08f3be4435e25803efc47458", size = 2190044, upload-time = "2026-05-06T13:40:43.231Z" }, + { url = "https://files.pythonhosted.org/packages/6b/65/d9cadc9f1920d7a127ad2edba16c1db7916e59719285cd6c94600b0080ba/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:8d0820e8192167f80d88d64038e609c31452eeca865b4e1d9950a27a4609b00b", size = 2329133, upload-time = "2026-05-06T13:39:57.365Z" }, + { url = "https://files.pythonhosted.org/packages/d0/cf/c873d91679f3a30bcf5e7ac280ce5573483e72295307685120d0d5ad3416/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fbdb89b3e1c94a30cc5edfce477c6e6a5dc4d8f84665b455c27582f211a1c72c", size = 2374464, upload-time = "2026-05-06T13:38:06.976Z" }, + { url = "https://files.pythonhosted.org/packages/47/bd/6f2fc8188f31bf10590f1e98e7b306336161fac930a8c514cd7bd828c7dc/pydantic_core-2.46.4-cp312-cp312-win32.whl", hash = "sha256:9aa768456404a8bf48a4406685ac2bec8e72b62c69313734fa3b73cf33b3a894", size = 1974823, upload-time = "2026-05-06T13:40:47.985Z" }, + { url = "https://files.pythonhosted.org/packages/40/8c/985c1d41ea1107c2534abd9870e4ed5c8e7669b5c308297835c001e7a1c4/pydantic_core-2.46.4-cp312-cp312-win_amd64.whl", hash = "sha256:e9c26f834c65f5752f3f06cb08cb86a913ceb7274d0db6e267808a708b46bc89", size = 2072919, upload-time = "2026-05-06T13:39:21.153Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ba/f463d006e0c47373ca7ec5e1a261c59dc01ef4d62b2657af925fb0deee3a/pydantic_core-2.46.4-cp312-cp312-win_arm64.whl", hash = "sha256:4fc73cb559bdb54b1134a706a2802a4cddd27a0633f5abb7e53056268751ac6a", size = 2027604, upload-time = "2026-05-06T13:39:03.753Z" }, + { url = "https://files.pythonhosted.org/packages/9d/1d/8987ad40f65ae1432753072f214fb5c74fe47ffbd0698bb9cbbb585664f8/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:1d8ba486450b14f3b1d63bc521d410ec7565e52f887b9fb671791886436a42f7", size = 2095527, upload-time = "2026-05-06T13:39:52.283Z" }, + { url = "https://files.pythonhosted.org/packages/64/d3/84c282a7eee1d3ac4c0377546ef5a1ea436ce26840d9ac3b7ed54a377507/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:3009f12e4e90b7f88b4f9adb1b0c4a3d58fe7820f3238c190047209d148026df", size = 1936024, upload-time = "2026-05-06T13:40:15.671Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ca/eac61596cdeb4d7e174d3dc0bd8a6238f14f75f97a24e7b7db4c7e7340a0/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad785e92e6dc634c21555edc8bd6b64957ab844541bcb96a1366c202951ae526", size = 1990696, upload-time = "2026-05-06T13:38:34.717Z" }, + { url = "https://files.pythonhosted.org/packages/fa/c3/7c8b240552251faf6b3a957db200fcfbbcec36763c050428b601e0c9b83b/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00c603d540afdd6b80eb39f078f33ebd46211f02f33e34a32d9f053bba711de0", size = 2147590, upload-time = "2026-05-06T13:39:29.883Z" }, +] + +[[package]] +name = "pydantic-settings" +version = "2.14.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5c/b5/8f48e906c3e0205276e8bd8cb7512217a87b2685304d64be27cad5b3019f/pydantic_settings-2.14.2.tar.gz", hash = "sha256:c19dd64b19097f1de80184f0cc7b0272a13ae6e170cbf240a3e27e381ed14a5f", size = 237700, upload-time = "2026-06-19T13:44:56.324Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/c1/6e422f34e569cf8e18df68d1939c81c099d2b61e4f7d9621c8a77560799c/pydantic_settings-2.14.2-py3-none-any.whl", hash = "sha256:a20c97b37910b6550d5ea50fbcc2d4187defe58cd57070b73863d069419c9440", size = 61715, upload-time = "2026-06-19T13:44:55.02Z" }, +] + +[[package]] +name = "pygments" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, +] + +[[package]] +name = "pyjwt" +version = "2.13.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/81/58d0ac84e1ef3a3843791d6954d94c0b33d526c75eeb1efbce9d0a4c4077/pyjwt-2.13.0.tar.gz", hash = "sha256:41571c89ca91598c79e8ef18a2d07367d4810fbbd6f637794879baf1b7703423", size = 107515, upload-time = "2026-05-21T19:54:36.618Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl", hash = "sha256:66adcc2aff09b3f1bbd95fc1e1577df8ac8723c978552fd43304c8a290ac5728", size = 31274, upload-time = "2026-05-21T19:54:35.362Z" }, +] + +[package.optional-dependencies] +crypto = [ + { name = "cryptography" }, +] + +[[package]] +name = "pyqwest" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cd/25/305acffe35817ac5dd3659f06bf5c7522cf2d6b1cbfb6e71dfd4e7cf28b0/pyqwest-0.8.0.tar.gz", hash = "sha256:138a6a01f5e3bdd92abed412f35bf122b5a7c41cadaffe9c8b3ba0dc2dc5d822", size = 469648, upload-time = "2026-07-31T03:33:42.436Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/38/76280a079b0f84dcc05c14eba16b6cd39bef9e8aa0a51e916abf71fea637/pyqwest-0.8.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:2976d8fc93b7b4fdb9bfc7ad231e6584d81b9777ad88c8256e02cfa8b690364d", size = 5216354, upload-time = "2026-07-31T03:32:16.344Z" }, + { url = "https://files.pythonhosted.org/packages/fd/0c/afde50b6814e6c053237fb6182f3ffcbe6562fdbfd0c44b6b6589cb37ea7/pyqwest-0.8.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:afe8a86b28ef637b85d2239758f91ef3acdb01bd569fb8abcb4ec70b368fd2d7", size = 5095245, upload-time = "2026-07-31T03:32:18.994Z" }, + { url = "https://files.pythonhosted.org/packages/d9/18/0b0d177754b337afaf9b7d7b0de476ae250bab3bbf105568211fa83da2d6/pyqwest-0.8.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8d948f99dc80e1d4879bbfb4ff073e1d7566dc307d483f6857907b9b634631d", size = 5614817, upload-time = "2026-07-31T03:32:21.005Z" }, + { url = "https://files.pythonhosted.org/packages/dc/12/d5b2e201ca3c374174644fbf201329ff6635ebabef0fcc49701f8d168984/pyqwest-0.8.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bcd1edaa837e136af6982c31c17100a16b6e4918e7237a34229928754edae35", size = 5557336, upload-time = "2026-07-31T03:32:22.725Z" }, + { url = "https://files.pythonhosted.org/packages/d8/36/d5ba098c323d7f5eb9cb9ebf075060d14c3364bf176d9815655065462bc7/pyqwest-0.8.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1c25504a5fe4d72f43b17253c9e1dc4cda426e9fa0a72474c4555455f63706c1", size = 5775102, upload-time = "2026-07-31T03:32:24.766Z" }, + { url = "https://files.pythonhosted.org/packages/1c/e5/1b1bae527e4de93b9eddbf15a78f1ce5198aece5c169478e385364e0f1f1/pyqwest-0.8.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:513fe7649d727cccb5d6e04999e91fed5f61f5e20a8556a2f96d3d1aeea02001", size = 5963251, upload-time = "2026-07-31T03:32:26.792Z" }, + { url = "https://files.pythonhosted.org/packages/44/14/a9d883fc59df1f34fe42764277ca26de11d74dd3aa3d9f9f4a35d7414f37/pyqwest-0.8.0-cp310-abi3-win_amd64.whl", hash = "sha256:7896646bd426db0cbd7a5d4ebd0dacd59f1a2c3cdc12fb2667234e9504e33b03", size = 4834356, upload-time = "2026-07-31T03:32:28.921Z" }, + { url = "https://files.pythonhosted.org/packages/2e/49/c0640e19718c4533590bcaba647ad3145f793c66c125cb62c399e580b1a6/pyqwest-0.8.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c4970ad95d4d51aa07980687d07e1f4003b68bc1fa1e46c9202f1b008c95662e", size = 5232611, upload-time = "2026-07-31T03:32:30.778Z" }, + { url = "https://files.pythonhosted.org/packages/50/85/25c440e1dc31320afa9de8a3ab43b0bc6f5ef5090e43fac350b5de4db623/pyqwest-0.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:63f341cf695b9c8b9b184a0f1c67f6e578b833502f1f21a9359f031b5b77a627", size = 5089482, upload-time = "2026-07-31T03:32:32.817Z" }, + { url = "https://files.pythonhosted.org/packages/5b/7c/a5c49001dc0685043512c5497a7820fe091d765f93a730ace81708ed8f5e/pyqwest-0.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed43c61eebe85aa078ff922378aac9904c9d0be06c99da5826c865c28f8468dc", size = 5618803, upload-time = "2026-07-31T03:32:34.801Z" }, + { url = "https://files.pythonhosted.org/packages/39/af/6835aaeb451f629886bae0b924a864b73b906c84944be37fea43298c163a/pyqwest-0.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7988aeb1dce1ee0d3dbcf9d6c8d3a2a821d9c56402c95c057567363ed01116c0", size = 5556779, upload-time = "2026-07-31T03:32:37.044Z" }, + { url = "https://files.pythonhosted.org/packages/ea/66/2f130d7dc3341112f1a620984d4af17cacf2a17085a1eaa98dfaa35da028/pyqwest-0.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37ebb0bfeaa5a6b5c6ebd1cfdbb3e4d89ac343e46be07a993e8af6473ee82b1b", size = 5779456, upload-time = "2026-07-31T03:32:39.021Z" }, + { url = "https://files.pythonhosted.org/packages/45/4b/14a30458a69e6f1b8e007ff6bd6fdf867cc28de45d046374f45087d31fd8/pyqwest-0.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4471266ff506d02f21350921abd0adbaa08d6b7db6d24408c2ed9635e187e263", size = 5962595, upload-time = "2026-07-31T03:32:41.02Z" }, + { url = "https://files.pythonhosted.org/packages/05/22/db95030afe6c5adc90b2864e194d8074175675a90703282286e3370ecd53/pyqwest-0.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:5b605cb927b5bbd0b1247a5439d90068fee84802003bd6609c48e985aeb15570", size = 4824467, upload-time = "2026-07-31T03:32:42.733Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "python-dotenv" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, +] + +[[package]] +name = "python-multipart" +version = "0.0.32" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/42/55c32bb9b12693c092ad250a0e82edb5b31ddeda6eb772de5f308b3804ad/python_multipart-0.0.32.tar.gz", hash = "sha256:be54b7f3fa167bb83e4fcd936b887b708f4e57fe75911c02aebf53efaf8d938e", size = 46881, upload-time = "2026-06-04T16:18:58.647Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl", hash = "sha256:ff6d3f776f16878c894e52e107296ffc890e913c611b1a4ec6c44e2821fe2e23", size = 30042, upload-time = "2026-06-04T16:18:57.319Z" }, +] + +[[package]] +name = "pywin32" +version = "312" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/ff/32aa7d2ed0ab12b323aaa64f9b75e6ad4f8fd09f9ccfc28c79414d46838d/pywin32-312-cp312-cp312-win32.whl", hash = "sha256:dab4f65ac9c4e48400a2a0530c46c3c579cd5905ecd11b80692373915269208b", size = 6371877, upload-time = "2026-06-04T07:49:28.836Z" }, + { url = "https://files.pythonhosted.org/packages/03/d9/77040d3b43df3f3be32ea289433d660d2727f5ba327bc73be835127d9d60/pywin32-312-cp312-cp312-win_amd64.whl", hash = "sha256:b457f6d628a47e8a7346ce22acb7e1a46a4a78b52e1d17e1af56871bd19a93bc", size = 6914841, upload-time = "2026-06-04T07:49:31.85Z" }, + { url = "https://files.pythonhosted.org/packages/e3/cc/7b1ec671775756020a0ee7f4feeaf3c568f0ab86bd3900088cf986937a92/pywin32-312-cp312-cp312-win_arm64.whl", hash = "sha256:6017c58e12f6809fbb0555b75df144c2922a9ffd18e4b9b5afa863b6c1a9d950", size = 6727901, upload-time = "2026-06-04T07:49:34.244Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, +] + +[[package]] +name = "pyzmq" +version = "27.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "implementation_name == 'pypy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750, upload-time = "2025-09-08T23:10:18.157Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279, upload-time = "2025-09-08T23:08:03.807Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645, upload-time = "2025-09-08T23:08:05.301Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574, upload-time = "2025-09-08T23:08:06.828Z" }, + { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995, upload-time = "2025-09-08T23:08:08.396Z" }, + { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070, upload-time = "2025-09-08T23:08:09.989Z" }, + { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121, upload-time = "2025-09-08T23:08:11.907Z" }, + { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550, upload-time = "2025-09-08T23:08:13.513Z" }, + { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184, upload-time = "2025-09-08T23:08:15.163Z" }, + { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480, upload-time = "2025-09-08T23:08:17.192Z" }, + { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993, upload-time = "2025-09-08T23:08:18.926Z" }, +] + +[[package]] +name = "referencing" +version = "0.37.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, +] + +[[package]] +name = "regex" +version = "2026.7.19" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/98/04b13f1ddfb63158025291c02e03eb42fbb7acb51d091d541050eb4e35e8/regex-2026.7.19.tar.gz", hash = "sha256:7e77b324909c1617cbb4c668677e2c6ae13f44d7c1de0d4f15f2e3c10f3315b5", size = 416440, upload-time = "2026-07-19T00:19:48.923Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/b9/d11d7e501ac8fd7d617684423ebb9561e0b998481c1e4cbc0cb212c5d74a/regex-2026.7.19-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2cc3460cedf7579948486eab03bc9ad7089df4d7281c0f47f4afe03e8d13f02d", size = 496778, upload-time = "2026-07-19T00:17:05.677Z" }, + { url = "https://files.pythonhosted.org/packages/3f/a9/a5ab6f312f24318019170dc485d5421fe4f89e43a98640da50d95a8a7041/regex-2026.7.19-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0e9554c8785eac5cffe6300f69a91f58ba72bc88a5f8d661235ad7c6aa5b8ccd", size = 297122, upload-time = "2026-07-19T00:17:07.59Z" }, + { url = "https://files.pythonhosted.org/packages/b3/63/4cab4d7f2d384a144d420b763d97674cb70619c878ea6fcd7640d0e62143/regex-2026.7.19-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d7da47a0f248977f08e2cb659ff3c17ddc13a4d39b3a7baa0a81bf5b415430f6", size = 292009, upload-time = "2026-07-19T00:17:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/22/85/102a81b218298957d4ea7d2f084fae537a71add9d6ff93c8e67284c5f45e/regex-2026.7.19-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:93db40c8de0815baab96a06e08a984bac71f989d13bab789e382158c5d426797", size = 796708, upload-time = "2026-07-19T00:17:11.542Z" }, + { url = "https://files.pythonhosted.org/packages/78/b5/dc136af5629938a037cd2b304c12240e132ec92f38be8ff9cc89af2a1f2d/regex-2026.7.19-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:66bd62c59a5427746e8c44becae1d9b99d22fb13f30f492083dfb9ad7c45cc18", size = 865651, upload-time = "2026-07-19T00:17:13.312Z" }, + { url = "https://files.pythonhosted.org/packages/e0/75/67402ae3cd9c8c988a4c805d15ee3eef015e7ca4cb112cf3e640fc1f4153/regex-2026.7.19-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1649eb39fcc9ea80c4d2f110fde2b8ab2aef3877b98f02ab9b14e961f418c511", size = 911756, upload-time = "2026-07-19T00:17:15.015Z" }, + { url = "https://files.pythonhosted.org/packages/2a/8e/096d00c7c480ef2ff4265349b14e2261d4ab787ba1f74e2e80d1c58079c3/regex-2026.7.19-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9dce8ec9695f531a1b8a6f314fd4b393adcccf2ea861db480cdf97a301d01a68", size = 801798, upload-time = "2026-07-19T00:17:17.208Z" }, + { url = "https://files.pythonhosted.org/packages/f0/41/e7ecac6edb5722417f85cc67eaf386322fbe8acf6918ec2fdc37c20dd9d0/regex-2026.7.19-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3080a7fd38ef049bd489e01c970c97dd84ff446a885b0f1f6b26d9b1ad13ce11", size = 776933, upload-time = "2026-07-19T00:17:19.347Z" }, + { url = "https://files.pythonhosted.org/packages/6f/69/03c9b3f058d66403e0ca2c938696e81d51cd4c6d47ec5265f02f96948d9a/regex-2026.7.19-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1d793a7988e04fcb1e2e135567443d82173225d657419ec09414a9b5a145b986", size = 784338, upload-time = "2026-07-19T00:17:21.057Z" }, + { url = "https://files.pythonhosted.org/packages/f6/f7/b38ab3d43f284afbb618fcd15d0e77eb786ae461ce1f6bc7494619ddc0f2/regex-2026.7.19-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e8b0abe7d870f53ca5143895fef7d1041a0c831a140d3dc2c760dd7ba25d4a8b", size = 860452, upload-time = "2026-07-19T00:17:23.119Z" }, + { url = "https://files.pythonhosted.org/packages/15/5c/ff60ef0571121714f3cf9920bc183071e384a10b556d042e0fdb06cc07a5/regex-2026.7.19-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:4e5413bd5f13d3a4e3539ca98f70f75e7fca92518dd7f117f030ebedd10b60cb", size = 765958, upload-time = "2026-07-19T00:17:24.81Z" }, + { url = "https://files.pythonhosted.org/packages/aa/0f/bd34021162c0ab47f9a315bd56cd5642e920c8e5668a75ef6c6a6fca590d/regex-2026.7.19-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:73b133a9e6fb512858e7f065e96f1180aa46646bc74a83aea62f1d314f3dd035", size = 851765, upload-time = "2026-07-19T00:17:26.993Z" }, + { url = "https://files.pythonhosted.org/packages/2a/20/a2ca43edade0595cccfdc98636739f536d9e26898e7dbddc2b9e98898953/regex-2026.7.19-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dbe6493fbd27321b1d1f2dd4f5c7e5bd4d8b1d7cab7f32fd67db3d0b2ed8248a", size = 789714, upload-time = "2026-07-19T00:17:28.699Z" }, + { url = "https://files.pythonhosted.org/packages/5d/47/e02db4015d424fc83c00ea0ac8c5e5ec14397943de9abf909d5ce3a25931/regex-2026.7.19-cp312-cp312-win32.whl", hash = "sha256:ddd67571c10869f65a5d7dde536d1e066e306cc90de57d7de4d5f34802428bb5", size = 267157, upload-time = "2026-07-19T00:17:31.051Z" }, + { url = "https://files.pythonhosted.org/packages/08/8e/c780c131f79b42ed22d1bd7da4096c2c35f813e835acd02ef0f018bd892c/regex-2026.7.19-cp312-cp312-win_amd64.whl", hash = "sha256:e30d40268a28d54ce0437031750497004c22602b8e3ab891f759b795a003b312", size = 277777, upload-time = "2026-07-19T00:17:32.848Z" }, + { url = "https://files.pythonhosted.org/packages/3e/4c/e4d7e086449bdf379d89774bf1f89dc4a41943f3c5a6125a03905b34b5fb/regex-2026.7.19-cp312-cp312-win_arm64.whl", hash = "sha256:de9208bb427130c82a5dbfd104f92c8876fc9559278c880b3002755bbbe9c83d", size = 277136, upload-time = "2026-07-19T00:17:34.803Z" }, +] + +[[package]] +name = "renderers" +version = "0.1.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "numpy" }, + { name = "openai" }, + { name = "openai-harmony" }, + { name = "prime-pydantic-config" }, + { name = "tiktoken" }, + { name = "transformers" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f9/82/e493c5f6752283b18f43b8bb3e6f3b2068310a0a42b0650de1b841713fa3/renderers-0.1.8.tar.gz", hash = "sha256:7a50b59cc64593da504c054bf3e2f0f147af5c1770bad7107de7b18887377280", size = 343291, upload-time = "2026-07-15T14:10:22.918Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/2b/6defb0cc5ca19d66798a6c656d30aab86d7c9d4cec14c2b24248b5421c86/renderers-0.1.8-py3-none-any.whl", hash = "sha256:40e6b2c766e23feb12f73b1fbdfef4dea51921479454756ac796612e3bef8397", size = 189915, upload-time = "2026-07-15T14:10:21.371Z" }, +] + +[[package]] +name = "requests" +version = "2.34.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" }, +] + +[[package]] +name = "rich" +version = "15.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" }, +] + +[[package]] +name = "rpds-py" +version = "2026.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/2a/9618a122aeb2a169a28b03889a2995fe297588964333d4a7d67bdf46e147/rpds_py-2026.6.3.tar.gz", hash = "sha256:1cebd1337c242e4ec2293e541f712b2da849b29f48f0c293684b71c0632625d4", size = 64051, upload-time = "2026-06-30T07:17:53.009Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/be/2e8974163072e7bab7df1a5acd54c4498e75e35d6d18b864d3a9d5dadc92/rpds_py-2026.6.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a0811d33247c3d6128a3001d763f2aa056bb3425204335400ac54f89eec3a0d0", size = 343691, upload-time = "2026-06-30T07:15:14.96Z" }, + { url = "https://files.pythonhosted.org/packages/a4/73/319dfa745dd668efe89309141ded489126461fcecd2b8f3a3cda185129b6/rpds_py-2026.6.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:538949e262e46caa31ac01bdb3c1e8f642622922cacbabbae6a8445d9dc33eaf", size = 338542, upload-time = "2026-06-30T07:15:16.267Z" }, + { url = "https://files.pythonhosted.org/packages/21/63/4239893be1c4d09b709b1a8f6be4188f0870084ff547f46606b8a75f1b03/rpds_py-2026.6.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55927d532399c2c646100ff7feb48eaa940ad70f42cd68e1328f3ded9f81ca24", size = 368180, upload-time = "2026-06-30T07:15:17.62Z" }, + { url = "https://files.pythonhosted.org/packages/1c/ca/9c5de382225234ceb37b1844ebdb140db12b2a278bb9efe2fcd19f6c82ce/rpds_py-2026.6.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f56f1695bc5c0871cbc33dc0130fcf503aab0c57dcc5a6700a4f49eba4f2652e", size = 375067, upload-time = "2026-06-30T07:15:18.952Z" }, + { url = "https://files.pythonhosted.org/packages/87/dc/863f69d1bf04ade34b7fe0d59b9fdf6f0135fe2d7cbca74f1d665589559d/rpds_py-2026.6.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:270b293dae9058fc9fcedab50f13cebf46fb8ed1d1d54e0521a9da5d6b211975", size = 490509, upload-time = "2026-06-30T07:15:20.434Z" }, + { url = "https://files.pythonhosted.org/packages/ce/ef/eac16a12048b45ec7c7fa94f2be3438a5f26bf9cc8580b18a1cfd609b7f6/rpds_py-2026.6.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:127565fead0a10943b282957bd5447804ff3160ad79f2ad2635e6d249e380680", size = 382754, upload-time = "2026-06-30T07:15:21.831Z" }, + { url = "https://files.pythonhosted.org/packages/04/8f/d2f3f532616be4d06c316ef119683e832bd3d41e112bf3a88f4151c95b17/rpds_py-2026.6.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecabd69db66de867690f9797f2f8fa27ba501bbc24540cbdbdc649cd15888ba6", size = 366189, upload-time = "2026-06-30T07:15:23.371Z" }, + { url = "https://files.pythonhosted.org/packages/e3/29/41a7b0e98a4b44cd676ab7598419623373eb43b20be68c084935c1a8cf88/rpds_py-2026.6.3-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:58eadac9cd119677b60e1cf8ac4052f35949d71b8a9e5556efccbe82533cf22a", size = 377750, upload-time = "2026-06-30T07:15:24.659Z" }, + { url = "https://files.pythonhosted.org/packages/2e/05/ecda0bec46f9a1565090bcdc941d023f6a25aff85fda28f89f8d19878152/rpds_py-2026.6.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7491ee23305ac3eb59e492b6945881f5cd77a6f731061a3f25b77fd40f9e99a4", size = 395576, upload-time = "2026-06-30T07:15:25.987Z" }, + { url = "https://files.pythonhosted.org/packages/68/a8/6ed52f03ee6cb854ce78785cc9a9a672eb880e83fd7224d471f667d151f1/rpds_py-2026.6.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2c99f7e8ccb3dd6e3e4bfeac657a7b208c9bac8075f4b078c02d7404c34107fa", size = 543807, upload-time = "2026-06-30T07:15:27.356Z" }, + { url = "https://files.pythonhosted.org/packages/8f/d6/156c0d3eea27ba09b92562ba2364ba124c0a061b199e17eac637cd25a5e2/rpds_py-2026.6.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:62698275682bf121181861295c9181e789030a2d516071f5b8f3c23c170cd0fc", size = 611187, upload-time = "2026-06-30T07:15:28.931Z" }, + { url = "https://files.pythonhosted.org/packages/f1/31/774212ed989c62f7f310220089f9b0a3fb8f40f5443d1727abd5d9f52bc9/rpds_py-2026.6.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a214c993455f99a89aaeadc9b21241900037adc9d97203e374d75513c5911822", size = 573030, upload-time = "2026-06-30T07:15:30.553Z" }, + { url = "https://files.pythonhosted.org/packages/c9/50/22f73127a41f1ce4f87fe39aadfb9a126345801c274aa93ae88456249327/rpds_py-2026.6.3-cp312-cp312-win32.whl", hash = "sha256:501f9f04a588d6a09179368c57071301445191767c64e4b52a6aa9871f1ef5ed", size = 202185, upload-time = "2026-06-30T07:15:32.027Z" }, + { url = "https://files.pythonhosted.org/packages/04/3a/f0ee4d4dde9d3b69dedf1b5f74e7a40017046d55052d173e418c6a94f960/rpds_py-2026.6.3-cp312-cp312-win_amd64.whl", hash = "sha256:2c958bf94822e9290a40aaf2a822d4bc5c88099093e3948ad6c571eca9272e5f", size = 220394, upload-time = "2026-06-30T07:15:33.359Z" }, + { url = "https://files.pythonhosted.org/packages/f3/83/3382fe37f809b59f02aac04dbc4e765b480b46ee0227ed516e3bdc4d3dfc/rpds_py-2026.6.3-cp312-cp312-win_arm64.whl", hash = "sha256:22bffe6042b9bcb0822bcd1955ec00e245daf17b4344e4ed8e9551b976b63e96", size = 215753, upload-time = "2026-06-30T07:15:34.778Z" }, +] + +[[package]] +name = "safetensors" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/45/06/f955dbbb1859e3bd23c8ac6141af5106e7ad5fedec4a3a6e3d60f94b7001/safetensors-0.8.0.tar.gz", hash = "sha256:fabaf3e0f18a6618d9b36560682562157f77c2b71fcffc7b432be2baed9d753d", size = 325846, upload-time = "2026-06-09T07:52:25.563Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/a0/f718cda65b05407d228f97602cf60dca269c979867aa5beb25410de26cd3/safetensors-0.8.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c554f85858e05226d3c2828e32395e677434685d6d94594a41643361c5e837f0", size = 473568, upload-time = "2026-06-09T07:52:18.829Z" }, + { url = "https://files.pythonhosted.org/packages/f5/b1/fa7c600e7dceae12e9606c7578cbc9ff1e1ed55844883ee5c92205e86226/safetensors-0.8.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:c80201d22cbf405b80647a60ada77bba06c8fba2da2743ba1e89cdcc39a81f25", size = 484562, upload-time = "2026-06-09T07:52:17.518Z" }, + { url = "https://files.pythonhosted.org/packages/09/7d/65a7de0af421317bb36a067241e4235fff194eed60b961ed6d3f59a3fc60/safetensors-0.8.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a46e5ff292c356d6991e60942ba7f79817682d3a2cef0702136448cb9c4d235", size = 502844, upload-time = "2026-06-09T07:52:07.624Z" }, + { url = "https://files.pythonhosted.org/packages/91/4f/3175c9d75634e0e0dda0082794193521035edd7c70a6f212bf33ca06ddf4/safetensors-0.8.0-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4124502b78f03534117c848f87a39b8f31e577b15eff423bf8bfb95f2a8c30d0", size = 511823, upload-time = "2026-06-09T07:52:09.565Z" }, + { url = "https://files.pythonhosted.org/packages/20/87/846c289e7aa2299eff406335717cf43ce8777194ece8aad75772e0411615/safetensors-0.8.0-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7bc0a787ba8a35be368ee3574edfa2b1ad389eebd0a72e482ae275490e3f6c98", size = 633461, upload-time = "2026-06-09T07:52:11.128Z" }, + { url = "https://files.pythonhosted.org/packages/76/22/8d64d9df2c45d5ded401df889d0ad90882804ca172d79ec4f0df8f727fe0/safetensors-0.8.0-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040070828e36dc8e122178bbbd5830ff9e97920affb84cbe0f46442497bed358", size = 545148, upload-time = "2026-06-09T07:52:13.603Z" }, + { url = "https://files.pythonhosted.org/packages/28/50/f203ff3a3ddfe19308efc83c5a3a29ed02bf786732ec35e68bf9162f3365/safetensors-0.8.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd6f3f93c9a0a7cc2788ee63fb763353d4bd2e89b0751bc78fcf7dda00bea774", size = 516040, upload-time = "2026-06-09T07:52:16.29Z" }, + { url = "https://files.pythonhosted.org/packages/46/fb/cdaed17ceb2948784fd9c36b6fd3e951b608547cea81a48e8ee6f8cfdfcb/safetensors-0.8.0-cp310-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:fcdd41ec4628fee5799f807c73c353629130fbd942aa23d83c623dd6c9d52d78", size = 513832, upload-time = "2026-06-09T07:52:12.37Z" }, + { url = "https://files.pythonhosted.org/packages/0d/49/1e15de264dcc3b77943d2d0c56a95809956883b1c2d6d585c792523f180b/safetensors-0.8.0-cp310-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8e9f537aa183a38ace122d27303dcd986b26bd2a7591f9181d7f0c396f4677ca", size = 559930, upload-time = "2026-06-09T07:52:14.743Z" }, + { url = "https://files.pythonhosted.org/packages/2a/43/bf38443278eab4b1be1fce2931e2b012ad9cb7df52ada751d0aab8f7659a/safetensors-0.8.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:87eec7ffed2b809f05a398a8becb7d013f19f7837cd15d9748580d6cf30dbaf4", size = 678670, upload-time = "2026-06-09T07:52:20.032Z" }, + { url = "https://files.pythonhosted.org/packages/72/e3/68cd3fa5b48488e84add63e04cb12f3bc28ae4638c06d4508c6e88823d0e/safetensors-0.8.0-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:4a95ae2b05d7726d751da4ebf626a2ca782b706e101bd894c95bc2450b1cffcc", size = 786679, upload-time = "2026-06-09T07:52:21.322Z" }, + { url = "https://files.pythonhosted.org/packages/29/4b/1c19c509d56e01f4fbb3d0a2e597450f6cc04d1d56cf52defb0a62dfd715/safetensors-0.8.0-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:3ae091f16662658bdc019a4ff6cb4c085bb7d725eb5978b183ffd265863b6d2d", size = 765683, upload-time = "2026-06-09T07:52:22.594Z" }, + { url = "https://files.pythonhosted.org/packages/27/43/41c1621732edd934d868a00d1b891584c892a7b62a9aab82ea5a0a5623ee/safetensors-0.8.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8e080062fcde23be189565e1c3305d16751a218ecf9412c8601e64204eb6f846", size = 722361, upload-time = "2026-06-09T07:52:23.924Z" }, + { url = "https://files.pythonhosted.org/packages/8e/3f/73ccf82579412b4a71c4ca673f10b5f1f888d7cf5af7fe24f27d30307be4/safetensors-0.8.0-cp310-abi3-win32.whl", hash = "sha256:2ddf52eac562eda224f99acfa7889d02968c1fd59a5b011ae7d8137c37e9c02d", size = 342401, upload-time = "2026-06-09T07:52:28.895Z" }, + { url = "https://files.pythonhosted.org/packages/1b/6d/3fba214c1e5e0f69991677ec3bc17023f0421776975e1de0c682dca475e2/safetensors-0.8.0-cp310-abi3-win_amd64.whl", hash = "sha256:096ec1a98435df7beb08853bb5aa9081a84f23d0adc67ed1a0a10550f608373f", size = 355540, upload-time = "2026-06-09T07:52:27.832Z" }, + { url = "https://files.pythonhosted.org/packages/8d/fc/7eedc3510d97878876e32774eebbeb61c43f148a96e915c84229a3e967aa/safetensors-0.8.0-cp310-abi3-win_arm64.whl", hash = "sha256:f7838e5135a406ad3e02efdcb8cf2e5397d368b0154537c4fec682dbc544d452", size = 340500, upload-time = "2026-06-09T07:52:26.745Z" }, +] + +[[package]] +name = "setproctitle" +version = "1.3.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8d/48/49393a96a2eef1ab418b17475fb92b8fcfad83d099e678751b05472e69de/setproctitle-1.3.7.tar.gz", hash = "sha256:bc2bc917691c1537d5b9bca1468437176809c7e11e5694ca79a9ca12345dcb9e", size = 27002, upload-time = "2025-09-05T12:51:25.278Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/f0/2dc88e842077719d7384d86cc47403e5102810492b33680e7dadcee64cd8/setproctitle-1.3.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2dc99aec591ab6126e636b11035a70991bc1ab7a261da428491a40b84376654e", size = 18049, upload-time = "2025-09-05T12:49:36.241Z" }, + { url = "https://files.pythonhosted.org/packages/f0/b4/50940504466689cda65680c9e9a1e518e5750c10490639fa687489ac7013/setproctitle-1.3.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cdd8aa571b7aa39840fdbea620e308a19691ff595c3a10231e9ee830339dd798", size = 13079, upload-time = "2025-09-05T12:49:38.088Z" }, + { url = "https://files.pythonhosted.org/packages/d0/99/71630546b9395b095f4082be41165d1078204d1696c2d9baade3de3202d0/setproctitle-1.3.7-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2906b6c7959cdb75f46159bf0acd8cc9906cf1361c9e1ded0d065fe8f9039629", size = 32932, upload-time = "2025-09-05T12:49:39.271Z" }, + { url = "https://files.pythonhosted.org/packages/50/22/cee06af4ffcfb0e8aba047bd44f5262e644199ae7527ae2c1f672b86495c/setproctitle-1.3.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6915964a6dda07920a1159321dcd6d94fc7fc526f815ca08a8063aeca3c204f1", size = 33736, upload-time = "2025-09-05T12:49:40.565Z" }, + { url = "https://files.pythonhosted.org/packages/5c/00/a5949a8bb06ef5e7df214fc393bb2fb6aedf0479b17214e57750dfdd0f24/setproctitle-1.3.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cff72899861c765bd4021d1ff1c68d60edc129711a2fdba77f9cb69ef726a8b6", size = 35605, upload-time = "2025-09-05T12:49:42.362Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3a/50caca532a9343828e3bf5778c7a84d6c737a249b1796d50dd680290594d/setproctitle-1.3.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b7cb05bd446687ff816a3aaaf831047fc4c364feff7ada94a66024f1367b448c", size = 33143, upload-time = "2025-09-05T12:49:43.515Z" }, + { url = "https://files.pythonhosted.org/packages/ca/14/b843a251296ce55e2e17c017d6b9f11ce0d3d070e9265de4ecad948b913d/setproctitle-1.3.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3a57b9a00de8cae7e2a1f7b9f0c2ac7b69372159e16a7708aa2f38f9e5cc987a", size = 34434, upload-time = "2025-09-05T12:49:45.31Z" }, + { url = "https://files.pythonhosted.org/packages/c8/b7/06145c238c0a6d2c4bc881f8be230bb9f36d2bf51aff7bddcb796d5eed67/setproctitle-1.3.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d8828b356114f6b308b04afe398ed93803d7fca4a955dd3abe84430e28d33739", size = 32795, upload-time = "2025-09-05T12:49:46.419Z" }, + { url = "https://files.pythonhosted.org/packages/ef/dc/ef76a81fac9bf27b84ed23df19c1f67391a753eed6e3c2254ebcb5133f56/setproctitle-1.3.7-cp312-cp312-win32.whl", hash = "sha256:b0304f905efc845829ac2bc791ddebb976db2885f6171f4a3de678d7ee3f7c9f", size = 12552, upload-time = "2025-09-05T12:49:47.635Z" }, + { url = "https://files.pythonhosted.org/packages/e2/5b/a9fe517912cd6e28cf43a212b80cb679ff179a91b623138a99796d7d18a0/setproctitle-1.3.7-cp312-cp312-win_amd64.whl", hash = "sha256:9888ceb4faea3116cf02a920ff00bfbc8cc899743e4b4ac914b03625bdc3c300", size = 13247, upload-time = "2025-09-05T12:49:49.16Z" }, +] + +[[package]] +name = "shellingham" +version = "1.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "sse-starlette" +version = "3.4.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "starlette" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6c/10/a34c656829ffc1c4b22ef36d70d9ebb6b99c020e2aeb17cee5485099f028/sse_starlette-3.4.6.tar.gz", hash = "sha256:725f8a1bd6d26ae1b2c9610c0ef5065dfdd496f3988d28adcf8c4b49dc25c627", size = 32542, upload-time = "2026-07-20T14:16:32.201Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/36/e10c1d1b7ca881d2625db2ec28508578499187bb1c389952c398474e1834/sse_starlette-3.4.6-py3-none-any.whl", hash = "sha256:56217ab4c9a9f9c5db7b21e08732d3e7c2b807f45231ad23de0551a24c4a41f6", size = 16516, upload-time = "2026-07-20T14:16:30.978Z" }, +] + +[[package]] +name = "starlette" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/e3/7c1dc7381d9f8ab7d854328ebfa884e62cb3f3d8549ddfd37c7814f42afa/starlette-1.3.1.tar.gz", hash = "sha256:05d0213193f2fbaae60e2ecb593b4add4262ad4e46536b54abe36f11a71724e0", size = 2703240, upload-time = "2026-06-12T09:23:11.602Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl", hash = "sha256:c7372aae11c3c3f26a42df7bd626cec2f47d03483d261d369516a615a53714c6", size = 73632, upload-time = "2026-06-12T09:23:10.017Z" }, +] + +[[package]] +name = "sympy" +version = "1.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mpmath" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, +] + +[[package]] +name = "tenacity" +version = "9.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/47/c6/ee486fd809e357697ee8a44d3d69222b344920433d3b6666ccd9b374630c/tenacity-9.1.4.tar.gz", hash = "sha256:adb31d4c263f2bd041081ab33b498309a57c77f9acf2db65aadf0898179cf93a", size = 49413, upload-time = "2026-02-07T10:45:33.841Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl", hash = "sha256:6095a360c919085f28c6527de529e76a06ad89b23659fa881ae0649b867a9d55", size = 28926, upload-time = "2026-02-07T10:45:32.24Z" }, +] + +[[package]] +name = "tiktoken" +version = "0.13.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "regex" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e4/e5/5f3cb2159769d0f4324c0e9e87f9de3c4b1cd45848a96b2eb3566ad5ca77/tiktoken-0.13.0.tar.gz", hash = "sha256:c9435714c3a84c2319499de9a300c0e604449dd0799ff246458b3bb6a7f433c1", size = 38986, upload-time = "2026-05-15T04:51:27.153Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/8e/144bde4e01df66b34bb865557c7cd754ed08b036217ebd79c9db5e9048a9/tiktoken-0.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:32ac870a806cfb260a02d0cb70426aef02e038297f8ad50df5040bb5af360791", size = 1034888, upload-time = "2026-05-15T04:50:31.579Z" }, + { url = "https://files.pythonhosted.org/packages/36/18/d4ac9d20956cdebca04841316660ed584c2fecdc2b81722a28bc7ad3b1e4/tiktoken-0.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4d9980f11429ed2d737c463bb1fb78cf330caa026adf002f714aced7849a687b", size = 982970, upload-time = "2026-05-15T04:50:32.961Z" }, + { url = "https://files.pythonhosted.org/packages/74/ed/6bb8d05b9f731f749fee5c6f5ca63e981143c826a5985877330507bd13b7/tiktoken-0.13.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3f277ebea5edd7b8bf03c6f9431e1d67d517530115572b2dc1d465326e8f88c7", size = 1115741, upload-time = "2026-05-15T04:50:34.475Z" }, + { url = "https://files.pythonhosted.org/packages/34/de/2ca96b07a82d972b74fe4b46de055b79c904e45c7eab699354a0bfa697dc/tiktoken-0.13.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:a116178fa7e1b4065bff05214360373a65cac22f965be7b3f73d00a0dbfe7649", size = 1136523, upload-time = "2026-05-15T04:50:35.782Z" }, + { url = "https://files.pythonhosted.org/packages/ee/dc/9dafec002c2d4424378563cf4cf5c7fb93631d2a55013c8b87554ee4012c/tiktoken-0.13.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2c397ddda233208345b01bd30f2fca79ff730e55731d0108a603f9bc57f6af3b", size = 1181954, upload-time = "2026-05-15T04:50:36.99Z" }, + { url = "https://files.pythonhosted.org/packages/a1/d0/1f8578c45b2f24759b46f0b50d31878c63c73e6bf0f2227e10ec5c5408dc/tiktoken-0.13.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:95097e4f89b06403976e498abf61a0ee73a7497e73fb599cb211d8197a054d91", size = 1240069, upload-time = "2026-05-15T04:50:38.221Z" }, + { url = "https://files.pythonhosted.org/packages/aa/90/28d7f154888610aa9237e541986beb62b479df29d193a5a0617dbb1514d0/tiktoken-0.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:8f2d16e7a7c783ad81f36e457d046d1f1c8af70b22aec8a13238efe531977c41", size = 874748, upload-time = "2026-05-15T04:50:39.587Z" }, +] + +[[package]] +name = "tokenizers" +version = "0.22.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "huggingface-hub" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917", size = 372115, upload-time = "2026-01-05T10:45:15.988Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/97/5dbfabf04c7e348e655e907ed27913e03db0923abb5dfdd120d7b25630e1/tokenizers-0.22.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:544dd704ae7238755d790de45ba8da072e9af3eea688f698b137915ae959281c", size = 3100275, upload-time = "2026-01-05T10:41:02.158Z" }, + { url = "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1e418a55456beedca4621dbab65a318981467a2b188e982a23e117f115ce5001", size = 2981472, upload-time = "2026-01-05T10:41:00.276Z" }, + { url = "https://files.pythonhosted.org/packages/d6/84/7990e799f1309a8b87af6b948f31edaa12a3ed22d11b352eaf4f4b2e5753/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2249487018adec45d6e3554c71d46eb39fa8ea67156c640f7513eb26f318cec7", size = 3290736, upload-time = "2026-01-05T10:40:32.165Z" }, + { url = "https://files.pythonhosted.org/packages/78/59/09d0d9ba94dcd5f4f1368d4858d24546b4bdc0231c2354aa31d6199f0399/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25b85325d0815e86e0bac263506dd114578953b7b53d7de09a6485e4a160a7dd", size = 3168835, upload-time = "2026-01-05T10:40:38.847Z" }, + { url = "https://files.pythonhosted.org/packages/47/50/b3ebb4243e7160bda8d34b731e54dd8ab8b133e50775872e7a434e524c28/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfb88f22a209ff7b40a576d5324bf8286b519d7358663db21d6246fb17eea2d5", size = 3521673, upload-time = "2026-01-05T10:40:56.614Z" }, + { url = "https://files.pythonhosted.org/packages/e0/fa/89f4cb9e08df770b57adb96f8cbb7e22695a4cb6c2bd5f0c4f0ebcf33b66/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c774b1276f71e1ef716e5486f21e76333464f47bece56bbd554485982a9e03e", size = 3724818, upload-time = "2026-01-05T10:40:44.507Z" }, + { url = "https://files.pythonhosted.org/packages/64/04/ca2363f0bfbe3b3d36e95bf67e56a4c88c8e3362b658e616d1ac185d47f2/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df6c4265b289083bf710dff49bc51ef252f9d5be33a45ee2bed151114a56207b", size = 3379195, upload-time = "2026-01-05T10:40:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/2e/76/932be4b50ef6ccedf9d3c6639b056a967a86258c6d9200643f01269211ca/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:369cc9fc8cc10cb24143873a0d95438bb8ee257bb80c71989e3ee290e8d72c67", size = 3274982, upload-time = "2026-01-05T10:40:58.331Z" }, + { url = "https://files.pythonhosted.org/packages/1d/28/5f9f5a4cc211b69e89420980e483831bcc29dade307955cc9dc858a40f01/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:29c30b83d8dcd061078b05ae0cb94d3c710555fbb44861139f9f83dcca3dc3e4", size = 9478245, upload-time = "2026-01-05T10:41:04.053Z" }, + { url = "https://files.pythonhosted.org/packages/6c/fb/66e2da4704d6aadebf8cb39f1d6d1957df667ab24cff2326b77cda0dcb85/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:37ae80a28c1d3265bb1f22464c856bd23c02a05bb211e56d0c5301a435be6c1a", size = 9560069, upload-time = "2026-01-05T10:45:10.673Z" }, + { url = "https://files.pythonhosted.org/packages/16/04/fed398b05caa87ce9b1a1bb5166645e38196081b225059a6edaff6440fac/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:791135ee325f2336f498590eb2f11dc5c295232f288e75c99a36c5dbce63088a", size = 9899263, upload-time = "2026-01-05T10:45:12.559Z" }, + { url = "https://files.pythonhosted.org/packages/05/a1/d62dfe7376beaaf1394917e0f8e93ee5f67fea8fcf4107501db35996586b/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38337540fbbddff8e999d59970f3c6f35a82de10053206a7562f1ea02d046fa5", size = 10033429, upload-time = "2026-01-05T10:45:14.333Z" }, + { url = "https://files.pythonhosted.org/packages/fd/18/a545c4ea42af3df6effd7d13d250ba77a0a86fb20393143bbb9a92e434d4/tokenizers-0.22.2-cp39-abi3-win32.whl", hash = "sha256:a6bf3f88c554a2b653af81f3204491c818ae2ac6fbc09e76ef4773351292bc92", size = 2502363, upload-time = "2026-01-05T10:45:20.593Z" }, + { url = "https://files.pythonhosted.org/packages/65/71/0670843133a43d43070abeb1949abfdef12a86d490bea9cd9e18e37c5ff7/tokenizers-0.22.2-cp39-abi3-win_amd64.whl", hash = "sha256:c9ea31edff2968b44a88f97d784c2f16dc0729b8b143ed004699ebca91f05c48", size = 2747786, upload-time = "2026-01-05T10:45:18.411Z" }, + { url = "https://files.pythonhosted.org/packages/72/f4/0de46cfa12cdcbcd464cc59fde36912af405696f687e53a091fb432f694c/tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc", size = 2612133, upload-time = "2026-01-05T10:45:17.232Z" }, +] + +[[package]] +name = "tomli" +version = "2.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543, upload-time = "2026-03-25T20:22:03.828Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", size = 155924, upload-time = "2026-03-25T20:21:21.626Z" }, + { url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", size = 150018, upload-time = "2026-03-25T20:21:23.002Z" }, + { url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", size = 244948, upload-time = "2026-03-25T20:21:24.04Z" }, + { url = "https://files.pythonhosted.org/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", size = 253341, upload-time = "2026-03-25T20:21:25.177Z" }, + { url = "https://files.pythonhosted.org/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", size = 248159, upload-time = "2026-03-25T20:21:26.364Z" }, + { url = "https://files.pythonhosted.org/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", size = 253290, upload-time = "2026-03-25T20:21:27.46Z" }, + { url = "https://files.pythonhosted.org/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", size = 98141, upload-time = "2026-03-25T20:21:28.492Z" }, + { url = "https://files.pythonhosted.org/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", size = 108847, upload-time = "2026-03-25T20:21:29.386Z" }, + { url = "https://files.pythonhosted.org/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", size = 95088, upload-time = "2026-03-25T20:21:30.677Z" }, + { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" }, +] + +[[package]] +name = "tomli-w" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/19/75/241269d1da26b624c0d5e110e8149093c759b7a286138f4efd61a60e75fe/tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021", size = 7184, upload-time = "2025-01-15T12:07:24.262Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", size = 6675, upload-time = "2025-01-15T12:07:22.074Z" }, +] + +[[package]] +name = "tqdm" +version = "4.70.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/21/3b/6c24bec5be5e743ffd99576daa5cc077722fc7d5bbc00bd133fa0c698dc6/tqdm-4.70.0.tar.gz", hash = "sha256:55b0b0dbd97462d06ebee91e4dac24ed4d4702be82b24f07e6c1d27e08cea220", size = 795438, upload-time = "2026-07-27T11:33:15.271Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl", hash = "sha256:7f585706bfddbdebf89daac705b2dfcc16890130727d3197ca62c732b4310953", size = 80184, upload-time = "2026-07-27T11:33:13.167Z" }, +] + +[[package]] +name = "transformers" +version = "5.14.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "huggingface-hub" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "regex" }, + { name = "safetensors" }, + { name = "tokenizers" }, + { name = "tqdm" }, + { name = "typer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5a/fb/2a2ba88f325e68a921d8b69ff63b477830b2e73ade9a3c8c8cab2f06d741/transformers-5.14.1.tar.gz", hash = "sha256:60d196c27781eacf8637e2b533f517582907ad6f9ae142046d6b69431a5b2173", size = 9295927, upload-time = "2026-07-16T09:41:57.773Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/67/8d85ca2323233ae3c0365a659c4e52ee1f587b440e4bc577e7d8e4416d0f/transformers-5.14.1-py3-none-any.whl", hash = "sha256:9db974c4079ede2d1a3ea7ca5a240df33f2cc26fc2b36ba64c5f2a4f43b6e725", size = 11625234, upload-time = "2026-07-16T09:41:54.143Z" }, +] + +[[package]] +name = "typer" +version = "0.27.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-doc" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "rich" }, + { name = "shellingham" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/40/4a3db7990d1f62a53182aa96eaef57aeb2886a27f90a195bc66713565d31/typer-0.27.1.tar.gz", hash = "sha256:a79bef8469a79c45498e7b814ecf8d603cc7644e9acbd9e19cac0334240b18df", size = 203994, upload-time = "2026-08-03T14:41:03.438Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/89/9518bc0c3929bee36b3a4a8e3daddd6e03f92f9961c66d4983b837160543/typer-0.27.1-py3-none-any.whl", hash = "sha256:53150287edd11baeb4e4722c8e394fcdf8181c0ae89485cba8d25c778d5edd56", size = 122874, upload-time = "2026-08-03T14:41:04.391Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, +] + +[[package]] +name = "tzdata" +version = "2026.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/92/ff/5a28bdfd8c3ebec42564ac7d0e54ca3db65044a9314a97f9564fa7a1e926/tzdata-2026.3.tar.gz", hash = "sha256:4a1518b8993086a7982523e071643f3c0e5f213e75b21318e78bcabfff9d1415", size = 198674, upload-time = "2026-07-10T08:50:37.887Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/6d/b53b99a9f2766d095985947a5782f1702cabb129a34f7a802d7197af832f/tzdata-2026.3-py2.py3-none-any.whl", hash = "sha256:dc096730c87af6cab1b171c9d532be840741ff5d459015e7f6947bd7d7e54931", size = 348168, upload-time = "2026-07-10T08:50:36.46Z" }, +] + +[[package]] +name = "understudy-campaign-admission-smoke" +version = "0.0.0" +source = { virtual = "." } +dependencies = [ + { name = "verifiers" }, +] + +[package.metadata] +requires-dist = [{ name = "verifiers", git = "https://github.com/PrimeIntellect-ai/verifiers.git?rev=ab65b6e8d34b03d162408d4bcb854430a86809e6" }] + +[[package]] +name = "urllib3" +version = "2.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, +] + +[[package]] +name = "uvicorn" +version = "0.52.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/03/18/ccce41535dee1be77735592bd19965f3972c82e07ee703d324709496b716/uvicorn-0.52.1.tar.gz", hash = "sha256:112ec661814189acbccd3f7b86460147cc065fc92c0821afa78918780e4354dd", size = 100571, upload-time = "2026-08-01T18:19:30.732Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/d5/68e6e9bca63c0badf67002890a46d3784c958de45b65e1275ec583ca1f06/uvicorn-0.52.1-py3-none-any.whl", hash = "sha256:e4403f9d93188cf9d1088e9f40e3acd12630e2df8675316704379a7fc20fff6a", size = 79859, upload-time = "2026-08-01T18:19:29.294Z" }, +] + +[[package]] +name = "uvloop" +version = "0.22.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250, upload-time = "2025-10-16T22:17:19.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/ff/7f72e8170be527b4977b033239a83a68d5c881cc4775fca255c677f7ac5d/uvloop-0.22.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:fe94b4564e865d968414598eea1a6de60adba0c040ba4ed05ac1300de402cd42", size = 1359936, upload-time = "2025-10-16T22:16:29.436Z" }, + { url = "https://files.pythonhosted.org/packages/c3/c6/e5d433f88fd54d81ef4be58b2b7b0cea13c442454a1db703a1eea0db1a59/uvloop-0.22.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:51eb9bd88391483410daad430813d982010f9c9c89512321f5b60e2cddbdddd6", size = 752769, upload-time = "2025-10-16T22:16:30.493Z" }, + { url = "https://files.pythonhosted.org/packages/24/68/a6ac446820273e71aa762fa21cdcc09861edd3536ff47c5cd3b7afb10eeb/uvloop-0.22.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:700e674a166ca5778255e0e1dc4e9d79ab2acc57b9171b79e65feba7184b3370", size = 4317413, upload-time = "2025-10-16T22:16:31.644Z" }, + { url = "https://files.pythonhosted.org/packages/5f/6f/e62b4dfc7ad6518e7eff2516f680d02a0f6eb62c0c212e152ca708a0085e/uvloop-0.22.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b5b1ac819a3f946d3b2ee07f09149578ae76066d70b44df3fa990add49a82e4", size = 4426307, upload-time = "2025-10-16T22:16:32.917Z" }, + { url = "https://files.pythonhosted.org/packages/90/60/97362554ac21e20e81bcef1150cb2a7e4ffdaf8ea1e5b2e8bf7a053caa18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e047cc068570bac9866237739607d1313b9253c3051ad84738cbb095be0537b2", size = 4131970, upload-time = "2025-10-16T22:16:34.015Z" }, + { url = "https://files.pythonhosted.org/packages/99/39/6b3f7d234ba3964c428a6e40006340f53ba37993f46ed6e111c6e9141d18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:512fec6815e2dd45161054592441ef76c830eddaad55c8aa30952e6fe1ed07c0", size = 4296343, upload-time = "2025-10-16T22:16:35.149Z" }, +] + +[[package]] +name = "verifiers" +version = "0.2.1" +source = { git = "https://github.com/PrimeIntellect-ai/verifiers.git?rev=ab65b6e8d34b03d162408d4bcb854430a86809e6#ab65b6e8d34b03d162408d4bcb854430a86809e6" } +dependencies = [ + { name = "aiohttp" }, + { name = "aiolimiter" }, + { name = "anthropic" }, + { name = "datasets" }, + { name = "gepa" }, + { name = "httpx" }, + { name = "loguru" }, + { name = "math-verify" }, + { name = "mcp" }, + { name = "msgpack" }, + { name = "numpy" }, + { name = "openai" }, + { name = "openai-agents" }, + { name = "prime-pydantic-config", extra = ["toml"] }, + { name = "prime-sandboxes" }, + { name = "prime-tunnel" }, + { name = "pydantic" }, + { name = "pyzmq" }, + { name = "renderers" }, + { name = "requests" }, + { name = "rich" }, + { name = "setproctitle" }, + { name = "tenacity" }, + { name = "tomli-w" }, + { name = "typing-extensions" }, + { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, +] + +[[package]] +name = "websockets" +version = "16.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/21/f7/bc3a25c5ec26ce62ce487690becc2f3710bbc7b33338f005ad390db0b986/websockets-16.1.1.tar.gz", hash = "sha256:db234eda965dcce15df96bb9709f587cd87d4d52aaf0e80e2f34ec04c7670c57", size = 182204, upload-time = "2026-07-17T22:51:05.858Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/9d/681cda21c9eee743203a6cb79b9d3d05adad9aa60ec660c6c9bf4dd619ca/websockets-16.1.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:cc97814dfb786a83b6e2dc2e79351e1b83e6d715647d6887fcabd83026417a00", size = 179600, upload-time = "2026-07-17T22:49:13.92Z" }, + { url = "https://files.pythonhosted.org/packages/fb/8d/6195a88b45e8d2a8f745fc2046e36f885a3c9763e6767d2c46229bf9510c/websockets-16.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e047dc87ef7ca50f4d309bf775ad4a71711c58556d75d7bd0604b2317f43e94b", size = 177272, upload-time = "2026-07-17T22:49:15.453Z" }, + { url = "https://files.pythonhosted.org/packages/73/e3/fe2d498c64dea0095c9a9f9a351af4cd6eef31b618395582bc1f38ba45ff/websockets-16.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:01fbdcbac298efe19360b94bc0039c8f746f0220ba570f327577bfee81059175", size = 177542, upload-time = "2026-07-17T22:49:16.875Z" }, + { url = "https://files.pythonhosted.org/packages/fe/ed/f1831681fce0e3242346e5458486003c5f124ed69e5e0b847fd029db4973/websockets-16.1.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0f62863e8a00a6d33c3d6566ec0b89f23787b747ffe0c3bc71ec0e76b82c94b1", size = 187137, upload-time = "2026-07-17T22:49:18.323Z" }, + { url = "https://files.pythonhosted.org/packages/6f/79/4ff9dcc1bb46f6b4c536936dde1fd60f9b564f3304307274db97f4c9496d/websockets-16.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8087e82f842609734c9b5a1330464f8e94e346ba0e18c832c08bafa4b0d63c15", size = 188374, upload-time = "2026-07-17T22:49:19.65Z" }, + { url = "https://files.pythonhosted.org/packages/62/c3/5c49b6efb36cab733d23773f6de575e1dba65736ead17d5d2b2a1daef779/websockets-16.1.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2bb5d041a8307d2e18782e7ce777f6fdb1e8c2f5d09291484b18c294b789d9aa", size = 191155, upload-time = "2026-07-17T22:49:21.331Z" }, + { url = "https://files.pythonhosted.org/packages/6e/f6/56ccceda3a4838d18f1d40821480da4775397e8b1eecf4031e20c50e2e90/websockets-16.1.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1db4de4a0e95673f7545d393c49eeb0c2f18ac1ef93073218c79d5cdb2ee75ab", size = 189011, upload-time = "2026-07-17T22:49:22.889Z" }, + { url = "https://files.pythonhosted.org/packages/86/d6/ad5286241a2bce1107e2798d3bfbd62cf79aee167bdb654f8cb1e9dbf949/websockets-16.1.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f17dbe07eb3ea7f99e4df9b7e0efefe80fbf30d37a8cc4d561a0aed310bc8847", size = 187766, upload-time = "2026-07-17T22:49:24.339Z" }, + { url = "https://files.pythonhosted.org/packages/bc/67/d65c970b7e347fdca69479beb7811c2060529956730a7a4e3ae7c66b0e31/websockets-16.1.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4b57693728576d84ede0a77987ab16881b783d2cd9f1dc180a8fbbc3f79c4428", size = 185173, upload-time = "2026-07-17T22:49:25.743Z" }, + { url = "https://files.pythonhosted.org/packages/1d/5b/14af3cd4ee69d8ea9baca58f3dc3cfb1ba78332a347fd478cb096549d60e/websockets-16.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2a636ff1e7a5c4edf71ef0e79adae7f25dba93b4fcbe3dc958733477ffeb0eaf", size = 187809, upload-time = "2026-07-17T22:49:27.147Z" }, + { url = "https://files.pythonhosted.org/packages/7b/11/be301710d70de97e3e7b3586e6d492c9c06d6a61bf1c2202c36cf0c75607/websockets-16.1.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d6bec75c290fe484a8ba4cacdf838501e17c06ecfbbf31eede81a9e431bd7751", size = 186412, upload-time = "2026-07-17T22:49:28.611Z" }, + { url = "https://files.pythonhosted.org/packages/db/07/fe1435bf6fe738a3d3b54dbe0c18dabf12cba4d909ac8b58b539ce27c1f4/websockets-16.1.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:54509b8e92fee4453e152b7558ddef37ce9705a044922f2095a6105e3f80c96f", size = 188290, upload-time = "2026-07-17T22:49:29.965Z" }, + { url = "https://files.pythonhosted.org/packages/8a/0a/81f394aff8efcbb01208c1ced77df0a3c7fcce584a88c7273663697946c2/websockets-16.1.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:f0aa4aad3b1b69ad3fd85a0fd0952ec64331c762bd77ec51cc814170873890b2", size = 185844, upload-time = "2026-07-17T22:49:31.447Z" }, + { url = "https://files.pythonhosted.org/packages/39/5c/dd485b995473f415510251fe9bd708f2d24458f439fce958daf8d66dc7c6/websockets-16.1.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:42290eb6db4ccaca7012656738214f8514082fb6fa40cdeb61bb9a471b52e383", size = 186823, upload-time = "2026-07-17T22:49:33.104Z" }, + { url = "https://files.pythonhosted.org/packages/9d/0b/f78de76ff446f1e66af12b43c48a35f31744de93cfdec2f4ea67d5d7bbf1/websockets-16.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:53260c8930da5771cec89439bff99c20c8cb03ddb9588b980697355a83cd4bd3", size = 187102, upload-time = "2026-07-17T22:49:34.616Z" }, + { url = "https://files.pythonhosted.org/packages/37/a1/4cf892007778eaf84ad162bfc98046e0ed89b63ac55949e3236626b2a23f/websockets-16.1.1-cp312-cp312-win32.whl", hash = "sha256:1d27fa8462ad6a1cb36206a3d0640b2333340def181fae11ed7f9adeaa5c0747", size = 179943, upload-time = "2026-07-17T22:49:36.213Z" }, + { url = "https://files.pythonhosted.org/packages/d9/de/6abe251d28c3a3f217096575400b27750b18e0b1d2fff3a2a239960fea07/websockets-16.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:b436f6ec4fc3a6b4237c84d3f83170ed2b40bb584222f0ac47a0c8a5921980c7", size = 180243, upload-time = "2026-07-17T22:49:37.626Z" }, + { url = "https://files.pythonhosted.org/packages/be/4d/2d0d67834092e354d2b0498f014a41249a89556bc406cf86f3e1557bb463/websockets-16.1.1-py3-none-any.whl", hash = "sha256:6abbd3e82c731c8e531714466acd5d87b5e88ac3243465337ba71d68e23ae7e3", size = 173814, upload-time = "2026-07-17T22:51:04.184Z" }, +] + +[[package]] +name = "win32-setctime" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/8f/705086c9d734d3b663af0e9bb3d4de6578d08f46b1b101c2442fd9aecaa2/win32_setctime-1.2.0.tar.gz", hash = "sha256:ae1fdf948f5640aae05c511ade119313fb6a30d7eabe25fef9764dca5873c4c0", size = 4867, upload-time = "2024-12-07T15:28:28.314Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/07/c6fe3ad3e685340704d314d765b7912993bcb8dc198f0e7a89382d37974b/win32_setctime-1.2.0-py3-none-any.whl", hash = "sha256:95d644c4e708aba81dc3704a116d8cbc974d70b3bdb8be1d150e36be6e9d1390", size = 4083, upload-time = "2024-12-07T15:28:26.465Z" }, +] + +[[package]] +name = "xxhash" +version = "3.8.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/63/71aa56b151a1b28770037a61bd4e461c2619cfc8866a4fcaf1548605e325/xxhash-3.8.1.tar.gz", hash = "sha256:b0de4bf3aa66363552d52c6a89003c479911f12098cd48a53d44a0f7a25f7c46", size = 86223, upload-time = "2026-07-06T10:49:58.937Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/91/f65c34a7aa7b4e7cf4854f8e6ef3f7ee32ceac41d4f008da0780db0612f6/xxhash-3.8.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e6e49370822c1f4d8d90e678b06dbcb08b51a026a7c4b55479e7d467f2e813bc", size = 34680, upload-time = "2026-07-06T10:44:40.932Z" }, + { url = "https://files.pythonhosted.org/packages/57/04/b10a245a4c09a9cfa88f8e9ae755029413ad1ac17047f9a61906e5ae0799/xxhash-3.8.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:220d68130f83f7cc86d6edfdeab176adc73d7200bf3a8ec10c629e8cf605c215", size = 32397, upload-time = "2026-07-06T10:44:42.196Z" }, + { url = "https://files.pythonhosted.org/packages/3a/75/45ab795b5945b6388583bd75202106af505537935566c15a1577797a0e08/xxhash-3.8.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4d365ee1892c1fa803536f8c6ce21d24b29c9718ec75eb856095c07830f8c478", size = 220549, upload-time = "2026-07-06T10:44:43.603Z" }, + { url = "https://files.pythonhosted.org/packages/13/44/5ba2bd0a14ddf4193fc7d8ec29625f659f22c06d60b28f04bf46305d8330/xxhash-3.8.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:852bfe059720632e2f16a6a4745e41d20937b2bf2a42a401e2412046bb6971cc", size = 241186, upload-time = "2026-07-06T10:44:45.534Z" }, + { url = "https://files.pythonhosted.org/packages/23/32/c4147def4d1e4538b906f82731e0ba23424377fc50a7cddd03cd284c8f63/xxhash-3.8.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2f8c25a7061d952de589bd0ea0eaadee32378ff83dd6a677b267f9cd86f401f8", size = 264852, upload-time = "2026-07-06T10:44:47.199Z" }, + { url = "https://files.pythonhosted.org/packages/6c/bd/71ed14f4f0318bb7fd7b2ec51999413487fa8da8d41208e84d50d1ef0f98/xxhash-3.8.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:868a8dcaff1a84ba78038e1cef14fc88ccf84d9b4d12ea604696e0693296aa56", size = 242663, upload-time = "2026-07-06T10:44:48.846Z" }, + { url = "https://files.pythonhosted.org/packages/91/09/70af22c565a8473b3f2ae73f88e7721af281bc4a575236dbd1970c9f76f6/xxhash-3.8.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6536d8677d2fff7e64cd0b98b976df9de7aee0e69590044c2af5f51b76b7a170", size = 473510, upload-time = "2026-07-06T10:44:50.695Z" }, + { url = "https://files.pythonhosted.org/packages/18/96/34db781c8f0cf99c544ca1f2bc2e5bf55426e1eb4ca6de8ea5da56a9f352/xxhash-3.8.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:82c0cedd280eab2e8291270e6c04894dbc096f8159a39dcf1807429f026ca3cc", size = 220469, upload-time = "2026-07-06T10:44:52.422Z" }, + { url = "https://files.pythonhosted.org/packages/93/5f/9a184f615fa5a4dce30c01534f62946ce5a11ce40f73785cbd356ccabaa9/xxhash-3.8.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:daa86e4b68221d38e669bb236ba112d0335353829fb627c82e5909e4bbe8694c", size = 310290, upload-time = "2026-07-06T10:44:54.142Z" }, + { url = "https://files.pythonhosted.org/packages/a9/dc/9b9a9789011ee153723a5eb9e7dd7fcbae2ba9b3fe7a729249ca7c252056/xxhash-3.8.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2bc7113e6f2b6b3922dd61796ca9f36af09da3773898e7003038dc992fc83b8d", size = 238173, upload-time = "2026-07-06T10:44:55.693Z" }, + { url = "https://files.pythonhosted.org/packages/ec/4d/71c6005ada9dcb608a4e1902e8475ecadb5f3fbfa04e1e244d276a2d0c43/xxhash-3.8.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5eed32dad81d6ba8e62dc7b9ffa0500199385d7810a8dd9d4eafaceb8c6e20bb", size = 269026, upload-time = "2026-07-06T10:44:57.424Z" }, + { url = "https://files.pythonhosted.org/packages/2f/87/d6c036ba25dfbd9c8633be5aa86fc9474bbb9e2c68212a841d090abe7344/xxhash-3.8.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:83697b0ea1f10e7f5d8b26a4906fa851393c61546c63839643a2b7fe2d868061", size = 224970, upload-time = "2026-07-06T10:44:59.085Z" }, + { url = "https://files.pythonhosted.org/packages/48/62/4c1f035a41c5752aa05e195b6c904c07b94fe9061a16de61e72a6e6b135f/xxhash-3.8.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:36fc69160465ae75c6ec4ac9f781bb2aa16ae7ff869e73c26fee85fbb11b9887", size = 240820, upload-time = "2026-07-06T10:45:00.746Z" }, + { url = "https://files.pythonhosted.org/packages/da/14/d39d565069b87e86d21a2af2a31d04db79249d25aa8d5b62959056a89857/xxhash-3.8.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:445e0f5a31f2f3546ae0895d4811e159518cdc9d824c11419898d40cfadb677e", size = 300619, upload-time = "2026-07-06T10:45:02.716Z" }, + { url = "https://files.pythonhosted.org/packages/13/22/75467acc887edc8cf71c97ab1708feb3df7a88bda589b9f399765c6387d2/xxhash-3.8.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:dfe0580fbfd5e4af87d0cc52d2044f155d55ebd8c8a93568758a2ea7d8e15975", size = 443267, upload-time = "2026-07-06T10:45:04.653Z" }, + { url = "https://files.pythonhosted.org/packages/a4/b6/1da3baa5fa6ef705e3425fddd382be7dfc4dfba2686df90a20f16e9c7b1b/xxhash-3.8.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:095e1323fa108be1292c54c86da3ef3c7a7dc015b105a52133973bc07a6ad11a", size = 217338, upload-time = "2026-07-06T10:45:06.304Z" }, + { url = "https://files.pythonhosted.org/packages/78/dd/b5295a9f97484e7a1c2b283a742ca45e3104991c55a1ef670dde161829ba/xxhash-3.8.1-cp312-cp312-win32.whl", hash = "sha256:bf28f55e427e0483acb1f666bd0d869b6d5e5a716680c216ad7befe3d4cfba2e", size = 31970, upload-time = "2026-07-06T10:45:07.823Z" }, + { url = "https://files.pythonhosted.org/packages/ec/31/3fa0b807d7e21515cd975e7fe5c039d52ac3e9401a96d6ad68dae6305215/xxhash-3.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:2256e80e4960ee282f63428adb349cb7f8bd8efe4db770d88eb815f4b9860724", size = 32741, upload-time = "2026-07-06T10:45:09.42Z" }, + { url = "https://files.pythonhosted.org/packages/b8/05/86feada74e239600e6875aa507afb40482a89b92700aa74a92da83bdcb77/xxhash-3.8.1-cp312-cp312-win_arm64.whl", hash = "sha256:9df56e6df96a60590935e22373041cccc91fd55858763dcffb55bf63b3a2b396", size = 29234, upload-time = "2026-07-06T10:45:10.809Z" }, +] + +[[package]] +name = "yarl" +version = "1.24.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "multidict" }, + { name = "propcache" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/31/33/ebe9e3d1f86c7a0b51094c0a146392045ca1631d2664889539dec8088a33/yarl-1.24.5.tar.gz", hash = "sha256:e81b83143bee16329c23db3c1b2d82b29892fcbcb849186d2f6e98a5abe9a57f", size = 228679, upload-time = "2026-07-20T02:07:45.435Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/84/71d051c850b5af41d168c679d9eb67eb7c55283ac4ee131673edf134bc4e/yarl-1.24.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d693396e5aea78db03decd60aec9ece16c9b40ba00a587f089615ff4e718a81d", size = 136035, upload-time = "2026-07-20T02:05:25.489Z" }, + { url = "https://files.pythonhosted.org/packages/03/4d/8ad27f9a1b7e69313cca5d695b925b48efe51208d3490e0844bae97cabc0/yarl-1.24.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3363fcc96e665878946ad7a106b9a13eac0541766a690ef287c0232ac768b6ec", size = 97642, upload-time = "2026-07-20T02:05:27.429Z" }, + { url = "https://files.pythonhosted.org/packages/ea/b4/05b4131c407006cd1e410e9c6539f16a0945724677e5364447313c15ea3e/yarl-1.24.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9d399bdcfb4a0f659b9b3788bbc89babe63d9a6a65aacdf4d4e7065ff2e6316c", size = 97323, upload-time = "2026-07-20T02:05:29.441Z" }, + { url = "https://files.pythonhosted.org/packages/20/16/e618c875c73e0e39611f20a581b3d5e8d59b8857bf001bee3263044c6deb/yarl-1.24.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90333fd89b43c0d08ac85f3f1447593fc2c66de18c3d6378d7125ea118dc7a54", size = 107741, upload-time = "2026-07-20T02:05:31.367Z" }, + { url = "https://files.pythonhosted.org/packages/d9/9a/c4defeaf3ed33fcb346aacf9c6e971a8d4e2bde04a0310e79abb208e7965/yarl-1.24.5-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:665b0a2c463cc9423dd647e0bfd9f4ccc9b50f768c55304d5e9f80b177c1de12", size = 103570, upload-time = "2026-07-20T02:05:33.303Z" }, + { url = "https://files.pythonhosted.org/packages/5f/e7/0e0e0de5865ebd5914537ef486f36c727a59865c3ac0cf5ff1b32aececbf/yarl-1.24.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e006d3a974c4ee19512e5f058abedb6eef36a5e553c14812bdeba1758d812e6d", size = 115815, upload-time = "2026-07-20T02:05:35.292Z" }, + { url = "https://files.pythonhosted.org/packages/2b/27/ca56b700cb170aba25a3893b75355b213935657dc5714d2383354a270e62/yarl-1.24.5-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e7d42c531243450ef0d4d9c172e7ed6ef052640f195629065041b5add4e058d1", size = 116025, upload-time = "2026-07-20T02:05:37.503Z" }, + { url = "https://files.pythonhosted.org/packages/d6/d0/d56c859b8222116f5d68459199f48359e0bf121b6f65a69bf329b3602ba0/yarl-1.24.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f08c7513ecef5aad65687bfdf6bc601ae9fccd04a42904501f8f7141abad9eb9", size = 109835, upload-time = "2026-07-20T02:05:39.506Z" }, + { url = "https://files.pythonhosted.org/packages/70/a2/3a35557e4d1a79425040eba202ccaf08bdc8717680fc77e2498a1ad2e0a5/yarl-1.24.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6c95b17fe34ed802f17e205112e6e10db92275c34fee290aa9bdc55a9c724027", size = 108884, upload-time = "2026-07-20T02:05:41.584Z" }, + { url = "https://files.pythonhosted.org/packages/e4/35/ef4c26356b7913c68983bac2d72a4212b3347af551cb8d250b99b5ed7b7f/yarl-1.24.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:56b149b22de33b23b0c6077ab9518c6dcb538ad462e1830e68d06591ccf6e38b", size = 107308, upload-time = "2026-07-20T02:05:43.697Z" }, + { url = "https://files.pythonhosted.org/packages/d5/91/ff0dc66c2ccf3e0153ab97ff61eabab4400e6a5264af427ab30cd69f1857/yarl-1.24.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a8fe66b8f300da93798025a785a5b90b42f3810dc2b72283ff84a41aaaebc293", size = 103646, upload-time = "2026-07-20T02:05:45.895Z" }, + { url = "https://files.pythonhosted.org/packages/74/f0/33b9271c7f881766359d58266fa0811d2e5210ed860e28da7dc6d7786344/yarl-1.24.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:377fe3732edbaf78ee74efdf2c9f49f6e99f20e7f9d2649fda3eb4badd77d76e", size = 115305, upload-time = "2026-07-20T02:05:47.832Z" }, + { url = "https://files.pythonhosted.org/packages/ef/65/fd79fb1868c4a80db8661091de525bf430f63c3bea1b20e8b6a84fc7d359/yarl-1.24.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e8ffa78582120024f476a611d7befc123cee59e47e8309d470cf667d806e613b", size = 108404, upload-time = "2026-07-20T02:05:49.604Z" }, + { url = "https://files.pythonhosted.org/packages/ff/ba/dbabe6b262f17a816c70cfc09558dbf03ece3ec76684d02f911a3d3a189c/yarl-1.24.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:daba5e594f06114e37db186efd2dd916609071e59daca901a0a2e71f02b142ce", size = 115940, upload-time = "2026-07-20T02:05:51.741Z" }, + { url = "https://files.pythonhosted.org/packages/a5/43/fab2d1dad9d340a268cdde63756a123d069723efff6a372d123fa74a9517/yarl-1.24.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:65be18ec59496c13908f02a2472751d9ef840b4f3fb5726f129306bf6a2a7bba", size = 110006, upload-time = "2026-07-20T02:05:53.554Z" }, + { url = "https://files.pythonhosted.org/packages/c4/27/41eb51bbd1b8d89546b83897cfb0164f1e109304fd408dbb151b639eec0f/yarl-1.24.5-cp312-cp312-win_amd64.whl", hash = "sha256:a929d878fec099030c292803b31e5d5540a7b6a31e6a3cc76cb4685fc2a2f51b", size = 97618, upload-time = "2026-07-20T02:05:55.57Z" }, + { url = "https://files.pythonhosted.org/packages/3c/25/b2553764b3d65db711d8f45416351ec4f420847558eb669edcbcaadf5780/yarl-1.24.5-cp312-cp312-win_arm64.whl", hash = "sha256:7ce27823052e2013b597e0c738b13e7e36b8ccb9400df8959417b052ab0fd92c", size = 93018, upload-time = "2026-07-20T02:05:57.554Z" }, + { url = "https://files.pythonhosted.org/packages/61/02/962c1cbfc401a30c1d034dc67ff395f64b52302c6d62de556c1fca99acc0/yarl-1.24.5-py3-none-any.whl", hash = "sha256:a33700d13d9b7d84fd10947b09ff69fb9a792e519c8cb9764a3ca70baa6c23a7", size = 58612, upload-time = "2026-07-20T02:07:43.461Z" }, +] diff --git a/tests/fixtures/campaign-admission/verifiers-0.2.1-one-task-trace.json b/tests/fixtures/campaign-admission/verifiers-0.2.1-one-task-trace.json new file mode 100644 index 00000000..ac88445d --- /dev/null +++ b/tests/fixtures/campaign-admission/verifiers-0.2.1-one-task-trace.json @@ -0,0 +1,16 @@ +{ + "runtime": "standard-verifiers", + "verifiers_version": "0.2.1", + "task": { "data": { "task_id": "public-synthetic-mutation-1", "split": "train" } }, + "rewards": { "assertion_fraction": 1.0 }, + "metrics": { "assertion_fraction": 1.0 }, + "errors": [], + "ok": true, + "calls": [{ "node": 2, "model": "synthetic-local", "endpoint": "/chat/completions", "finish_reason": "tool_calls" }], + "nodes": [ + { "message": { "role": "system", "content": "Operate only on the public synthetic record." }, "sampled": false }, + { "parent": 0, "message": { "role": "user", "content": "Set synthetic record alpha to ready." }, "sampled": false }, + { "parent": 1, "message": { "role": "assistant", "tool_calls": [{ "id": "call-public-1", "name": "world_toolset_set-record", "arguments": "{\"id\":\"alpha\",\"status\":\"ready\"}" }] }, "sampled": true }, + { "parent": 2, "message": { "role": "tool", "tool_call_id": "call-public-1", "name": "world_toolset_set-record", "content": "{\"ok\":true,\"applied\":true}" }, "sampled": false } + ] +} From cb4c5475e3cb5b565a6f71f117ce5d9bebae5d21 Mon Sep 17 00:00:00 2001 From: luis manrique <166242911+lluisinthedesert@users.noreply.github.com> Date: Tue, 4 Aug 2026 04:58:50 -0700 Subject: [PATCH 2/8] strengthen campaign admission evidence --- package-lock.json | 1 + package.json | 5 +- ...derstudy.campaign_admission.v1.schema.json | 41 +++- src/campaign-admission/index.ts | 220 +++++++++++++++++- src/commands/campaigns.ts | 15 +- src/index.ts | 3 + tests/campaign-admission-cli.test.mjs | 52 ++--- tests/campaign-admission.test.mjs | 148 +++++------- .../fixtures/campaign-admission/request.json | 2 +- .../fixtures/campaign-admission/response.json | 2 +- .../uv-project/.python-version | 1 + .../uv-project/generate_smoke.py | 103 ++++++++ .../uv-project/generated/after-state.json | 7 + .../uv-project/generated/before-state.json | 7 + .../generated/execution-receipt.json | 33 +++ .../uv-project/generated/trace.json | 72 ++++++ .../verifiers-0.2.1-one-task-trace.json | 16 -- tests/helpers/campaign-admission-fixture.mjs | 28 +++ 18 files changed, 598 insertions(+), 158 deletions(-) create mode 100644 tests/fixtures/campaign-admission/uv-project/.python-version create mode 100755 tests/fixtures/campaign-admission/uv-project/generate_smoke.py create mode 100644 tests/fixtures/campaign-admission/uv-project/generated/after-state.json create mode 100644 tests/fixtures/campaign-admission/uv-project/generated/before-state.json create mode 100644 tests/fixtures/campaign-admission/uv-project/generated/execution-receipt.json create mode 100644 tests/fixtures/campaign-admission/uv-project/generated/trace.json delete mode 100644 tests/fixtures/campaign-admission/verifiers-0.2.1-one-task-trace.json create mode 100644 tests/helpers/campaign-admission-fixture.mjs diff --git a/package-lock.json b/package-lock.json index 913b2e25..5e834d4f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@inquirer/prompts": "^8.4.3", "@modelcontextprotocol/sdk": "1.29.0", "ai": "6.0.224", + "ajv": "8.20.0", "commander": "^14.0.3", "kleur": "^4.1.5", "openai": "^6.42.0", diff --git a/package.json b/package.json index 5b712466..36d5fc0c 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "@inquirer/prompts": "^8.4.3", "@modelcontextprotocol/sdk": "1.29.0", "ai": "6.0.224", + "ajv": "8.20.0", "commander": "^14.0.3", "kleur": "^4.1.5", "openai": "^6.42.0", @@ -69,8 +70,8 @@ "devDependencies": { "@types/json-schema": "7.0.15", "@types/node": "^24.3.0", - "undici-types": "7.16.0", - "typescript": "^5.7.3" + "typescript": "^5.7.3", + "undici-types": "7.16.0" }, "engines": { "node": ">=22.19.0" diff --git a/schemas/understudy.campaign_admission.v1.schema.json b/schemas/understudy.campaign_admission.v1.schema.json index 0e8bd3db..5aa6d3e2 100644 --- a/schemas/understudy.campaign_admission.v1.schema.json +++ b/schemas/understudy.campaign_admission.v1.schema.json @@ -5,12 +5,15 @@ "description": "Public, fail-closed campaign admission evidence. References and hashes only; never embeds customer prompts, traces, credentials, or answer keys.", "type": "object", "additionalProperties": false, - "required": ["schema_version", "campaign_id", "environment", "transport_fingerprints", "mutation_smoke", "spend"], + "required": ["schema_version", "campaign_id", "environment", "transport_fingerprints", "tool_steps", "payload_parity", "workload_contract", "mutation_smoke", "spend"], "properties": { "schema_version": { "const": "understudy.campaign_admission.v1" }, "campaign_id": { "type": "string", "minLength": 1 }, "environment": { "$ref": "#/$defs/environment" }, "transport_fingerprints": { "$ref": "#/$defs/fingerprints" }, + "tool_steps": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/tool_step" } }, + "payload_parity": { "$ref": "#/$defs/payload_parity" }, + "workload_contract": { "$ref": "#/$defs/workload_contract" }, "mutation_smoke": { "$ref": "#/$defs/mutation_smoke" }, "spend": { "$ref": "#/$defs/spend" } }, @@ -43,23 +46,44 @@ }, "fingerprints": { "type": "object", "additionalProperties": false, - "required": ["raw_request_sha256", "semantic_request_sha256", "raw_response_sha256", "semantic_response_sha256", "raw_tools_sha256", "semantic_tools_sha256"], + "required": ["raw_request_sha256", "semantic_request_sha256", "raw_response_sha256", "semantic_response_sha256", "raw_tools_sha256", "semantic_tools_sha256", "raw_trace_sha256", "semantic_trace_sha256"], "properties": { "raw_request_sha256": { "$ref": "#/$defs/sha256" }, "semantic_request_sha256": { "$ref": "#/$defs/sha256" }, "raw_response_sha256": { "$ref": "#/$defs/sha256" }, "semantic_response_sha256": { "$ref": "#/$defs/sha256" }, - "raw_tools_sha256": { "$ref": "#/$defs/sha256" }, "semantic_tools_sha256": { "$ref": "#/$defs/sha256" } + "raw_tools_sha256": { "$ref": "#/$defs/sha256" }, "semantic_tools_sha256": { "$ref": "#/$defs/sha256" }, + "raw_trace_sha256": { "$ref": "#/$defs/sha256" }, "semantic_trace_sha256": { "$ref": "#/$defs/sha256" } } }, + "tool_step": { + "type": "object", "additionalProperties": false, + "required": ["call_id_sha256", "normalized_tool_name_sha256", "tool_class", "response_raw_arguments_sha256", "response_semantic_arguments_sha256", "trace_call_raw_arguments_sha256", "trace_call_semantic_arguments_sha256", "trace_result_raw_sha256", "trace_result_semantic_sha256", "trace_call_result_pair_sha256", "raw_arguments_equal", "semantic_arguments_equal", "mutation"], + "properties": { + "call_id_sha256": { "$ref": "#/$defs/sha256" }, "normalized_tool_name_sha256": { "$ref": "#/$defs/sha256" }, + "tool_class": { "enum": ["mutation", "observation"] }, + "response_raw_arguments_sha256": { "$ref": "#/$defs/sha256" }, "response_semantic_arguments_sha256": { "$ref": "#/$defs/sha256" }, + "trace_call_raw_arguments_sha256": { "$ref": "#/$defs/sha256" }, "trace_call_semantic_arguments_sha256": { "$ref": "#/$defs/sha256" }, + "trace_result_raw_sha256": { "$ref": "#/$defs/sha256" }, "trace_result_semantic_sha256": { "$ref": "#/$defs/sha256" }, "trace_call_result_pair_sha256": { "$ref": "#/$defs/sha256" }, + "raw_arguments_equal": { "type": "boolean" }, "semantic_arguments_equal": { "const": true }, "mutation": { "type": "boolean" } + } + }, + "payload_parity": { + "type": "object", "additionalProperties": false, "required": ["messages_sha256", "tools_sha256", "sampling_sha256", "context_overflow_behavior"], + "properties": { "messages_sha256": { "$ref": "#/$defs/sha256" }, "tools_sha256": { "$ref": "#/$defs/sha256" }, "sampling_sha256": { "$ref": "#/$defs/sha256" }, "context_overflow_behavior": { "const": "fail" } } + }, + "workload_contract": { + "type": "object", "additionalProperties": false, "required": ["benchmark_prompt_sha256", "candidate_source", "candidate_tag_sha256", "policy_injection_count", "mcp_version", "tool_schema_sha256", "package_inventory_sha256"], + "properties": { "benchmark_prompt_sha256": { "$ref": "#/$defs/sha256" }, "candidate_source": { "const": "outer_system_transcript" }, "candidate_tag_sha256": { "$ref": "#/$defs/sha256" }, "policy_injection_count": { "const": 1 }, "mcp_version": { "const": "1.29.0" }, "tool_schema_sha256": { "$ref": "#/$defs/sha256" }, "package_inventory_sha256": { "$ref": "#/$defs/sha256" } } + }, "mutation_smoke": { "type": "object", "additionalProperties": false, - "required": ["runtime", "verifiers_version", "task_count", "calls", "nodes", "assertion_fraction", "seed_candidate_sha256", "mutated_candidate_sha256", "eval_exit_code", "trace_artifact_sha256", "mutating_effects"], + "required": ["runtime", "verifiers_version", "task_count", "calls", "nodes", "assertion_fraction", "seed_candidate_sha256", "mutated_candidate_sha256", "eval_exit_code", "trace_artifact_sha256", "execution_receipt_sha256", "mutating_effects"], "properties": { "runtime": { "const": "standard-verifiers" }, "verifiers_version": { "const": "0.2.1" }, "task_count": { "const": 1 }, "calls": { "type": "integer", "minimum": 1 }, "nodes": { "type": "integer", "minimum": 1 }, "assertion_fraction": { "type": "number", "exclusiveMinimum": 0, "maximum": 1 }, "seed_candidate_sha256": { "$ref": "#/$defs/sha256" }, "mutated_candidate_sha256": { "$ref": "#/$defs/sha256" }, - "eval_exit_code": { "const": 0 }, "trace_artifact_sha256": { "$ref": "#/$defs/sha256" }, - "mutating_effects": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["tool", "applied"], "properties": { "tool": { "type": "string", "minLength": 1 }, "applied": { "const": true } } } + "eval_exit_code": { "const": 0 }, "trace_artifact_sha256": { "$ref": "#/$defs/sha256" }, "execution_receipt_sha256": { "$ref": "#/$defs/sha256" }, + "mutating_effects": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["tool", "applied"], "properties": { "tool": { "type": "string", "minLength": 1 }, "applied": { "const": true } } } } } }, "allocation": { "type": "object", "additionalProperties": false, "required": ["cap_usd"], "properties": { "cap_usd": { "type": "number", "minimum": 0 } } }, @@ -72,10 +96,11 @@ "properties": { "charge_id": { "type": "string", "minLength": 1 }, "lane": { "enum": ["optimizer", "endpoint", "training"] }, "amount_usd": { "type": "number", "minimum": 0 }, "immutable_receipt_sha256": { "$ref": "#/$defs/sha256" } } }, "spend": { - "type": "object", "additionalProperties": false, "required": ["campaign_total_usd", "allocations", "transfers", "charges"], + "type": "object", "additionalProperties": false, "required": ["campaign_total_usd", "prior_spend_usd", "allocations", "transfers", "charges"], "properties": { "campaign_total_usd": { "type": "number", "minimum": 0 }, - "allocations": { "type": "object", "additionalProperties": false, "required": ["optimizer", "endpoint", "training"], "properties": { "optimizer": { "$ref": "#/$defs/allocation" }, "endpoint": { "$ref": "#/$defs/allocation" }, "training": { "$ref": "#/$defs/allocation" } }, + "prior_spend_usd": { "type": "number", "minimum": 0 }, + "allocations": { "type": "object", "additionalProperties": false, "required": ["optimizer", "endpoint", "training"], "properties": { "optimizer": { "$ref": "#/$defs/allocation" }, "endpoint": { "$ref": "#/$defs/allocation" }, "training": { "$ref": "#/$defs/allocation" } } }, "transfers": { "type": "array", "items": { "$ref": "#/$defs/transfer" } }, "charges": { "type": "array", "items": { "$ref": "#/$defs/charge" } } } diff --git a/src/campaign-admission/index.ts b/src/campaign-admission/index.ts index 3566241a..0dcfe10e 100644 --- a/src/campaign-admission/index.ts +++ b/src/campaign-admission/index.ts @@ -1,5 +1,6 @@ import { createHash } from "node:crypto"; import { readFileSync } from "node:fs"; +import { createRequire } from "node:module"; export const CAMPAIGN_ADMISSION_SCHEMA_VERSION = "understudy.campaign_admission.v1" as const; export const SPEND_LANES = ["optimizer", "endpoint", "training"] as const; @@ -12,6 +13,9 @@ export type TransportArtifacts = { response: Buffer; tools: Buffer; trace: Buffer; + executionReceipt: Buffer; + beforeState: Buffer; + afterState: Buffer; }; export type TransportFingerprints = { @@ -21,13 +25,35 @@ export type TransportFingerprints = { semantic_response_sha256: string; raw_tools_sha256: string; semantic_tools_sha256: string; + raw_trace_sha256: string; + semantic_trace_sha256: string; +}; + +export type ToolStepFingerprint = { + call_id_sha256: string; + normalized_tool_name_sha256: string; + tool_class: "mutation" | "observation"; + response_raw_arguments_sha256: string; + response_semantic_arguments_sha256: string; + trace_call_raw_arguments_sha256: string; + trace_call_semantic_arguments_sha256: string; + trace_result_raw_sha256: string; + trace_result_semantic_sha256: string; + trace_call_result_pair_sha256: string; + raw_arguments_equal: boolean; + semantic_arguments_equal: boolean; + mutation: boolean; }; export type AdmissionResult = { + admission_only: true; + compile_authorized: false; admitted: boolean; errors: string[]; fingerprints: TransportFingerprints; + tool_steps: ToolStepFingerprint[]; effective_spend_caps_usd: Record; + cumulative_spend_usd: number; }; export type ResolvedPackagePin = { name: string; version: string; git_revision?: string }; @@ -39,6 +65,10 @@ const SHA256 = /^[a-f0-9]{64}$/; const EXACT_VERSION = /^[0-9][0-9A-Za-z.!+_-]*$/; const GIT_REVISION = /^[a-f0-9]{40}$/; const IMAGE_DIGEST = /^sha256:[a-f0-9]{64}$/; +const require = createRequire(import.meta.url); +const Ajv2020 = require("ajv/dist/2020").default as new (options: Record) => { compile: (schema: unknown) => ((value: unknown) => boolean) & { errors?: { instancePath: string; message?: string; keyword: string }[] | null } }; +const publishedSchema = JSON.parse(readFileSync(new URL("../../schemas/understudy.campaign_admission.v1.schema.json", import.meta.url), "utf8")); +const validateSchema = new Ajv2020({ allErrors: true, strict: true }).compile(publishedSchema); export function sha256Bytes(value: Uint8Array): string { return createHash("sha256").update(value).digest("hex"); @@ -71,9 +101,101 @@ export function fingerprintTransport(artifacts: TransportArtifacts): TransportFi semantic_response_sha256: semanticJsonSha256(artifacts.response, "response"), raw_tools_sha256: sha256Bytes(artifacts.tools), semantic_tools_sha256: semanticJsonSha256(artifacts.tools, "tools"), + raw_trace_sha256: sha256Bytes(artifacts.trace), + semantic_trace_sha256: semanticJsonSha256(artifacts.trace, "trace"), }; } +function parseObjectJsonString(value: unknown, label: string): { raw: string; decoded: JsonObject; raw_sha256: string; semantic_sha256: string } { + if (typeof value !== "string") throw new Error(`${label} arguments must be an exact JSON string on the wire`); + let decoded: unknown; + try { decoded = JSON.parse(value); } catch { throw new Error(`${label} arguments must be valid JSON`); } + if (decoded === null || typeof decoded !== "object" || Array.isArray(decoded)) throw new Error(`${label} arguments must decode to an object`); + return { raw: value, decoded: decoded as JsonObject, raw_sha256: sha256Bytes(Buffer.from(value)), semantic_sha256: sha256Bytes(Buffer.from(canonicalize(decoded))) }; +} + +function normalizedToolName(value: unknown, label: string): string { + if (typeof value !== "string" || value.length === 0) throw new Error(`${label} tool name is required`); + return value.replace(/^world_toolset_/, "").trim().toLowerCase(); +} + +export function fingerprintToolSteps(artifacts: TransportArtifacts): ToolStepFingerprint[] { + const response = object(JSON.parse(artifacts.response.toString("utf8"))); + const traceValue = JSON.parse(artifacts.trace.toString("utf8")); + const traces = Array.isArray(traceValue) ? traceValue : [traceValue]; + if (traces.length !== 1) throw new Error("tool transport requires exactly one Verifiers trace"); + const trace = object(traces[0]); + + const responseCalls: JsonObject[] = []; + for (const choice of (Array.isArray(response.choices) ? response.choices : []).map(object)) { + const message = object(choice.message); + for (const call of (Array.isArray(message.tool_calls) ? message.tool_calls : []).map(object)) responseCalls.push(call); + } + if (responseCalls.length === 0) throw new Error("response contains no sampled tool calls"); + + const traceCalls = new Map }>(); + const traceResults = new Map(); + for (const node of (Array.isArray(trace.nodes) ? trace.nodes : []).map(object)) { + const message = object(node.message); + if (message.role === "assistant" && node.sampled === true) { + for (const call of (Array.isArray(message.tool_calls) ? message.tool_calls : []).map(object)) { + const id = call.id; + if (typeof id !== "string" || id.length === 0) throw new Error("sampled trace call id is required"); + if (traceCalls.has(id)) throw new Error(`duplicate sampled trace call id hash ${sha256Bytes(Buffer.from(id))}`); + const fn = object(call.function); + traceCalls.set(id, { name: normalizedToolName(call.name ?? fn.name, "trace call"), arguments: parseObjectJsonString(call.arguments ?? fn.arguments, "trace call") }); + } + } + if (message.role === "tool") { + const id = message.tool_call_id; + if (typeof id !== "string" || id.length === 0) throw new Error("trace tool result call id is required"); + if (traceResults.has(id)) throw new Error(`duplicate trace result id hash ${sha256Bytes(Buffer.from(id))}`); + if (typeof message.content !== "string") throw new Error("trace result content must be a JSON string"); + let decoded: unknown; + try { decoded = JSON.parse(message.content); } catch { throw new Error("trace result content must be valid JSON"); } + if (decoded === null || typeof decoded !== "object" || Array.isArray(decoded)) throw new Error("trace result content must decode to an object"); + traceResults.set(id, { name: normalizedToolName(message.name, "trace result"), raw: message.content, semantic_sha256: sha256Bytes(Buffer.from(canonicalize(decoded))), mutation: object(decoded).applied === true }); + } + } + + const seenResponseIds = new Set(); + const steps = responseCalls.map((call): ToolStepFingerprint => { + const id = call.id; + if (typeof id !== "string" || id.length === 0) throw new Error("response tool call id is required"); + if (seenResponseIds.has(id)) throw new Error(`duplicate response tool call id hash ${sha256Bytes(Buffer.from(id))}`); + seenResponseIds.add(id); + const fn = object(call.function); + const responseName = normalizedToolName(call.name ?? fn.name, "response call"); + const responseArguments = parseObjectJsonString(call.arguments ?? fn.arguments, "response call"); + const executedCall = traceCalls.get(id); + const executedResult = traceResults.get(id); + if (!executedCall) throw new Error(`missing executed trace call for response id hash ${sha256Bytes(Buffer.from(id))}`); + if (!executedResult) throw new Error(`missing executed trace result for response id hash ${sha256Bytes(Buffer.from(id))}`); + if (responseName !== executedCall.name || responseName !== executedResult.name) throw new Error(`tool name mismatch for call id hash ${sha256Bytes(Buffer.from(id))}`); + const rawEqual = responseArguments.raw === executedCall.arguments.raw; + const semanticEqual = responseArguments.semantic_sha256 === executedCall.arguments.semantic_sha256; + if (!semanticEqual) throw new Error(`semantic argument mismatch for call id hash ${sha256Bytes(Buffer.from(id))}`); + const resultRawSha = sha256Bytes(Buffer.from(executedResult.raw)); + return { + call_id_sha256: sha256Bytes(Buffer.from(id)), + normalized_tool_name_sha256: sha256Bytes(Buffer.from(responseName)), + tool_class: executedResult.mutation ? "mutation" : "observation", + response_raw_arguments_sha256: responseArguments.raw_sha256, + response_semantic_arguments_sha256: responseArguments.semantic_sha256, + trace_call_raw_arguments_sha256: executedCall.arguments.raw_sha256, + trace_call_semantic_arguments_sha256: executedCall.arguments.semantic_sha256, + trace_result_raw_sha256: resultRawSha, + trace_result_semantic_sha256: executedResult.semantic_sha256, + trace_call_result_pair_sha256: sha256Bytes(Buffer.from(`${sha256Bytes(Buffer.from(id))}:${sha256Bytes(Buffer.from(responseName))}:${executedCall.arguments.raw_sha256}:${resultRawSha}`)), + raw_arguments_equal: rawEqual, + semantic_arguments_equal: semanticEqual, + mutation: executedResult.mutation, + }; + }); + if (traceCalls.size !== responseCalls.length || traceResults.size !== responseCalls.length) throw new Error("every sampled response call must pair with exactly one trace call and result"); + return steps; +} + export function parseUvLockPins(lockText: string): ResolvedPackagePin[] { return lockText.split(/^\[\[package\]\]\s*$/m).slice(1).map((block) => { const name = block.match(/^name = "([^"]+)"$/m)?.[1]; @@ -84,6 +206,77 @@ export function parseUvLockPins(lockText: string): ResolvedPackagePin[] { }).sort((left, right) => left.name.localeCompare(right.name) || left.version.localeCompare(right.version)); } +export function publishedSchemaErrors(value: unknown): string[] { + if (validateSchema(value)) return []; + return (validateSchema.errors ?? []).map((error: { instancePath: string; message?: string; keyword: string }) => `schema${error.instancePath || "/"}: ${error.message ?? error.keyword}`); +} + +function validateExecutionReceipt(manifest: JsonObject, artifacts: TransportArtifacts, errors: string[]): void { + let receipt: JsonObject; + let before: JsonObject; + let after: JsonObject; + try { + receipt = object(JSON.parse(artifacts.executionReceipt.toString("utf8"))); + before = object(JSON.parse(artifacts.beforeState.toString("utf8"))); + after = object(JSON.parse(artifacts.afterState.toString("utf8"))); + } catch { errors.push("execution receipt and state artifacts must be valid JSON objects"); return; } + const smoke = object(manifest.mutation_smoke); + if (smoke.execution_receipt_sha256 !== sha256Bytes(artifacts.executionReceipt)) errors.push("mutation_smoke.execution_receipt_sha256 does not match supplied receipt"); + if (receipt.schema_version !== "understudy.synthetic_verifiers_execution.v1") errors.push("synthetic execution receipt schema is invalid"); + const argv = receipt.argv; + if (canonicalize(argv) !== canonicalize(["uv", "run", "--project", ".", "--locked", "python", "generate_smoke.py", "--output", "generated"])) errors.push("synthetic smoke must use exact locked-project uv argv"); + if (Array.isArray(argv) && argv.includes("--no-project")) errors.push("synthetic smoke cannot use --no-project"); + const interpreter = object(receipt.interpreter); + if (interpreter.implementation !== "CPython" || interpreter.version !== object(manifest.environment).python_version) errors.push("execution receipt interpreter does not match the admitted project"); + if (receipt.resolved_package_inventory_sha256 !== object(manifest.environment).uv_lock_sha256) errors.push("execution receipt package inventory is not bound to uv.lock"); + if (object(receipt.verifiers).version !== "0.2.1") errors.push("execution receipt did not run Verifiers 0.2.1"); + if (receipt.trace_sha256 !== sha256Bytes(artifacts.trace)) errors.push("execution receipt does not bind the supplied trace"); + if (receipt.before_state_sha256 !== sha256Bytes(artifacts.beforeState) || receipt.after_state_sha256 !== sha256Bytes(artifacts.afterState)) errors.push("execution receipt does not bind before/after state"); + if (receipt.seed_candidate_sha256 !== smoke.seed_candidate_sha256 || receipt.mutated_candidate_sha256 !== smoke.mutated_candidate_sha256) errors.push("candidate hashes are not bound to generated inputs"); + const delta = object(receipt.verified_state_delta); + if (delta.path !== "/records/alpha/status" || delta.before !== "pending" || delta.after !== "ready") errors.push("execution receipt does not verify the required state delta"); + if (object(object(before.records).alpha).status !== "pending" || object(object(after.records).alpha).status !== "ready") errors.push("before/after state artifacts do not contain the verified mutation"); +} + +function validatePayloadParity(manifest: JsonObject, artifacts: TransportArtifacts, errors: string[]): void { + let request: JsonObject; + let trace: JsonObject; + try { request = object(JSON.parse(artifacts.request.toString("utf8"))); trace = object(JSON.parse(artifacts.trace.toString("utf8"))); } + catch { errors.push("payload parity artifacts must be valid JSON"); return; } + const parity = object(manifest.payload_parity); + const calls = Array.isArray(trace.calls) ? trace.calls.map(object) : []; + const call = calls[0] ?? {}; + const requestMessages = request.messages; + const requestSampling = object(request.sampling); + const requestTools = JSON.parse(artifacts.tools.toString("utf8")); + const messagesHash = sha256Bytes(Buffer.from(canonicalize(requestMessages))); + const toolsHash = sha256Bytes(Buffer.from(canonicalize(requestTools))); + const samplingHash = sha256Bytes(Buffer.from(canonicalize(requestSampling))); + if (parity.messages_sha256 !== messagesHash || call.messages_sha256 !== messagesHash) errors.push("upstream messages payload parity failed"); + if (parity.tools_sha256 !== toolsHash || call.tools_sha256 !== toolsHash) errors.push("upstream tools payload parity failed"); + if (parity.sampling_sha256 !== samplingHash || call.sampling_sha256 !== samplingHash) errors.push("upstream sampling payload parity failed"); + if (parity.context_overflow_behavior !== "fail" || call.context_overflow_behavior !== "fail") errors.push("context overflow must fail rather than lower max_tokens"); + if (call.max_tokens !== requestSampling.max_tokens) errors.push("executed max_tokens differs from the requested payload"); + const workload = object(manifest.workload_contract); + const candidateTags = (Array.isArray(requestMessages) ? requestMessages : []).flatMap((message) => { + const row = object(message); + if (row.role !== "system") return []; + const content = row.content; + return typeof content === "string" ? [...content.matchAll(/([\s\S]*?)<\/candidate_policy>/g)].map((match) => match[1]) : []; + }); + if (candidateTags.length !== 1) errors.push("outer system transcript must contain exactly one candidate_policy tag"); + if (candidateTags.length === 1 && workload.candidate_tag_sha256 !== sha256Bytes(Buffer.from(candidateTags[0]))) errors.push("candidate tag hash does not match outer system transcript"); + const fixedMessages = (Array.isArray(requestMessages) ? requestMessages : []).map((message) => { + const row = object(message); + return typeof row.content === "string" ? { ...row, content: row.content.replace(/[\s\S]*?<\/candidate_policy>/g, "") } : row; + }); + if (workload.candidate_source !== "outer_system_transcript" || workload.policy_injection_count !== 1) errors.push("candidate policy must come from the outer system transcript and be injected exactly once"); + if (workload.benchmark_prompt_sha256 !== sha256Bytes(Buffer.from(canonicalize(fixedMessages)))) errors.push("fixed benchmark prompt slot is not hash-bound independently of the candidate policy"); + if (workload.tool_schema_sha256 !== toolsHash) errors.push("workload tool schema hash does not match tools artifact"); + if (workload.package_inventory_sha256 !== object(manifest.environment).uv_lock_sha256) errors.push("workload package inventory hash does not match uv.lock"); + if (workload.mcp_version !== "1.29.0" || !Array.isArray(object(manifest.environment).resolved_packages) || !(object(manifest.environment).resolved_packages as unknown[]).map(object).some((pin) => pin.name === "mcp" && pin.version === "1.29.0")) errors.push("MCP must be pinned to 1.29.0 in the exact lock inventory"); +} + function object(value: unknown): JsonObject { return value !== null && typeof value === "object" && !Array.isArray(value) ? value as JsonObject : {}; } @@ -164,10 +357,12 @@ function validateSmoke(manifest: JsonObject, traceBytes: Uint8Array, errors: str for (const effect of effects) if (effect.applied === true && typeof effect.tool === "string" && !appliedTools.has(effect.tool)) errors.push(`declared mutating effect ${effect.tool} is absent from the trace`); } -function validateSpend(manifest: JsonObject, errors: string[]): Record { +function validateSpend(manifest: JsonObject, errors: string[]): { effective: Record; cumulative: number } { const spend = object(manifest.spend); const total = number(spend.campaign_total_usd); if (total === null || total < 0) errors.push("spend.campaign_total_usd must be non-negative"); + const prior = number(spend.prior_spend_usd); + if (prior === null || prior < 0) errors.push("spend.prior_spend_usd must be non-negative"); const allocations = object(spend.allocations); const caps = Object.fromEntries(SPEND_LANES.map((lane) => [lane, number(object(allocations[lane]).cap_usd) ?? -1])) as Record; for (const lane of SPEND_LANES) if (caps[lane] < 0) errors.push(`spend.allocations.${lane}.cap_usd must be non-negative`); @@ -209,12 +404,14 @@ function validateSpend(manifest: JsonObject, errors: string[]): Record= 0) charged[lane] += amount; } for (const lane of SPEND_LANES) if (charged[lane] > effective[lane] + 1e-9) errors.push(`${lane} charges exceed its immutable allocation`); - return effective; + const cumulative = Math.max(0, prior ?? 0) + SPEND_LANES.reduce((sum, lane) => sum + charged[lane], 0); + if (total !== null && cumulative > total + 1e-9) errors.push("prior spend plus new charges exceeds campaign total"); + return { effective, cumulative }; } export function validateCampaignAdmission(manifest: unknown, artifacts: TransportArtifacts): AdmissionResult { const value = object(manifest); - const errors: string[] = []; + const errors: string[] = publishedSchemaErrors(manifest); if (value.schema_version !== CAMPAIGN_ADMISSION_SCHEMA_VERSION) errors.push(`schema_version must equal ${CAMPAIGN_ADMISSION_SCHEMA_VERSION}`); validateEnvironment(value, errors); const fingerprints = fingerprintTransport(artifacts); @@ -222,11 +419,20 @@ export function validateCampaignAdmission(manifest: unknown, artifacts: Transpor for (const [key, actual] of Object.entries(fingerprints)) { if (declared[key] !== actual) errors.push(`transport_fingerprints.${key} does not match the supplied artifact`); } + let tool_steps: ToolStepFingerprint[] = []; + try { + tool_steps = fingerprintToolSteps(artifacts); + if (canonicalize(value.tool_steps) !== canonicalize(tool_steps)) errors.push("tool_steps do not match derived redacted response/trace fingerprints"); + } catch (error) { + errors.push(error instanceof Error ? error.message : String(error)); + } validateSmoke(value, artifacts.trace, errors); - const effective_spend_caps_usd = validateSpend(value, errors); - return { admitted: errors.length === 0, errors, fingerprints, effective_spend_caps_usd }; + validateExecutionReceipt(value, artifacts, errors); + validatePayloadParity(value, artifacts, errors); + const spend = validateSpend(value, errors); + return { admission_only: true, compile_authorized: false, admitted: errors.length === 0, errors, fingerprints, tool_steps, effective_spend_caps_usd: spend.effective, cumulative_spend_usd: spend.cumulative }; } -export function readTransportArtifacts(paths: { request: string; response: string; tools: string; trace: string }): TransportArtifacts { - return { request: readFileSync(paths.request), response: readFileSync(paths.response), tools: readFileSync(paths.tools), trace: readFileSync(paths.trace) }; +export function readTransportArtifacts(paths: { request: string; response: string; tools: string; trace: string; executionReceipt: string; beforeState: string; afterState: string }): TransportArtifacts { + return { request: readFileSync(paths.request), response: readFileSync(paths.response), tools: readFileSync(paths.tools), trace: readFileSync(paths.trace), executionReceipt: readFileSync(paths.executionReceipt), beforeState: readFileSync(paths.beforeState), afterState: readFileSync(paths.afterState) }; } diff --git a/src/commands/campaigns.ts b/src/commands/campaigns.ts index 8f84b597..1aa0fe65 100644 --- a/src/commands/campaigns.ts +++ b/src/commands/campaigns.ts @@ -20,7 +20,11 @@ export function registerCampaignsCommand(program: Command): void { .requiredOption("--response ", "Raw JSON response artifact") .requiredOption("--tools ", "Raw JSON tool catalog artifact") .requiredOption("--trace ", "Exactly-one-task standard-Verifiers trace artifact") - .action((options: { manifest: string; project: string; request: string; response: string; tools: string; trace: string }) => { + .requiredOption("--execution-receipt ", "Generated locked-project execution receipt") + .requiredOption("--before-state ", "Generated before-state artifact") + .requiredOption("--after-state ", "Generated after-state artifact") + .requiredOption("--smoke-generator ", "Provider-free generator inside the locked project") + .action((options: { manifest: string; project: string; request: string; response: string; tools: string; trace: string; executionReceipt: string; beforeState: string; afterState: string; smokeGenerator: string }) => { try { const project = resolve(options.project); const manifest = JSON.parse(readFileSync(resolve(options.manifest), "utf8")) as Record; @@ -33,6 +37,7 @@ export function registerCampaignsCommand(program: Command): void { if (!uvVersion) throw new Error("could not parse uv version"); if (environment.uv_version !== uvVersion) throw new Error(`uv version mismatch: expected ${String(environment.uv_version)}, got ${uvVersion}`); execFileSync("uv", ["lock", "--check", "--project", project], { stdio: "pipe" }); + execFileSync("uv", ["sync", "--locked", "--check", "--project", project], { stdio: "pipe" }); const declaredPins = JSON.stringify(environment.resolved_packages); const lockedPins = JSON.stringify(parseUvLockPins(readFileSync(lock, "utf8"))); if (declaredPins !== lockedPins) throw new Error("resolved package pins do not exactly match uv.lock"); @@ -40,7 +45,13 @@ export function registerCampaignsCommand(program: Command): void { const pythonVersion = execFileSync(python, ["-c", "import platform; print(platform.python_version())"], { encoding: "utf8" }).trim(); if (pythonVersion !== environment.python_version) throw new Error(`python version mismatch: expected ${String(environment.python_version)}, got ${pythonVersion}`); if (fileSha256(python) !== environment.python_executable_sha256) throw new Error("python executable hash does not match manifest"); - const result = validateCampaignAdmission(manifest, readTransportArtifacts({ request: resolve(options.request), response: resolve(options.response), tools: resolve(options.tools), trace: resolve(options.trace) })); + const generator = resolve(options.smokeGenerator); + if (generator !== join(project, "generate_smoke.py")) throw new Error("smoke generator must be generate_smoke.py inside the locked project"); + const comparisons = [["trace.json", options.trace], ["execution-receipt.json", options.executionReceipt], ["before-state.json", options.beforeState], ["after-state.json", options.afterState]] as const; + const expected = new Map(comparisons.map(([generated, supplied]) => [generated, readFileSync(resolve(supplied))])); + execFileSync("uv", ["run", "--project", ".", "--locked", "python", "generate_smoke.py", "--output", "generated"], { cwd: project, stdio: "pipe" }); + for (const [generated] of comparisons) if (!readFileSync(join(project, "generated", generated)).equals(expected.get(generated)!)) throw new Error(`generated ${generated} differs from supplied fixture`); + const result = validateCampaignAdmission(manifest, readTransportArtifacts({ request: resolve(options.request), response: resolve(options.response), tools: resolve(options.tools), trace: resolve(options.trace), executionReceipt: resolve(options.executionReceipt), beforeState: resolve(options.beforeState), afterState: resolve(options.afterState) })); process.stdout.write(`${JSON.stringify(result, null, 2)}\n`); if (!result.admitted) process.exitCode = 1; } catch (error) { diff --git a/src/index.ts b/src/index.ts index 1a7c1edc..6e746ae7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -120,7 +120,9 @@ export { CAMPAIGN_ADMISSION_SCHEMA_VERSION, SPEND_LANES, fingerprintTransport, + fingerprintToolSteps, parseUvLockPins, + publishedSchemaErrors, readTransportArtifacts, semanticJsonSha256, sha256Bytes as sha256CampaignAdmissionBytes, @@ -129,6 +131,7 @@ export { type SpendLane, type TransportArtifacts, type TransportFingerprints, + type ToolStepFingerprint, type ResolvedPackagePin, } from "./campaign-admission/index.js"; diff --git a/tests/campaign-admission-cli.test.mjs b/tests/campaign-admission-cli.test.mjs index 0d3c27be..9baf477b 100644 --- a/tests/campaign-admission-cli.test.mjs +++ b/tests/campaign-admission-cli.test.mjs @@ -5,49 +5,35 @@ import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join, resolve } from "node:path"; import { it } from "node:test"; +import { baseManifest } from "./helpers/campaign-admission-fixture.mjs"; const fixture = resolve("tests/fixtures/campaign-admission"); const sha = (value) => createHash("sha256").update(value).digest("hex"); -it("campaigns admit verifies the locked project and public synthetic evidence", async (t) => { +it("campaigns admit reruns the exact locked generator and verifies its bytes", async (t) => { if (spawnSync("uv", ["--version"]).status !== 0) return t.skip("uv is unavailable"); const mod = await import("../dist/campaign-admission/index.js"); + const { manifest } = baseManifest(mod); const project = join(fixture, "uv-project"); - const request = join(fixture, "request.json"); - const response = join(fixture, "response.json"); - const tools = join(fixture, "tools.json"); - const trace = join(fixture, "verifiers-0.2.1-one-task-trace.json"); - const python = execFileSync("uv", ["python", "find", "3.12"], { encoding: "utf8" }).trim(); - const pythonVersion = execFileSync(python, ["-c", "import platform; print(platform.python_version())"], { encoding: "utf8" }).trim(); - const artifacts = { request: readFileSync(request), response: readFileSync(response), tools: readFileSync(tools), trace: readFileSync(trace) }; - const lock = readFileSync(join(project, "uv.lock")); - const manifest = { - schema_version: "understudy.campaign_admission.v1", - campaign_id: "public-synthetic-cli", - environment: { - pyproject_sha256: sha(readFileSync(join(project, "pyproject.toml"))), uv_lock_sha256: sha(lock), - uv_lock_check_command: "uv lock --check", uv_lock_check_exit_code: 0, - uv_version: execFileSync("uv", ["--version"], { encoding: "utf8" }).trim().match(/^uv\s+(\S+)/)[1], - python_version: pythonVersion, python_executable_sha256: sha(readFileSync(python)), - container_image_digest: `sha256:${"c".repeat(64)}`, - resolved_packages: mod.parseUvLockPins(lock.toString("utf8")), - }, - transport_fingerprints: mod.fingerprintTransport(artifacts), - mutation_smoke: { - runtime: "standard-verifiers", verifiers_version: "0.2.1", task_count: 1, calls: 1, nodes: 4, assertion_fraction: 1, - seed_candidate_sha256: "d".repeat(64), mutated_candidate_sha256: "e".repeat(64), eval_exit_code: 0, - trace_artifact_sha256: sha(artifacts.trace), mutating_effects: [{ tool: "set-record", applied: true }], - }, - spend: { campaign_total_usd: 3, allocations: { optimizer: { cap_usd: 1 }, endpoint: { cap_usd: 1 }, training: { cap_usd: 1 } }, transfers: [], charges: [] }, - }; + const python = execFileSync("uv", ["python", "find", manifest.environment.python_version], { encoding: "utf8" }).trim(); + manifest.environment.uv_version = execFileSync("uv", ["--version"], { encoding: "utf8" }).trim().match(/^uv\s+(\S+)/)[1]; + manifest.environment.python_executable_sha256 = sha(readFileSync(python)); + const generated = join(project, "generated"); const temp = mkdtempSync(join(tmpdir(), "campaign-admission-cli-")); try { const manifestPath = join(temp, "manifest.json"); writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`); - const run = spawnSync("node", [resolve("dist/bin.js"), "campaigns", "admit", "--manifest", manifestPath, "--project", project, "--request", request, "--response", response, "--tools", tools, "--trace", trace], { encoding: "utf8" }); + const args = [resolve("dist/bin.js"), "campaigns", "admit", "--manifest", manifestPath, "--project", project, + "--request", join(fixture, "request.json"), "--response", join(fixture, "response.json"), "--tools", join(fixture, "tools.json"), + "--trace", join(generated, "trace.json"), "--execution-receipt", join(generated, "execution-receipt.json"), + "--before-state", join(generated, "before-state.json"), "--after-state", join(generated, "after-state.json"), + "--smoke-generator", join(project, "generate_smoke.py")]; + const run = spawnSync("node", args, { encoding: "utf8", timeout: 30_000 }); assert.equal(run.status, 0, `${run.stderr}\n${run.stdout}`); - assert.equal(JSON.parse(run.stdout).admitted, true); - } finally { - rmSync(temp, { recursive: true, force: true }); - } + const output = JSON.parse(run.stdout); + assert.equal(output.admitted, true); + assert.equal(output.admission_only, true); + assert.equal(output.compile_authorized, false); + assert.equal(output.tool_steps[0].semantic_arguments_equal, true); + } finally { rmSync(temp, { recursive: true, force: true }); } }); diff --git a/tests/campaign-admission.test.mjs b/tests/campaign-admission.test.mjs index 82199ad8..771d530a 100644 --- a/tests/campaign-admission.test.mjs +++ b/tests/campaign-admission.test.mjs @@ -1,123 +1,95 @@ import assert from "node:assert/strict"; -import { createHash } from "node:crypto"; -import { readFileSync } from "node:fs"; -import { join, resolve } from "node:path"; import { describe, it } from "node:test"; - -const fixture = resolve("tests/fixtures/campaign-admission"); -const bytes = (name) => readFileSync(join(fixture, name)); -const sha = (value) => createHash("sha256").update(value).digest("hex"); - -function baseManifest(mod) { - const artifacts = { request: bytes("request.json"), response: bytes("response.json"), tools: bytes("tools.json"), trace: bytes("verifiers-0.2.1-one-task-trace.json") }; - const trace = JSON.parse(bytes("verifiers-0.2.1-one-task-trace.json")); - return { - artifacts, - manifest: { - schema_version: "understudy.campaign_admission.v1", - campaign_id: "public-synthetic-campaign", - environment: { - pyproject_sha256: sha(bytes("uv-project/pyproject.toml")), - uv_lock_sha256: sha(bytes("uv-project/uv.lock")), - uv_lock_check_command: "uv lock --check", - uv_lock_check_exit_code: 0, - uv_version: "0.8.0", - python_version: "3.12.11", - python_executable_sha256: "1".repeat(64), - container_image_digest: `sha256:${"2".repeat(64)}`, - resolved_packages: mod.parseUvLockPins(bytes("uv-project/uv.lock").toString("utf8")), - }, - transport_fingerprints: mod.fingerprintTransport(artifacts), - mutation_smoke: { - runtime: trace.runtime, - verifiers_version: trace.verifiers_version, - task_count: 1, - calls: trace.calls.length, - nodes: trace.nodes.length, - assertion_fraction: trace.metrics.assertion_fraction, - seed_candidate_sha256: "4".repeat(64), - mutated_candidate_sha256: "5".repeat(64), - eval_exit_code: 0, - trace_artifact_sha256: sha(bytes("verifiers-0.2.1-one-task-trace.json")), - mutating_effects: [{ tool: "set-record", applied: true }], - }, - spend: { - campaign_total_usd: 100, - allocations: { optimizer: { cap_usd: 20 }, endpoint: { cap_usd: 50 }, training: { cap_usd: 30 } }, - transfers: [], - charges: [ - { charge_id: "optimizer-1", lane: "optimizer", amount_usd: 2, immutable_receipt_sha256: "6".repeat(64) }, - { charge_id: "endpoint-1", lane: "endpoint", amount_usd: 3, immutable_receipt_sha256: "7".repeat(64) }, - { charge_id: "training-1", lane: "training", amount_usd: 4, immutable_receipt_sha256: "8".repeat(64) }, - ], - }, - }, - }; -} +import { baseManifest } from "./helpers/campaign-admission-fixture.mjs"; describe("campaign admission", () => { - it("admits complete provider-free standard-Verifiers 0.2.1 evidence", async () => { + it("admits generated provider-free standard-Verifiers 0.2.1 evidence", async () => { const mod = await import("../dist/campaign-admission/index.js"); const { manifest, artifacts } = baseManifest(mod); const result = mod.validateCampaignAdmission(manifest, artifacts); assert.equal(result.admitted, true, result.errors.join("\n")); - assert.deepEqual(result.effective_spend_caps_usd, { optimizer: 20, endpoint: 50, training: 30 }); + assert.equal(result.admission_only, true); + assert.equal(result.compile_authorized, false); + assert.equal(result.cumulative_spend_usd, 19); + assert.equal(result.tool_steps[0].raw_arguments_equal, false); + assert.equal(result.tool_steps[0].semantic_arguments_equal, true); + assert.equal(result.tool_steps[0].mutation, true); + }); + + it("whitespace changes alter raw arguments while preserving semantic equality", async () => { + const mod = await import("../dist/campaign-admission/index.js"); + const { manifest, artifacts } = baseManifest(mod); + const response = JSON.parse(artifacts.response); + response.choices[0].message.tool_calls[0].function.arguments = '{"id":"alpha","status":"ready"}'; + const changed = Buffer.from(`${JSON.stringify(response)}\n`); + const changedArtifacts = { ...artifacts, response: changed }; + manifest.transport_fingerprints = mod.fingerprintTransport(changedArtifacts); + manifest.tool_steps = mod.fingerprintToolSteps(changedArtifacts); + const result = mod.validateCampaignAdmission(manifest, changedArtifacts); + assert.equal(result.admitted, true, result.errors.join("\n")); + assert.equal(result.tool_steps[0].raw_arguments_equal, true); + assert.equal(result.tool_steps[0].semantic_arguments_equal, true); }); - it("distinguishes raw-byte hashes from canonical semantic hashes", async () => { + it("rejects executed argument changes, missing/duplicate IDs, and non-string arguments", async () => { const mod = await import("../dist/campaign-admission/index.js"); - const compact = Buffer.from('{"b":2,"a":1}'); - const formatted = Buffer.from('{\n "a": 1,\n "b": 2\n}'); - assert.notEqual(mod.sha256Bytes(compact), mod.sha256Bytes(formatted)); - assert.equal(mod.semanticJsonSha256(compact, "compact"), mod.semanticJsonSha256(formatted, "formatted")); + const base = baseManifest(mod); + for (const mutate of [ + (trace) => { trace.nodes[2].message.tool_calls[0].arguments = '{"id":"beta","status":"ready"}'; }, + (trace) => { trace.nodes[2].message.tool_calls.push({ ...trace.nodes[2].message.tool_calls[0] }); }, + (trace) => { trace.nodes[2].message.tool_calls[0].arguments = { id: "alpha", status: "ready" }; }, + (trace) => { trace.nodes.splice(3, 1); }, + (trace) => { trace.nodes[2].message.tool_calls[0].name = "world_toolset_other-record"; }, + (trace) => { trace.nodes[2].message.tool_calls[0].arguments = "not-json"; }, + (trace) => { trace.nodes[2].message.tool_calls[0].arguments = "[]"; }, + ]) { + const trace = JSON.parse(base.artifacts.trace); + mutate(trace); + const artifacts = { ...base.artifacts, trace: Buffer.from(`${JSON.stringify(trace)}\n`) }; + const result = mod.validateCampaignAdmission(base.manifest, artifacts); + assert.equal(result.admitted, false); + assert.match(result.errors.join("\n"), /mismatch|duplicate|JSON string|missing executed|valid JSON|decode to an object/); + } }); - it("fails closed for no-op or non-Verifiers mutation evidence", async () => { + it("enforces published schema and runtime lockstep", async () => { const mod = await import("../dist/campaign-admission/index.js"); const { manifest, artifacts } = baseManifest(mod); - manifest.mutation_smoke.runtime = "mock"; - manifest.mutation_smoke.calls = 0; - manifest.mutation_smoke.nodes = 0; - manifest.mutation_smoke.assertion_fraction = 0; - manifest.mutation_smoke.mutated_candidate_sha256 = manifest.mutation_smoke.seed_candidate_sha256; - manifest.mutation_smoke.mutating_effects = []; + delete manifest.campaign_id; + manifest.private_prompt = "must be rejected"; const result = mod.validateCampaignAdmission(manifest, artifacts); assert.equal(result.admitted, false); - assert.match(result.errors.join("\n"), /standard-verifiers/); - assert.match(result.errors.join("\n"), /real mutation/); - assert.match(result.errors.join("\n"), /applied tool effect/); + assert.match(result.errors.join("\n"), /campaign_id/); + assert.match(result.errors.join("\n"), /additional properties/); + assert.deepEqual(mod.publishedSchemaErrors({ ...baseManifest(mod).manifest }), []); }); - it("requires explicit immutable transfer authority and enforces adjusted lane caps", async () => { + it("quarantines unchanged candidates and invalid generated state bindings", async () => { const mod = await import("../dist/campaign-admission/index.js"); const { manifest, artifacts } = baseManifest(mod); - manifest.spend.transfers.push({ transfer_id: "move-1", from: "training", to: "endpoint", amount_usd: 10, authority_id: "approval-public-1", immutable_receipt_sha256: "9".repeat(64) }); - manifest.spend.charges.push({ charge_id: "endpoint-2", lane: "endpoint", amount_usd: 55, immutable_receipt_sha256: "a".repeat(64) }); - let result = mod.validateCampaignAdmission(manifest, artifacts); - assert.equal(result.admitted, true, result.errors.join("\n")); - assert.deepEqual(result.effective_spend_caps_usd, { optimizer: 20, endpoint: 60, training: 20 }); - delete manifest.spend.transfers[0].authority_id; - result = mod.validateCampaignAdmission(manifest, artifacts); + manifest.mutation_smoke.mutated_candidate_sha256 = manifest.mutation_smoke.seed_candidate_sha256; + const result = mod.validateCampaignAdmission(manifest, artifacts); assert.equal(result.admitted, false); - assert.match(result.errors.join("\n"), /authority_id/); + assert.match(result.errors.join("\n"), /real mutation|candidate hashes/); }); - it("rejects campaign-total and lane overspend independently", async () => { + it("requires immutable transfers and rejects prior plus new spend beyond total", async () => { const mod = await import("../dist/campaign-admission/index.js"); const { manifest, artifacts } = baseManifest(mod); - manifest.spend.campaign_total_usd = 99; - manifest.spend.charges.push({ charge_id: "optimizer-2", lane: "optimizer", amount_usd: 19, immutable_receipt_sha256: "b".repeat(64) }); + manifest.spend.transfers.push({ transfer_id: "move-1", from: "training", to: "endpoint", amount_usd: 10, authority_id: "approval-public-1", immutable_receipt_sha256: "9".repeat(64) }); + manifest.spend.charges.push({ charge_id: "endpoint-2", lane: "endpoint", amount_usd: 55, immutable_receipt_sha256: "a".repeat(64) }); + manifest.spend.prior_spend_usd = 95; const result = mod.validateCampaignAdmission(manifest, artifacts); assert.equal(result.admitted, false); - assert.match(result.errors.join("\n"), /sum of lane caps/); - assert.match(result.errors.join("\n"), /optimizer charges/); + assert.match(result.errors.join("\n"), /prior spend plus new charges/); }); - it("rejects transport evidence when supplied bytes change", async () => { + it("fails payload parity and max-token overflow downgrades closed", async () => { const mod = await import("../dist/campaign-admission/index.js"); const { manifest, artifacts } = baseManifest(mod); - const result = mod.validateCampaignAdmission(manifest, { ...artifacts, request: Buffer.from(`${artifacts.request.toString()} `) }); + manifest.payload_parity.context_overflow_behavior = "truncate"; + const result = mod.validateCampaignAdmission(manifest, artifacts); assert.equal(result.admitted, false); - assert.match(result.errors.join("\n"), /raw_request_sha256/); + assert.match(result.errors.join("\n"), /context_overflow/); }); }); diff --git a/tests/fixtures/campaign-admission/request.json b/tests/fixtures/campaign-admission/request.json index f263f610..c5fd1dfc 100644 --- a/tests/fixtures/campaign-admission/request.json +++ b/tests/fixtures/campaign-admission/request.json @@ -1 +1 @@ -{"messages":[{"role":"user","content":"Set synthetic record alpha to ready."}],"model":"synthetic-local"} +{"messages":[{"role":"system","content":"Only inspect the synthetic record.\nSet record alpha to ready with set-record, then report success."},{"role":"user","content":"Set synthetic record alpha to ready."}],"model":"synthetic-local","sampling":{"max_tokens":256,"temperature":0}} diff --git a/tests/fixtures/campaign-admission/response.json b/tests/fixtures/campaign-admission/response.json index 1a63a99d..c32149a8 100644 --- a/tests/fixtures/campaign-admission/response.json +++ b/tests/fixtures/campaign-admission/response.json @@ -1 +1 @@ -{"choices":[{"finish_reason":"tool_calls","message":{"role":"assistant","tool_calls":[{"id":"call-public-1","type":"function","function":{"name":"set-record","arguments":"{\"id\":\"alpha\",\"status\":\"ready\"}"}}]}}]} +{"choices":[{"finish_reason":"tool_calls","message":{"role":"assistant","tool_calls":[{"id":"call-public-1","type":"function","function":{"name":"set-record","arguments":"{ \"status\": \"ready\", \"id\": \"alpha\" }"}}]}}]} diff --git a/tests/fixtures/campaign-admission/uv-project/.python-version b/tests/fixtures/campaign-admission/uv-project/.python-version new file mode 100644 index 00000000..28d9a01b --- /dev/null +++ b/tests/fixtures/campaign-admission/uv-project/.python-version @@ -0,0 +1 @@ +3.12.13 diff --git a/tests/fixtures/campaign-admission/uv-project/generate_smoke.py b/tests/fixtures/campaign-admission/uv-project/generate_smoke.py new file mode 100755 index 00000000..b23667f5 --- /dev/null +++ b/tests/fixtures/campaign-admission/uv-project/generate_smoke.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python3 +"""Generate the public one-task mutation receipt through pinned Verifiers.""" + +import argparse +import asyncio +import hashlib +import json +import platform +from pathlib import Path + +import verifiers as vf + +ARGV = ["uv", "run", "--project", ".", "--locked", "python", "generate_smoke.py", "--output", "generated"] +SEED = "Only inspect the synthetic record." +CANDIDATE = "Set record alpha to ready with set-record, then report success." +MESSAGES = [ + {"role": "system", "content": f"{SEED}\n{CANDIDATE}"}, + {"role": "user", "content": "Set synthetic record alpha to ready."}, +] +TOOLS = [{"type": "function", "function": {"name": "set-record", "description": "Mutate a public synthetic record.", "parameters": {"type": "object", "additionalProperties": False, "required": ["id", "status"], "properties": {"id": {"type": "string"}, "status": {"enum": ["ready"]}}}}}] +SAMPLING = {"max_tokens": 256, "temperature": 0} + + +def canonical(value): + return json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=False) + + +def sha_bytes(value): + return hashlib.sha256(value).hexdigest() + + +def write_json(path, value): + path.write_text(json.dumps(value, sort_keys=True, indent=2) + "\n", encoding="utf-8") + + +async def generate(output): + before = {"records": {"alpha": {"status": "pending"}}} + after = {"records": {"alpha": {"status": "ready"}}} + arguments = '{"id":"alpha","status":"ready"}' + call_id = "call-public-1" + + def assertion_fraction(state): + return 1.0 if state["after_state"]["records"]["alpha"]["status"] == "ready" else 0.0 + + state = { + "prompt": MESSAGES, + "completion": [{"role": "assistant", "tool_calls": [{"id": call_id, "name": "world_toolset_set-record", "arguments": arguments}]}], + "task": "public-synthetic-mutation-1", + "before_state": before, + "after_state": after, + } + rubric = vf.Rubric(funcs=[assertion_fraction]) + await rubric.score_rollout(state) + assertion = state["metrics"]["assertion_fraction"] + if assertion != 1.0: + raise RuntimeError("pinned Verifiers rubric did not accept the synthetic mutation") + + output.mkdir(parents=True, exist_ok=True) + before_path = output / "before-state.json" + after_path = output / "after-state.json" + trace_path = output / "trace.json" + write_json(before_path, before) + write_json(after_path, after) + trace = { + "runtime": "standard-verifiers", + "verifiers_version": vf.__version__, + "task": {"data": {"task_id": state["task"], "split": "train"}}, + "rewards": {"assertion_fraction": assertion}, + "metrics": {"assertion_fraction": assertion}, + "errors": [], + "ok": True, + "calls": [{"node": 2, "model": "synthetic-local", "endpoint": "/chat/completions", "finish_reason": "tool_calls", "messages_sha256": sha_bytes(canonical(MESSAGES).encode()), "tools_sha256": sha_bytes(canonical(TOOLS).encode()), "sampling_sha256": sha_bytes(canonical(SAMPLING).encode()), "max_tokens": 256, "context_overflow_behavior": "fail"}], + "nodes": [ + {"message": MESSAGES[0], "sampled": False}, + {"parent": 0, "message": MESSAGES[1], "sampled": False}, + {"parent": 1, "message": state["completion"][0], "sampled": True}, + {"parent": 2, "message": {"role": "tool", "tool_call_id": call_id, "name": "world_toolset_set-record", "content": canonical({"ok": True, "applied": True, "before": "pending", "after": "ready"})}, "sampled": False}, + ], + } + write_json(trace_path, trace) + + lock_path = Path("uv.lock") + receipt = { + "schema_version": "understudy.synthetic_verifiers_execution.v1", + "argv": ARGV, + "interpreter": {"implementation": platform.python_implementation(), "version": platform.python_version()}, + "resolved_package_inventory_sha256": sha_bytes(lock_path.read_bytes()), + "verifiers": {"version": vf.__version__, "module": "verifiers"}, + "seed_candidate_sha256": sha_bytes(SEED.encode()), + "mutated_candidate_sha256": sha_bytes(CANDIDATE.encode()), + "before_state_sha256": sha_bytes(before_path.read_bytes()), + "after_state_sha256": sha_bytes(after_path.read_bytes()), + "trace_sha256": sha_bytes(trace_path.read_bytes()), + "verified_state_delta": {"path": "/records/alpha/status", "before": "pending", "after": "ready"}, + } + write_json(output / "execution-receipt.json", receipt) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--output", default="generated") + args = parser.parse_args() + asyncio.run(generate(Path(args.output))) diff --git a/tests/fixtures/campaign-admission/uv-project/generated/after-state.json b/tests/fixtures/campaign-admission/uv-project/generated/after-state.json new file mode 100644 index 00000000..492eea14 --- /dev/null +++ b/tests/fixtures/campaign-admission/uv-project/generated/after-state.json @@ -0,0 +1,7 @@ +{ + "records": { + "alpha": { + "status": "ready" + } + } +} diff --git a/tests/fixtures/campaign-admission/uv-project/generated/before-state.json b/tests/fixtures/campaign-admission/uv-project/generated/before-state.json new file mode 100644 index 00000000..1e43e886 --- /dev/null +++ b/tests/fixtures/campaign-admission/uv-project/generated/before-state.json @@ -0,0 +1,7 @@ +{ + "records": { + "alpha": { + "status": "pending" + } + } +} diff --git a/tests/fixtures/campaign-admission/uv-project/generated/execution-receipt.json b/tests/fixtures/campaign-admission/uv-project/generated/execution-receipt.json new file mode 100644 index 00000000..97e1a08f --- /dev/null +++ b/tests/fixtures/campaign-admission/uv-project/generated/execution-receipt.json @@ -0,0 +1,33 @@ +{ + "after_state_sha256": "578c4dc9e95cf9ef87e1ccd5f2236a61cc2faf0a120d16f52f871643f3675a34", + "argv": [ + "uv", + "run", + "--project", + ".", + "--locked", + "python", + "generate_smoke.py", + "--output", + "generated" + ], + "before_state_sha256": "9e4f76c756726a6c01f052f18b08db9fa2e073cd5e074f7693d55159d5f99612", + "interpreter": { + "implementation": "CPython", + "version": "3.12.13" + }, + "mutated_candidate_sha256": "0ba2e4298634b3771db51d77ffca15af1c7e731fc15c290b60ab5c44097c1f6c", + "resolved_package_inventory_sha256": "be34de4d14a135dac01c2649f6447b4abebde8242ff51cbf6d8bba2835d7c8dd", + "schema_version": "understudy.synthetic_verifiers_execution.v1", + "seed_candidate_sha256": "4dbee206fc073f8db3e50fad210ca48772e481ad31ee37f33e638bca91db1914", + "trace_sha256": "a60d2d3f6096130e1c0d999a24ec2170e697f03892f078f6db58d17398483ddf", + "verified_state_delta": { + "after": "ready", + "before": "pending", + "path": "/records/alpha/status" + }, + "verifiers": { + "module": "verifiers", + "version": "0.2.1" + } +} diff --git a/tests/fixtures/campaign-admission/uv-project/generated/trace.json b/tests/fixtures/campaign-admission/uv-project/generated/trace.json new file mode 100644 index 00000000..5a3a2bc3 --- /dev/null +++ b/tests/fixtures/campaign-admission/uv-project/generated/trace.json @@ -0,0 +1,72 @@ +{ + "calls": [ + { + "context_overflow_behavior": "fail", + "endpoint": "/chat/completions", + "finish_reason": "tool_calls", + "max_tokens": 256, + "messages_sha256": "6f71099eedf6d5b161ceea52fa0663b0c104b5729a77d3a5f4264967b5853808", + "model": "synthetic-local", + "node": 2, + "sampling_sha256": "b779b17d306d67fbd5b415e6b2e82d89e0dc2c4f2e35c57901f7114d3bbd0562", + "tools_sha256": "ad4cc5e9dc6e0a8481d7b6b890033bd33fc457c49a875d458d27e4299b761b64" + } + ], + "errors": [], + "metrics": { + "assertion_fraction": 1.0 + }, + "nodes": [ + { + "message": { + "content": "Only inspect the synthetic record.\nSet record alpha to ready with set-record, then report success.", + "role": "system" + }, + "sampled": false + }, + { + "message": { + "content": "Set synthetic record alpha to ready.", + "role": "user" + }, + "parent": 0, + "sampled": false + }, + { + "message": { + "role": "assistant", + "tool_calls": [ + { + "arguments": "{\"id\":\"alpha\",\"status\":\"ready\"}", + "id": "call-public-1", + "name": "world_toolset_set-record" + } + ] + }, + "parent": 1, + "sampled": true + }, + { + "message": { + "content": "{\"after\":\"ready\",\"applied\":true,\"before\":\"pending\",\"ok\":true}", + "name": "world_toolset_set-record", + "role": "tool", + "tool_call_id": "call-public-1" + }, + "parent": 2, + "sampled": false + } + ], + "ok": true, + "rewards": { + "assertion_fraction": 1.0 + }, + "runtime": "standard-verifiers", + "task": { + "data": { + "split": "train", + "task_id": "public-synthetic-mutation-1" + } + }, + "verifiers_version": "0.2.1" +} diff --git a/tests/fixtures/campaign-admission/verifiers-0.2.1-one-task-trace.json b/tests/fixtures/campaign-admission/verifiers-0.2.1-one-task-trace.json deleted file mode 100644 index ac88445d..00000000 --- a/tests/fixtures/campaign-admission/verifiers-0.2.1-one-task-trace.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "runtime": "standard-verifiers", - "verifiers_version": "0.2.1", - "task": { "data": { "task_id": "public-synthetic-mutation-1", "split": "train" } }, - "rewards": { "assertion_fraction": 1.0 }, - "metrics": { "assertion_fraction": 1.0 }, - "errors": [], - "ok": true, - "calls": [{ "node": 2, "model": "synthetic-local", "endpoint": "/chat/completions", "finish_reason": "tool_calls" }], - "nodes": [ - { "message": { "role": "system", "content": "Operate only on the public synthetic record." }, "sampled": false }, - { "parent": 0, "message": { "role": "user", "content": "Set synthetic record alpha to ready." }, "sampled": false }, - { "parent": 1, "message": { "role": "assistant", "tool_calls": [{ "id": "call-public-1", "name": "world_toolset_set-record", "arguments": "{\"id\":\"alpha\",\"status\":\"ready\"}" }] }, "sampled": true }, - { "parent": 2, "message": { "role": "tool", "tool_call_id": "call-public-1", "name": "world_toolset_set-record", "content": "{\"ok\":true,\"applied\":true}" }, "sampled": false } - ] -} diff --git a/tests/helpers/campaign-admission-fixture.mjs b/tests/helpers/campaign-admission-fixture.mjs new file mode 100644 index 00000000..5dc2adcc --- /dev/null +++ b/tests/helpers/campaign-admission-fixture.mjs @@ -0,0 +1,28 @@ +import { createHash } from "node:crypto"; +import { readFileSync } from "node:fs"; +import { join, resolve } from "node:path"; + +const fixture = resolve("tests/fixtures/campaign-admission"); +const bytes = (name) => readFileSync(join(fixture, name)); +const sha = (value) => createHash("sha256").update(value).digest("hex"); + +export function baseManifest(mod) { + const generated = "uv-project/generated"; + const artifacts = { request: bytes("request.json"), response: bytes("response.json"), tools: bytes("tools.json"), trace: bytes(`${generated}/trace.json`), executionReceipt: bytes(`${generated}/execution-receipt.json`), beforeState: bytes(`${generated}/before-state.json`), afterState: bytes(`${generated}/after-state.json`) }; + const trace = JSON.parse(artifacts.trace); + const receipt = JSON.parse(artifacts.executionReceipt); + const request = JSON.parse(artifacts.request); + const semantic = (value) => mod.semanticJsonSha256(Buffer.from(JSON.stringify(value)), "fixture"); + const fixedMessages = request.messages.map((message) => ({ ...message, content: message.content.replace(/[\s\S]*?<\/candidate_policy>/g, "") })); + const lockHash = sha(bytes("uv-project/uv.lock")); + const manifest = { + schema_version: "understudy.campaign_admission.v1", campaign_id: "public-synthetic-campaign", + environment: { pyproject_sha256: sha(bytes("uv-project/pyproject.toml")), uv_lock_sha256: lockHash, uv_lock_check_command: "uv lock --check", uv_lock_check_exit_code: 0, uv_version: "0.12.1", python_version: receipt.interpreter.version, python_executable_sha256: "1".repeat(64), container_image_digest: `sha256:${"2".repeat(64)}`, resolved_packages: mod.parseUvLockPins(bytes("uv-project/uv.lock").toString("utf8")) }, + transport_fingerprints: mod.fingerprintTransport(artifacts), tool_steps: mod.fingerprintToolSteps(artifacts), + payload_parity: { messages_sha256: semantic(request.messages), tools_sha256: semantic(JSON.parse(artifacts.tools)), sampling_sha256: semantic(request.sampling), context_overflow_behavior: "fail" }, + workload_contract: { benchmark_prompt_sha256: semantic(fixedMessages), candidate_source: "outer_system_transcript", candidate_tag_sha256: receipt.mutated_candidate_sha256, policy_injection_count: 1, mcp_version: "1.29.0", tool_schema_sha256: semantic(JSON.parse(artifacts.tools)), package_inventory_sha256: lockHash }, + mutation_smoke: { runtime: trace.runtime, verifiers_version: trace.verifiers_version, task_count: 1, calls: trace.calls.length, nodes: trace.nodes.length, assertion_fraction: trace.metrics.assertion_fraction, seed_candidate_sha256: receipt.seed_candidate_sha256, mutated_candidate_sha256: receipt.mutated_candidate_sha256, eval_exit_code: 0, trace_artifact_sha256: sha(artifacts.trace), execution_receipt_sha256: sha(artifacts.executionReceipt), mutating_effects: [{ tool: "set-record", applied: true }] }, + spend: { campaign_total_usd: 100, prior_spend_usd: 10, allocations: { optimizer: { cap_usd: 20 }, endpoint: { cap_usd: 50 }, training: { cap_usd: 30 } }, transfers: [], charges: [{ charge_id: "optimizer-1", lane: "optimizer", amount_usd: 2, immutable_receipt_sha256: "6".repeat(64) }, { charge_id: "endpoint-1", lane: "endpoint", amount_usd: 3, immutable_receipt_sha256: "7".repeat(64) }, { charge_id: "training-1", lane: "training", amount_usd: 4, immutable_receipt_sha256: "8".repeat(64) }] }, + }; + return { artifacts, manifest }; +} From dc0d4d6b8b042cd42ec218e9b19d466b7287ed63 Mon Sep 17 00:00:00 2001 From: luis manrique <166242911+lluisinthedesert@users.noreply.github.com> Date: Tue, 4 Aug 2026 05:14:55 -0700 Subject: [PATCH 3/8] close campaign admission review gaps --- ...derstudy.campaign_admission.v1.schema.json | 25 +- src/campaign-admission/index.ts | 64 ++- src/commands/campaigns.ts | 11 +- tests/campaign-admission-cli.test.mjs | 6 +- tests/campaign-admission.test.mjs | 72 ++- .../fixtures/campaign-admission/response.json | 2 +- .../uv-project/generate_smoke.py | 186 ++++++-- .../generated/execution-receipt.json | 427 +++++++++++++++++- .../generated/overflow-receipt.json | 11 + .../uv-project/generated/trace.json | 6 +- tests/helpers/campaign-admission-fixture.mjs | 15 +- 11 files changed, 732 insertions(+), 93 deletions(-) mode change 100755 => 100644 tests/fixtures/campaign-admission/uv-project/generate_smoke.py create mode 100644 tests/fixtures/campaign-admission/uv-project/generated/overflow-receipt.json diff --git a/schemas/understudy.campaign_admission.v1.schema.json b/schemas/understudy.campaign_admission.v1.schema.json index 5aa6d3e2..4dfa07d5 100644 --- a/schemas/understudy.campaign_admission.v1.schema.json +++ b/schemas/understudy.campaign_admission.v1.schema.json @@ -5,7 +5,7 @@ "description": "Public, fail-closed campaign admission evidence. References and hashes only; never embeds customer prompts, traces, credentials, or answer keys.", "type": "object", "additionalProperties": false, - "required": ["schema_version", "campaign_id", "environment", "transport_fingerprints", "tool_steps", "payload_parity", "workload_contract", "mutation_smoke", "spend"], + "required": ["schema_version", "campaign_id", "environment", "transport_fingerprints", "tool_steps", "payload_parity", "workload_contract", "optimizer_input", "endpoint_bundle", "candidate_lineage", "context_gates", "mutation_smoke", "spend"], "properties": { "schema_version": { "const": "understudy.campaign_admission.v1" }, "campaign_id": { "type": "string", "minLength": 1 }, @@ -14,6 +14,10 @@ "tool_steps": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/tool_step" } }, "payload_parity": { "$ref": "#/$defs/payload_parity" }, "workload_contract": { "$ref": "#/$defs/workload_contract" }, + "optimizer_input": { "$ref": "#/$defs/optimizer_input" }, + "endpoint_bundle": { "$ref": "#/$defs/endpoint_bundle" }, + "candidate_lineage": { "$ref": "#/$defs/candidate_lineage" }, + "context_gates": { "$ref": "#/$defs/context_gates" }, "mutation_smoke": { "$ref": "#/$defs/mutation_smoke" }, "spend": { "$ref": "#/$defs/spend" } }, @@ -23,7 +27,7 @@ "exact_version": { "type": "string", "pattern": "^[0-9][0-9A-Za-z.!+_-]*$" }, "environment": { "type": "object", "additionalProperties": false, - "required": ["pyproject_sha256", "uv_lock_sha256", "uv_lock_check_command", "uv_lock_check_exit_code", "uv_version", "python_version", "python_executable_sha256", "resolved_packages", "container_image_digest"], + "required": ["pyproject_sha256", "uv_lock_sha256", "uv_lock_check_command", "uv_lock_check_exit_code", "uv_version", "python_version", "python_executable_sha256", "installed_distributions_sha256", "resolved_packages", "container_image_digest"], "properties": { "pyproject_sha256": { "$ref": "#/$defs/sha256" }, "uv_lock_sha256": { "$ref": "#/$defs/sha256" }, @@ -32,6 +36,7 @@ "uv_version": { "$ref": "#/$defs/exact_version" }, "python_version": { "$ref": "#/$defs/exact_version" }, "python_executable_sha256": { "$ref": "#/$defs/sha256" }, + "installed_distributions_sha256": { "$ref": "#/$defs/sha256" }, "container_image_digest": { "$ref": "#/$defs/image_digest" }, "resolved_packages": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/package_pin" } } } @@ -63,22 +68,26 @@ "response_raw_arguments_sha256": { "$ref": "#/$defs/sha256" }, "response_semantic_arguments_sha256": { "$ref": "#/$defs/sha256" }, "trace_call_raw_arguments_sha256": { "$ref": "#/$defs/sha256" }, "trace_call_semantic_arguments_sha256": { "$ref": "#/$defs/sha256" }, "trace_result_raw_sha256": { "$ref": "#/$defs/sha256" }, "trace_result_semantic_sha256": { "$ref": "#/$defs/sha256" }, "trace_call_result_pair_sha256": { "$ref": "#/$defs/sha256" }, - "raw_arguments_equal": { "type": "boolean" }, "semantic_arguments_equal": { "const": true }, "mutation": { "type": "boolean" } + "raw_arguments_equal": { "const": true }, "semantic_arguments_equal": { "const": true }, "mutation": { "type": "boolean" } } }, "payload_parity": { - "type": "object", "additionalProperties": false, "required": ["messages_sha256", "tools_sha256", "sampling_sha256", "context_overflow_behavior"], - "properties": { "messages_sha256": { "$ref": "#/$defs/sha256" }, "tools_sha256": { "$ref": "#/$defs/sha256" }, "sampling_sha256": { "$ref": "#/$defs/sha256" }, "context_overflow_behavior": { "const": "fail" } } + "type": "object", "additionalProperties": false, "required": ["messages_sha256", "tools_sha256", "sampling_sha256", "context_overflow_behavior", "overflow_probe_receipt_sha256"], + "properties": { "messages_sha256": { "$ref": "#/$defs/sha256" }, "tools_sha256": { "$ref": "#/$defs/sha256" }, "sampling_sha256": { "$ref": "#/$defs/sha256" }, "context_overflow_behavior": { "const": "fail" }, "overflow_probe_receipt_sha256": { "$ref": "#/$defs/sha256" } } }, "workload_contract": { - "type": "object", "additionalProperties": false, "required": ["benchmark_prompt_sha256", "candidate_source", "candidate_tag_sha256", "policy_injection_count", "mcp_version", "tool_schema_sha256", "package_inventory_sha256"], - "properties": { "benchmark_prompt_sha256": { "$ref": "#/$defs/sha256" }, "candidate_source": { "const": "outer_system_transcript" }, "candidate_tag_sha256": { "$ref": "#/$defs/sha256" }, "policy_injection_count": { "const": 1 }, "mcp_version": { "const": "1.29.0" }, "tool_schema_sha256": { "$ref": "#/$defs/sha256" }, "package_inventory_sha256": { "$ref": "#/$defs/sha256" } } + "type": "object", "additionalProperties": false, "required": ["benchmark_prompt_sha256", "candidate_source", "candidate_tag_sha256", "policy_injection_count", "verifiers_version", "verifiers_git_revision", "mcp_version", "tool_schema_sha256", "package_inventory_sha256"], + "properties": { "benchmark_prompt_sha256": { "$ref": "#/$defs/sha256" }, "candidate_source": { "const": "outer_system_transcript" }, "candidate_tag_sha256": { "$ref": "#/$defs/sha256" }, "policy_injection_count": { "const": 1 }, "verifiers_version": { "$ref": "#/$defs/exact_version" }, "verifiers_git_revision": { "type": "string", "pattern": "^[a-f0-9]{40}$" }, "mcp_version": { "$ref": "#/$defs/exact_version" }, "tool_schema_sha256": { "$ref": "#/$defs/sha256" }, "package_inventory_sha256": { "$ref": "#/$defs/sha256" } } }, + "optimizer_input": { "type": "object", "additionalProperties": false, "required": ["input_bundle_sha256"], "properties": { "input_bundle_sha256": { "$ref": "#/$defs/sha256" } } }, + "endpoint_bundle": { "type": "object", "additionalProperties": false, "required": ["bundle_kind", "schema_version", "executable_bundle_sha256", "environment_sha256", "health_receipt_sha256", "model_attestation_sha256", "frozen", "seed"], "properties": { "bundle_kind": { "enum": ["policy", "checkpoint"] }, "schema_version": { "type": "string", "minLength": 1 }, "executable_bundle_sha256": { "$ref": "#/$defs/sha256" }, "environment_sha256": { "$ref": "#/$defs/sha256" }, "health_receipt_sha256": { "$ref": "#/$defs/sha256" }, "model_attestation_sha256": { "$ref": "#/$defs/sha256" }, "frozen": { "const": true }, "seed": { "const": false } } }, + "candidate_lineage": { "type": "object", "additionalProperties": false, "required": ["parent_candidate_sha256", "candidate_sha256", "prompt_sha256", "model_attestation_sha256", "checkpoint_sha256"], "properties": { "parent_candidate_sha256": { "$ref": "#/$defs/sha256" }, "candidate_sha256": { "$ref": "#/$defs/sha256" }, "prompt_sha256": { "$ref": "#/$defs/sha256" }, "model_attestation_sha256": { "$ref": "#/$defs/sha256" }, "checkpoint_sha256": { "$ref": "#/$defs/sha256" } } }, + "context_gates": { "type": "object", "additionalProperties": false, "required": ["source_context_sha256", "reflection_context_sha256", "source_context_present", "reflection_context_present"], "properties": { "source_context_sha256": { "$ref": "#/$defs/sha256" }, "reflection_context_sha256": { "$ref": "#/$defs/sha256" }, "source_context_present": { "const": true }, "reflection_context_present": { "const": true } } }, "mutation_smoke": { "type": "object", "additionalProperties": false, "required": ["runtime", "verifiers_version", "task_count", "calls", "nodes", "assertion_fraction", "seed_candidate_sha256", "mutated_candidate_sha256", "eval_exit_code", "trace_artifact_sha256", "execution_receipt_sha256", "mutating_effects"], "properties": { - "runtime": { "const": "standard-verifiers" }, "verifiers_version": { "const": "0.2.1" }, "task_count": { "const": 1 }, + "runtime": { "const": "standard-verifiers" }, "verifiers_version": { "$ref": "#/$defs/exact_version" }, "task_count": { "const": 1 }, "calls": { "type": "integer", "minimum": 1 }, "nodes": { "type": "integer", "minimum": 1 }, "assertion_fraction": { "type": "number", "exclusiveMinimum": 0, "maximum": 1 }, "seed_candidate_sha256": { "$ref": "#/$defs/sha256" }, "mutated_candidate_sha256": { "$ref": "#/$defs/sha256" }, diff --git a/src/campaign-admission/index.ts b/src/campaign-admission/index.ts index 0dcfe10e..5e48134f 100644 --- a/src/campaign-admission/index.ts +++ b/src/campaign-admission/index.ts @@ -16,6 +16,7 @@ export type TransportArtifacts = { executionReceipt: Buffer; beforeState: Buffer; afterState: Buffer; + overflowReceipt: Buffer; }; export type TransportFingerprints = { @@ -174,6 +175,7 @@ export function fingerprintToolSteps(artifacts: TransportArtifacts): ToolStepFin if (responseName !== executedCall.name || responseName !== executedResult.name) throw new Error(`tool name mismatch for call id hash ${sha256Bytes(Buffer.from(id))}`); const rawEqual = responseArguments.raw === executedCall.arguments.raw; const semanticEqual = responseArguments.semantic_sha256 === executedCall.arguments.semantic_sha256; + if (!rawEqual) throw new Error(`raw argument mismatch for call id hash ${sha256Bytes(Buffer.from(id))}`); if (!semanticEqual) throw new Error(`semantic argument mismatch for call id hash ${sha256Bytes(Buffer.from(id))}`); const resultRawSha = sha256Bytes(Buffer.from(executedResult.raw)); return { @@ -228,8 +230,15 @@ function validateExecutionReceipt(manifest: JsonObject, artifacts: TransportArti if (Array.isArray(argv) && argv.includes("--no-project")) errors.push("synthetic smoke cannot use --no-project"); const interpreter = object(receipt.interpreter); if (interpreter.implementation !== "CPython" || interpreter.version !== object(manifest.environment).python_version) errors.push("execution receipt interpreter does not match the admitted project"); - if (receipt.resolved_package_inventory_sha256 !== object(manifest.environment).uv_lock_sha256) errors.push("execution receipt package inventory is not bound to uv.lock"); - if (object(receipt.verifiers).version !== "0.2.1") errors.push("execution receipt did not run Verifiers 0.2.1"); + if (interpreter.path_kind !== "project_relative" || typeof interpreter.path !== "string" || !/^\.venv\/bin\/python[0-9.]*$/.test(interpreter.path) || interpreter.executable_sha256 !== object(manifest.environment).python_executable_sha256) errors.push("execution receipt interpreter path/hash is not the locked project Python"); + const installed = Array.isArray(receipt.installed_distributions) ? receipt.installed_distributions.map(object) : []; + const declared = Array.isArray(object(manifest.environment).resolved_packages) ? (object(manifest.environment).resolved_packages as unknown[]).map(object) : []; + const installedPairs = installed.map((pin) => `${pin.name}==${pin.version}`).sort(); + const declaredPairs = new Set(declared.map((pin) => `${pin.name}==${pin.version}`)); + if (installedPairs.some((pin) => !declaredPairs.has(pin))) errors.push("inside-project installed distributions contain a package outside the exact lock inventory"); + if (receipt.installed_distributions_sha256 !== sha256Bytes(Buffer.from(canonicalize(installed)))) errors.push("installed distribution inventory hash is invalid"); + if (receipt.installed_distributions_sha256 !== object(manifest.environment).installed_distributions_sha256) errors.push("inside-project installed distribution inventory does not match the manifest"); + if (object(receipt.verifiers).version !== object(manifest.workload_contract).verifiers_version || object(receipt.verifiers).git_revision !== object(manifest.workload_contract).verifiers_git_revision) errors.push("execution receipt Verifiers version/commit does not match workload contract"); if (receipt.trace_sha256 !== sha256Bytes(artifacts.trace)) errors.push("execution receipt does not bind the supplied trace"); if (receipt.before_state_sha256 !== sha256Bytes(artifacts.beforeState) || receipt.after_state_sha256 !== sha256Bytes(artifacts.afterState)) errors.push("execution receipt does not bind before/after state"); if (receipt.seed_candidate_sha256 !== smoke.seed_candidate_sha256 || receipt.mutated_candidate_sha256 !== smoke.mutated_candidate_sha256) errors.push("candidate hashes are not bound to generated inputs"); @@ -256,6 +265,11 @@ function validatePayloadParity(manifest: JsonObject, artifacts: TransportArtifac if (parity.tools_sha256 !== toolsHash || call.tools_sha256 !== toolsHash) errors.push("upstream tools payload parity failed"); if (parity.sampling_sha256 !== samplingHash || call.sampling_sha256 !== samplingHash) errors.push("upstream sampling payload parity failed"); if (parity.context_overflow_behavior !== "fail" || call.context_overflow_behavior !== "fail") errors.push("context overflow must fail rather than lower max_tokens"); + let overflow: JsonObject = {}; + try { overflow = object(JSON.parse(artifacts.overflowReceipt.toString("utf8"))); } catch { errors.push("overflow probe receipt must be valid JSON"); } + if (parity.overflow_probe_receipt_sha256 !== sha256Bytes(artifacts.overflowReceipt)) errors.push("overflow probe receipt hash does not match supplied evidence"); + if (overflow.schema_version !== "understudy.synthetic_overflow_probe.v1" || overflow.failure !== "OverlongPromptError" || overflow.failed_before_sampling !== true || overflow.sample_calls !== 0 || overflow.tool_calls !== 0) errors.push("oversized probe did not fail before sampling and tool execution"); + if (overflow.requested_max_tokens !== requestSampling.max_tokens || overflow.effective_max_tokens !== requestSampling.max_tokens) errors.push("overflow probe changed requested max_tokens"); if (call.max_tokens !== requestSampling.max_tokens) errors.push("executed max_tokens differs from the requested payload"); const workload = object(manifest.workload_contract); const candidateTags = (Array.isArray(requestMessages) ? requestMessages : []).flatMap((message) => { @@ -274,7 +288,40 @@ function validatePayloadParity(manifest: JsonObject, artifacts: TransportArtifac if (workload.benchmark_prompt_sha256 !== sha256Bytes(Buffer.from(canonicalize(fixedMessages)))) errors.push("fixed benchmark prompt slot is not hash-bound independently of the candidate policy"); if (workload.tool_schema_sha256 !== toolsHash) errors.push("workload tool schema hash does not match tools artifact"); if (workload.package_inventory_sha256 !== object(manifest.environment).uv_lock_sha256) errors.push("workload package inventory hash does not match uv.lock"); - if (workload.mcp_version !== "1.29.0" || !Array.isArray(object(manifest.environment).resolved_packages) || !(object(manifest.environment).resolved_packages as unknown[]).map(object).some((pin) => pin.name === "mcp" && pin.version === "1.29.0")) errors.push("MCP must be pinned to 1.29.0 in the exact lock inventory"); + const pins = Array.isArray(object(manifest.environment).resolved_packages) ? (object(manifest.environment).resolved_packages as unknown[]).map(object) : []; + const verifierPin = pins.find((pin) => pin.name === "verifiers"); + const mcpPin = pins.find((pin) => pin.name === "mcp"); + if (!verifierPin || verifierPin.version !== workload.verifiers_version || verifierPin.git_revision !== workload.verifiers_git_revision) errors.push("Verifiers version/commit must exactly match the supplied lock inventory"); + if (!mcpPin || mcpPin.version !== workload.mcp_version) errors.push("MCP version must exactly match the supplied lock inventory"); +} + +function validateBundles(manifest: JsonObject, errors: string[]): void { + const optimizer = object(manifest.optimizer_input); + const endpoint = object(manifest.endpoint_bundle); + const lineage = object(manifest.candidate_lineage); + const gates = object(manifest.context_gates); + for (const [path, value] of [ + ["optimizer_input.input_bundle_sha256", optimizer.input_bundle_sha256], + ["endpoint_bundle.executable_bundle_sha256", endpoint.executable_bundle_sha256], + ["endpoint_bundle.environment_sha256", endpoint.environment_sha256], + ["endpoint_bundle.health_receipt_sha256", endpoint.health_receipt_sha256], + ["endpoint_bundle.model_attestation_sha256", endpoint.model_attestation_sha256], + ["candidate_lineage.parent_candidate_sha256", lineage.parent_candidate_sha256], + ["candidate_lineage.candidate_sha256", lineage.candidate_sha256], + ["candidate_lineage.prompt_sha256", lineage.prompt_sha256], + ["candidate_lineage.model_attestation_sha256", lineage.model_attestation_sha256], + ["candidate_lineage.checkpoint_sha256", lineage.checkpoint_sha256], + ["context_gates.source_context_sha256", gates.source_context_sha256], + ["context_gates.reflection_context_sha256", gates.reflection_context_sha256], + ] as [string, unknown][]) requireSha(errors, value, path); + if (endpoint.frozen !== true || endpoint.seed !== false) errors.push("endpoint executable bundle must be a frozen non-seed candidate"); + if (endpoint.executable_bundle_sha256 === optimizer.input_bundle_sha256) errors.push("optimizer input bundle must be distinct from the executable endpoint bundle"); + if (endpoint.environment_sha256 !== object(manifest.environment).uv_lock_sha256) errors.push("endpoint bundle environment does not match the admitted locked project"); + if (endpoint.model_attestation_sha256 !== lineage.model_attestation_sha256) errors.push("endpoint model attestation does not match candidate lineage"); + const expectedCandidate = sha256Bytes(Buffer.from(canonicalize({ parent_candidate_sha256: lineage.parent_candidate_sha256, prompt_sha256: lineage.prompt_sha256, model_attestation_sha256: lineage.model_attestation_sha256, checkpoint_sha256: lineage.checkpoint_sha256, executable_bundle_sha256: endpoint.executable_bundle_sha256 }))); + if (lineage.candidate_sha256 !== expectedCandidate) errors.push("candidate mutation is not bound to parent, prompt, model, checkpoint, and executable bundle"); + if (lineage.parent_candidate_sha256 === lineage.candidate_sha256) errors.push("candidate lineage is unchanged from its parent"); + if (gates.source_context_present !== true || gates.reflection_context_present !== true || gates.source_context_sha256 === gates.reflection_context_sha256) errors.push("distinct source and reflection context gates are required"); } function object(value: unknown): JsonObject { @@ -298,6 +345,7 @@ function validateEnvironment(manifest: JsonObject, errors: string[]): void { if (typeof environment.uv_version !== "string" || !EXACT_VERSION.test(environment.uv_version)) errors.push("environment.uv_version must be exact"); if (typeof environment.python_version !== "string" || !EXACT_VERSION.test(environment.python_version)) errors.push("environment.python_version must be exact"); requireSha(errors, environment.python_executable_sha256, "environment.python_executable_sha256"); + requireSha(errors, environment.installed_distributions_sha256, "environment.installed_distributions_sha256"); if (typeof environment.container_image_digest !== "string" || !IMAGE_DIGEST.test(environment.container_image_digest)) errors.push("environment.container_image_digest must be an immutable sha256 digest"); const pins = Array.isArray(environment.resolved_packages) ? environment.resolved_packages.map(object) : []; @@ -319,7 +367,7 @@ function validateEnvironment(manifest: JsonObject, errors: string[]): void { function validateSmoke(manifest: JsonObject, traceBytes: Uint8Array, errors: string[]): void { const smoke = object(manifest.mutation_smoke); if (smoke.runtime !== "standard-verifiers") errors.push("mutation_smoke.runtime must equal standard-verifiers"); - if (smoke.verifiers_version !== "0.2.1") errors.push("mutation_smoke.verifiers_version must equal 0.2.1"); + if (smoke.verifiers_version !== object(manifest.workload_contract).verifiers_version) errors.push("mutation_smoke.verifiers_version must match workload contract"); if (smoke.task_count !== 1) errors.push("mutation_smoke.task_count must equal 1"); if (!(number(smoke.calls) !== null && Number(smoke.calls) > 0)) errors.push("mutation_smoke.calls must be > 0"); if (!(number(smoke.nodes) !== null && Number(smoke.nodes) > 0)) errors.push("mutation_smoke.nodes must be > 0"); @@ -339,7 +387,7 @@ function validateSmoke(manifest: JsonObject, traceBytes: Uint8Array, errors: str const traces = Array.isArray(parsed) ? parsed : [parsed]; if (traces.length !== 1) { errors.push("mutation smoke trace must contain exactly one task"); return; } const trace = object(traces[0]); - if (trace.runtime !== "standard-verifiers" || trace.verifiers_version !== "0.2.1") errors.push("mutation smoke trace is not standard-Verifiers 0.2.1 evidence"); + if (trace.runtime !== "standard-verifiers" || trace.verifiers_version !== smoke.verifiers_version) errors.push("mutation smoke trace does not match the admitted standard-Verifiers version"); const calls = Array.isArray(trace.calls) ? trace.calls : []; const nodes = Array.isArray(trace.nodes) ? trace.nodes.map(object) : []; if (calls.length !== smoke.calls || calls.length === 0) errors.push("mutation_smoke.calls does not match a non-empty trace calls array"); @@ -388,6 +436,7 @@ function validateSpend(manifest: JsonObject, errors: string[]): { effective: Rec } } for (const lane of SPEND_LANES) if (effective[lane] < -1e-9) errors.push(`authorized transfers overdraw ${lane} allocation`); + if (total !== null && Math.max(0, prior ?? 0) + SPEND_LANES.reduce((sum, lane) => sum + Math.max(0, effective[lane]), 0) > total + 1e-9) errors.push("prior spend plus effective lane allocations exceeds campaign total"); const charged = Object.fromEntries(SPEND_LANES.map((lane) => [lane, 0])) as Record; const chargeIds = new Set(); @@ -429,10 +478,11 @@ export function validateCampaignAdmission(manifest: unknown, artifacts: Transpor validateSmoke(value, artifacts.trace, errors); validateExecutionReceipt(value, artifacts, errors); validatePayloadParity(value, artifacts, errors); + validateBundles(value, errors); const spend = validateSpend(value, errors); return { admission_only: true, compile_authorized: false, admitted: errors.length === 0, errors, fingerprints, tool_steps, effective_spend_caps_usd: spend.effective, cumulative_spend_usd: spend.cumulative }; } -export function readTransportArtifacts(paths: { request: string; response: string; tools: string; trace: string; executionReceipt: string; beforeState: string; afterState: string }): TransportArtifacts { - return { request: readFileSync(paths.request), response: readFileSync(paths.response), tools: readFileSync(paths.tools), trace: readFileSync(paths.trace), executionReceipt: readFileSync(paths.executionReceipt), beforeState: readFileSync(paths.beforeState), afterState: readFileSync(paths.afterState) }; +export function readTransportArtifacts(paths: { request: string; response: string; tools: string; trace: string; executionReceipt: string; beforeState: string; afterState: string; overflowReceipt: string }): TransportArtifacts { + return { request: readFileSync(paths.request), response: readFileSync(paths.response), tools: readFileSync(paths.tools), trace: readFileSync(paths.trace), executionReceipt: readFileSync(paths.executionReceipt), beforeState: readFileSync(paths.beforeState), afterState: readFileSync(paths.afterState), overflowReceipt: readFileSync(paths.overflowReceipt) }; } diff --git a/src/commands/campaigns.ts b/src/commands/campaigns.ts index 1aa0fe65..9410bed2 100644 --- a/src/commands/campaigns.ts +++ b/src/commands/campaigns.ts @@ -23,8 +23,9 @@ export function registerCampaignsCommand(program: Command): void { .requiredOption("--execution-receipt ", "Generated locked-project execution receipt") .requiredOption("--before-state ", "Generated before-state artifact") .requiredOption("--after-state ", "Generated after-state artifact") + .requiredOption("--overflow-receipt ", "Generated oversized-request failure receipt") .requiredOption("--smoke-generator ", "Provider-free generator inside the locked project") - .action((options: { manifest: string; project: string; request: string; response: string; tools: string; trace: string; executionReceipt: string; beforeState: string; afterState: string; smokeGenerator: string }) => { + .action((options: { manifest: string; project: string; request: string; response: string; tools: string; trace: string; executionReceipt: string; beforeState: string; afterState: string; overflowReceipt: string; smokeGenerator: string }) => { try { const project = resolve(options.project); const manifest = JSON.parse(readFileSync(resolve(options.manifest), "utf8")) as Record; @@ -41,17 +42,13 @@ export function registerCampaignsCommand(program: Command): void { const declaredPins = JSON.stringify(environment.resolved_packages); const lockedPins = JSON.stringify(parseUvLockPins(readFileSync(lock, "utf8"))); if (declaredPins !== lockedPins) throw new Error("resolved package pins do not exactly match uv.lock"); - const python = execFileSync("uv", ["python", "find", String(environment.python_version)], { encoding: "utf8" }).trim(); - const pythonVersion = execFileSync(python, ["-c", "import platform; print(platform.python_version())"], { encoding: "utf8" }).trim(); - if (pythonVersion !== environment.python_version) throw new Error(`python version mismatch: expected ${String(environment.python_version)}, got ${pythonVersion}`); - if (fileSha256(python) !== environment.python_executable_sha256) throw new Error("python executable hash does not match manifest"); const generator = resolve(options.smokeGenerator); if (generator !== join(project, "generate_smoke.py")) throw new Error("smoke generator must be generate_smoke.py inside the locked project"); - const comparisons = [["trace.json", options.trace], ["execution-receipt.json", options.executionReceipt], ["before-state.json", options.beforeState], ["after-state.json", options.afterState]] as const; + const comparisons = [["trace.json", options.trace], ["execution-receipt.json", options.executionReceipt], ["before-state.json", options.beforeState], ["after-state.json", options.afterState], ["overflow-receipt.json", options.overflowReceipt]] as const; const expected = new Map(comparisons.map(([generated, supplied]) => [generated, readFileSync(resolve(supplied))])); execFileSync("uv", ["run", "--project", ".", "--locked", "python", "generate_smoke.py", "--output", "generated"], { cwd: project, stdio: "pipe" }); for (const [generated] of comparisons) if (!readFileSync(join(project, "generated", generated)).equals(expected.get(generated)!)) throw new Error(`generated ${generated} differs from supplied fixture`); - const result = validateCampaignAdmission(manifest, readTransportArtifacts({ request: resolve(options.request), response: resolve(options.response), tools: resolve(options.tools), trace: resolve(options.trace), executionReceipt: resolve(options.executionReceipt), beforeState: resolve(options.beforeState), afterState: resolve(options.afterState) })); + const result = validateCampaignAdmission(manifest, readTransportArtifacts({ request: resolve(options.request), response: resolve(options.response), tools: resolve(options.tools), trace: resolve(options.trace), executionReceipt: resolve(options.executionReceipt), beforeState: resolve(options.beforeState), afterState: resolve(options.afterState), overflowReceipt: resolve(options.overflowReceipt) })); process.stdout.write(`${JSON.stringify(result, null, 2)}\n`); if (!result.admitted) process.exitCode = 1; } catch (error) { diff --git a/tests/campaign-admission-cli.test.mjs b/tests/campaign-admission-cli.test.mjs index 9baf477b..918ea256 100644 --- a/tests/campaign-admission-cli.test.mjs +++ b/tests/campaign-admission-cli.test.mjs @@ -1,6 +1,5 @@ import assert from "node:assert/strict"; import { execFileSync, spawnSync } from "node:child_process"; -import { createHash } from "node:crypto"; import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join, resolve } from "node:path"; @@ -8,16 +7,12 @@ import { it } from "node:test"; import { baseManifest } from "./helpers/campaign-admission-fixture.mjs"; const fixture = resolve("tests/fixtures/campaign-admission"); -const sha = (value) => createHash("sha256").update(value).digest("hex"); - it("campaigns admit reruns the exact locked generator and verifies its bytes", async (t) => { if (spawnSync("uv", ["--version"]).status !== 0) return t.skip("uv is unavailable"); const mod = await import("../dist/campaign-admission/index.js"); const { manifest } = baseManifest(mod); const project = join(fixture, "uv-project"); - const python = execFileSync("uv", ["python", "find", manifest.environment.python_version], { encoding: "utf8" }).trim(); manifest.environment.uv_version = execFileSync("uv", ["--version"], { encoding: "utf8" }).trim().match(/^uv\s+(\S+)/)[1]; - manifest.environment.python_executable_sha256 = sha(readFileSync(python)); const generated = join(project, "generated"); const temp = mkdtempSync(join(tmpdir(), "campaign-admission-cli-")); try { @@ -27,6 +22,7 @@ it("campaigns admit reruns the exact locked generator and verifies its bytes", a "--request", join(fixture, "request.json"), "--response", join(fixture, "response.json"), "--tools", join(fixture, "tools.json"), "--trace", join(generated, "trace.json"), "--execution-receipt", join(generated, "execution-receipt.json"), "--before-state", join(generated, "before-state.json"), "--after-state", join(generated, "after-state.json"), + "--overflow-receipt", join(generated, "overflow-receipt.json"), "--smoke-generator", join(project, "generate_smoke.py")]; const run = spawnSync("node", args, { encoding: "utf8", timeout: 30_000 }); assert.equal(run.status, 0, `${run.stderr}\n${run.stdout}`); diff --git a/tests/campaign-admission.test.mjs b/tests/campaign-admission.test.mjs index 771d530a..1c1a4e59 100644 --- a/tests/campaign-admission.test.mjs +++ b/tests/campaign-admission.test.mjs @@ -11,24 +11,22 @@ describe("campaign admission", () => { assert.equal(result.admission_only, true); assert.equal(result.compile_authorized, false); assert.equal(result.cumulative_spend_usd, 19); - assert.equal(result.tool_steps[0].raw_arguments_equal, false); + assert.equal(result.tool_steps[0].raw_arguments_equal, true); assert.equal(result.tool_steps[0].semantic_arguments_equal, true); assert.equal(result.tool_steps[0].mutation, true); }); - it("whitespace changes alter raw arguments while preserving semantic equality", async () => { + it("rejects whitespace-only raw argument drift even when semantics match", async () => { const mod = await import("../dist/campaign-admission/index.js"); const { manifest, artifacts } = baseManifest(mod); const response = JSON.parse(artifacts.response); - response.choices[0].message.tool_calls[0].function.arguments = '{"id":"alpha","status":"ready"}'; + response.choices[0].message.tool_calls[0].function.arguments = '{ "id": "alpha", "status": "ready" }'; const changed = Buffer.from(`${JSON.stringify(response)}\n`); const changedArtifacts = { ...artifacts, response: changed }; manifest.transport_fingerprints = mod.fingerprintTransport(changedArtifacts); - manifest.tool_steps = mod.fingerprintToolSteps(changedArtifacts); const result = mod.validateCampaignAdmission(manifest, changedArtifacts); - assert.equal(result.admitted, true, result.errors.join("\n")); - assert.equal(result.tool_steps[0].raw_arguments_equal, true); - assert.equal(result.tool_steps[0].semantic_arguments_equal, true); + assert.equal(result.admitted, false); + assert.match(result.errors.join("\n"), /raw argument mismatch/); }); it("rejects executed argument changes, missing/duplicate IDs, and non-string arguments", async () => { @@ -84,6 +82,15 @@ describe("campaign admission", () => { assert.match(result.errors.join("\n"), /prior spend plus new charges/); }); + it("reserves campaign total for prior spend plus effective lane allocations", async () => { + const mod = await import("../dist/campaign-admission/index.js"); + const { manifest, artifacts } = baseManifest(mod); + manifest.spend.prior_spend_usd = 11; + const result = mod.validateCampaignAdmission(manifest, artifacts); + assert.equal(result.admitted, false); + assert.match(result.errors.join("\n"), /prior spend plus effective lane allocations/); + }); + it("fails payload parity and max-token overflow downgrades closed", async () => { const mod = await import("../dist/campaign-admission/index.js"); const { manifest, artifacts } = baseManifest(mod); @@ -92,4 +99,55 @@ describe("campaign admission", () => { assert.equal(result.admitted, false); assert.match(result.errors.join("\n"), /context_overflow/); }); + + it("requires an executed overflow receipt with zero samples and tools", async () => { + const mod = await import("../dist/campaign-admission/index.js"); + const { manifest, artifacts } = baseManifest(mod); + const overflow = JSON.parse(artifacts.overflowReceipt); + overflow.sample_calls = 1; + const changed = { ...artifacts, overflowReceipt: Buffer.from(`${JSON.stringify(overflow)}\n`) }; + manifest.payload_parity.overflow_probe_receipt_sha256 = mod.sha256Bytes(changed.overflowReceipt); + const result = mod.validateCampaignAdmission(manifest, changed); + assert.equal(result.admitted, false); + assert.match(result.errors.join("\n"), /did not fail before sampling and tool execution/); + }); + + it("rejects external interpreters, no-project argv, and changed installed distributions", async () => { + const mod = await import("../dist/campaign-admission/index.js"); + for (const mutate of [ + (receipt) => { receipt.argv.splice(2, 0, "--no-project"); }, + (receipt) => { receipt.interpreter.path = "/usr/bin/python3"; }, + (receipt) => { receipt.installed_distributions[0].version = "999"; receipt.installed_distributions_sha256 = mod.semanticJsonSha256(Buffer.from(JSON.stringify(receipt.installed_distributions)), "installed"); }, + ]) { + const { manifest, artifacts } = baseManifest(mod); + const receipt = JSON.parse(artifacts.executionReceipt); + mutate(receipt); + const changed = { ...artifacts, executionReceipt: Buffer.from(`${JSON.stringify(receipt)}\n`) }; + manifest.mutation_smoke.execution_receipt_sha256 = mod.sha256Bytes(changed.executionReceipt); + const result = mod.validateCampaignAdmission(manifest, changed); + assert.equal(result.admitted, false); + assert.match(result.errors.join("\n"), /locked-project uv argv|cannot use --no-project|locked project Python|installed distributions/); + } + }); + + it("requires exact workload Verifiers version and commit pins without a global 0.2.1 constant", async () => { + const mod = await import("../dist/campaign-admission/index.js"); + const { manifest, artifacts } = baseManifest(mod); + manifest.workload_contract.verifiers_version = "0.2.2.dev77"; + const result = mod.validateCampaignAdmission(manifest, artifacts); + assert.equal(result.admitted, false); + assert.match(result.errors.join("\n"), /version\/commit|lock inventory|workload contract/); + assert.deepEqual(mod.publishedSchemaErrors(manifest).filter((error) => error.includes("verifiers_version")), []); + }); + + it("rejects unbound executable bundles, candidate lineage, and context gates", async () => { + const mod = await import("../dist/campaign-admission/index.js"); + const { manifest, artifacts } = baseManifest(mod); + manifest.endpoint_bundle.environment_sha256 = "e".repeat(64); + manifest.candidate_lineage.model_attestation_sha256 = "f".repeat(64); + manifest.context_gates.reflection_context_sha256 = manifest.context_gates.source_context_sha256; + const result = mod.validateCampaignAdmission(manifest, artifacts); + assert.equal(result.admitted, false); + assert.match(result.errors.join("\n"), /endpoint bundle environment|model attestation|context gates/); + }); }); diff --git a/tests/fixtures/campaign-admission/response.json b/tests/fixtures/campaign-admission/response.json index c32149a8..1a63a99d 100644 --- a/tests/fixtures/campaign-admission/response.json +++ b/tests/fixtures/campaign-admission/response.json @@ -1 +1 @@ -{"choices":[{"finish_reason":"tool_calls","message":{"role":"assistant","tool_calls":[{"id":"call-public-1","type":"function","function":{"name":"set-record","arguments":"{ \"status\": \"ready\", \"id\": \"alpha\" }"}}]}}]} +{"choices":[{"finish_reason":"tool_calls","message":{"role":"assistant","tool_calls":[{"id":"call-public-1","type":"function","function":{"name":"set-record","arguments":"{\"id\":\"alpha\",\"status\":\"ready\"}"}}]}}]} diff --git a/tests/fixtures/campaign-admission/uv-project/generate_smoke.py b/tests/fixtures/campaign-admission/uv-project/generate_smoke.py old mode 100755 new mode 100644 index b23667f5..d2398446 --- a/tests/fixtures/campaign-admission/uv-project/generate_smoke.py +++ b/tests/fixtures/campaign-admission/uv-project/generate_smoke.py @@ -1,14 +1,21 @@ #!/usr/bin/env python3 -"""Generate the public one-task mutation receipt through pinned Verifiers.""" +"""Generate provider-free evidence by executing pinned Verifiers 0.2.1.""" import argparse import asyncio import hashlib +import importlib.metadata import json +import os import platform +import sys +import time from pathlib import Path import verifiers as vf +from datasets import Dataset +from verifiers.clients import Client +from verifiers.types import AssistantMessage, Response, ResponseMessage, ToolCall ARGV = ["uv", "run", "--project", ".", "--locked", "python", "generate_smoke.py", "--output", "generated"] SEED = "Only inspect the synthetic record." @@ -17,8 +24,9 @@ {"role": "system", "content": f"{SEED}\n{CANDIDATE}"}, {"role": "user", "content": "Set synthetic record alpha to ready."}, ] -TOOLS = [{"type": "function", "function": {"name": "set-record", "description": "Mutate a public synthetic record.", "parameters": {"type": "object", "additionalProperties": False, "required": ["id", "status"], "properties": {"id": {"type": "string"}, "status": {"enum": ["ready"]}}}}}] SAMPLING = {"max_tokens": 256, "temperature": 0} +ARGUMENTS = '{"id":"alpha","status":"ready"}' +CALL_ID = "call-public-1" def canonical(value): @@ -33,69 +41,147 @@ def write_json(path, value): path.write_text(json.dumps(value, sort_keys=True, indent=2) + "\n", encoding="utf-8") -async def generate(output): - before = {"records": {"alpha": {"status": "pending"}}} - after = {"records": {"alpha": {"status": "ready"}}} - arguments = '{"id":"alpha","status":"ready"}' - call_id = "call-public-1" - - def assertion_fraction(state): - return 1.0 if state["after_state"]["records"]["alpha"]["status"] == "ready" else 0.0 - - state = { - "prompt": MESSAGES, - "completion": [{"role": "assistant", "tool_calls": [{"id": call_id, "name": "world_toolset_set-record", "arguments": arguments}]}], - "task": "public-synthetic-mutation-1", - "before_state": before, - "after_state": after, +class SyntheticClient(Client): + def __init__(self, *, overflow_limit=None): + super().__init__(object()) + self.sample_calls = 0 + self.overflow_limit = overflow_limit + + def setup_client(self, config): + return object() + + async def to_native_tool(self, tool): + return tool + + async def to_native_prompt(self, messages): + return messages, {} + + async def get_native_response(self, prompt, model, sampling_args, tools=None, **kwargs): + raise AssertionError("the synthetic client overrides get_response") + + async def raise_from_native_response(self, response): + return None + + async def from_native_response(self, response): + return response + + async def close(self): + return None + + async def get_response(self, prompt, model, sampling_args, tools=None, **kwargs): + if self.overflow_limit is not None and len(canonical([m.model_dump() for m in prompt])) > self.overflow_limit: + raise vf.OverlongPromptError("synthetic context limit exceeded") + self.sample_calls += 1 + if self.sample_calls == 1: + message = ResponseMessage(role="assistant", content=None, finish_reason="tool_calls", is_truncated=False, tool_calls=[ToolCall(id=CALL_ID, name="set-record", arguments=ARGUMENTS)]) + else: + message = ResponseMessage(role="assistant", content="done", finish_reason="stop", is_truncated=False) + return Response(id=f"synthetic-{self.sample_calls}", created=0, model=model, usage=None, message=message) + + +async def execute_mutation(): + records = {"alpha": {"status": "pending"}} + tool_calls = 0 + + def set_record(id: str, status: str) -> str: + """Mutate a public synthetic record.""" + nonlocal tool_calls + tool_calls += 1 + before = records[id]["status"] + records[id]["status"] = status + return canonical({"ok": True, "applied": before != status, "before": before, "after": status}) + set_record.__name__ = "set-record" + + dataset = Dataset.from_list([{"prompt": MESSAGES, "answer": "ready"}]) + env = vf.ToolEnv(tools=[set_record], dataset=dataset, max_turns=2, sampling_args=SAMPLING) + client = SyntheticClient() + before = {"records": json.loads(json.dumps(records))} + state = await env.rollout({"prompt": MESSAGES, "example_id": 0, "answer": "ready"}, client, "synthetic-local", SAMPLING) + after = {"records": json.loads(json.dumps(records))} + if tool_calls != 1 or before["records"]["alpha"]["status"] != "pending" or after["records"]["alpha"]["status"] != "ready": + raise RuntimeError("Verifiers ToolEnv did not execute the required state delta exactly once") + completion = state["trajectory"][0]["completion"][0] + result = state["trajectory"][1]["prompt"][-1] + return before, after, state, completion, result, tool_calls + + +async def execute_overflow_probe(): + tool_calls = 0 + + def set_record(id: str, status: str) -> str: + nonlocal tool_calls + tool_calls += 1 + return canonical({"ok": True}) + set_record.__name__ = "set-record" + + oversized = [{"role": "user", "content": "x" * 4096}] + env = vf.ToolEnv(tools=[set_record], dataset=Dataset.from_list([{"prompt": oversized}]), max_turns=1, sampling_args=SAMPLING) + client = SyntheticClient(overflow_limit=128) + state = await env.rollout({"prompt": oversized, "example_id": 0}, client, "synthetic-local", SAMPLING) + failure = "OverlongPromptError" if state.get("prompt_too_long") else (type(state.get("error")).__name__ if state.get("error") else None) + if failure != "OverlongPromptError" or client.sample_calls != 0 or tool_calls != 0 or state["trajectory"]: + raise RuntimeError(f"oversized Verifiers probe did not fail before sampling/tool execution: failure={failure} samples={client.sample_calls} tools={tool_calls} trajectory={len(state['trajectory'])} error={state.get('error')!r}") + return { + "schema_version": "understudy.synthetic_overflow_probe.v1", + "failure": failure, + "failed_before_sampling": True, + "sample_calls": client.sample_calls, + "tool_calls": tool_calls, + "trajectory_steps": len(state["trajectory"]), + "oversized_request_sha256": sha_bytes(canonical(oversized).encode()), + "requested_max_tokens": SAMPLING["max_tokens"], + "effective_max_tokens": state["sampling_args"]["max_tokens"], } - rubric = vf.Rubric(funcs=[assertion_fraction]) - await rubric.score_rollout(state) - assertion = state["metrics"]["assertion_fraction"] - if assertion != 1.0: - raise RuntimeError("pinned Verifiers rubric did not accept the synthetic mutation") + +async def generate(output): + before, after, state, completion, result, tool_calls = await execute_mutation() + overflow = await execute_overflow_probe() output.mkdir(parents=True, exist_ok=True) - before_path = output / "before-state.json" - after_path = output / "after-state.json" - trace_path = output / "trace.json" + before_path, after_path, trace_path = output / "before-state.json", output / "after-state.json", output / "trace.json" write_json(before_path, before) write_json(after_path, after) + write_json(output / "overflow-receipt.json", overflow) + tools = [{"type": "function", "function": {"name": "set-record", "description": "Mutate a public synthetic record.", "parameters": env_tool_schema()}}] trace = { - "runtime": "standard-verifiers", - "verifiers_version": vf.__version__, - "task": {"data": {"task_id": state["task"], "split": "train"}}, - "rewards": {"assertion_fraction": assertion}, - "metrics": {"assertion_fraction": assertion}, - "errors": [], - "ok": True, - "calls": [{"node": 2, "model": "synthetic-local", "endpoint": "/chat/completions", "finish_reason": "tool_calls", "messages_sha256": sha_bytes(canonical(MESSAGES).encode()), "tools_sha256": sha_bytes(canonical(TOOLS).encode()), "sampling_sha256": sha_bytes(canonical(SAMPLING).encode()), "max_tokens": 256, "context_overflow_behavior": "fail"}], + "runtime": "standard-verifiers", "verifiers_version": vf.__version__, + "task": {"data": {"task_id": "public-synthetic-mutation-1", "split": "train"}}, + "rewards": {"assertion_fraction": 1.0}, "metrics": {"assertion_fraction": 1.0}, "errors": [], "ok": True, + "calls": [{"node": 2, "model": "synthetic-local", "endpoint": "/chat/completions", "finish_reason": "tool_calls", "messages_sha256": sha_bytes(canonical(MESSAGES).encode()), "tools_sha256": sha_bytes(canonical(tools).encode()), "sampling_sha256": sha_bytes(canonical(SAMPLING).encode()), "max_tokens": 256, "context_overflow_behavior": "fail"}], "nodes": [ - {"message": MESSAGES[0], "sampled": False}, - {"parent": 0, "message": MESSAGES[1], "sampled": False}, - {"parent": 1, "message": state["completion"][0], "sampled": True}, - {"parent": 2, "message": {"role": "tool", "tool_call_id": call_id, "name": "world_toolset_set-record", "content": canonical({"ok": True, "applied": True, "before": "pending", "after": "ready"})}, "sampled": False}, + {"message": MESSAGES[0], "sampled": False}, {"parent": 0, "message": MESSAGES[1], "sampled": False}, + {"parent": 1, "message": completion.model_dump(exclude_none=True), "sampled": True}, + {"parent": 2, "message": {**result.model_dump(exclude_none=True), "name": "world_toolset_set-record"}, "sampled": False}, ], + "execution": {"verifiers_trajectory_steps": len(state["trajectory"]), "tool_calls": tool_calls}, } write_json(trace_path, trace) - - lock_path = Path("uv.lock") + installed = sorted(({"name": d.metadata["Name"].lower().replace("_", "-"), "version": d.version} for d in importlib.metadata.distributions()), key=lambda x: (x["name"], x["version"])) + executable = str(Path(sys.executable).absolute()) + project_root = str(Path.cwd().resolve()) + if not executable.startswith(str(Path(project_root, ".venv").absolute()) + os.sep): + raise RuntimeError("generator is not running inside the exact project .venv") + verifiers_dist = importlib.metadata.distribution("verifiers") + direct_url = json.loads(verifiers_dist.read_text("direct_url.json") or "{}") + verifiers_commit = direct_url.get("vcs_info", {}).get("commit_id") + if not isinstance(verifiers_commit, str) or len(verifiers_commit) != 40: + raise RuntimeError("installed Verifiers distribution lacks an exact git commit") receipt = { - "schema_version": "understudy.synthetic_verifiers_execution.v1", - "argv": ARGV, - "interpreter": {"implementation": platform.python_implementation(), "version": platform.python_version()}, - "resolved_package_inventory_sha256": sha_bytes(lock_path.read_bytes()), - "verifiers": {"version": vf.__version__, "module": "verifiers"}, - "seed_candidate_sha256": sha_bytes(SEED.encode()), - "mutated_candidate_sha256": sha_bytes(CANDIDATE.encode()), - "before_state_sha256": sha_bytes(before_path.read_bytes()), - "after_state_sha256": sha_bytes(after_path.read_bytes()), - "trace_sha256": sha_bytes(trace_path.read_bytes()), - "verified_state_delta": {"path": "/records/alpha/status", "before": "pending", "after": "ready"}, + "schema_version": "understudy.synthetic_verifiers_execution.v1", "argv": ARGV, + "interpreter": {"implementation": platform.python_implementation(), "version": platform.python_version(), "path": str(Path(executable).relative_to(project_root)), "path_kind": "project_relative", "executable_sha256": sha_bytes(Path(executable).read_bytes())}, + "installed_distributions": installed, "installed_distributions_sha256": sha_bytes(canonical(installed).encode()), + "verifiers": {"version": vf.__version__, "module": "verifiers", "git_revision": verifiers_commit}, + "seed_candidate_sha256": sha_bytes(SEED.encode()), "mutated_candidate_sha256": sha_bytes(CANDIDATE.encode()), + "before_state_sha256": sha_bytes(before_path.read_bytes()), "after_state_sha256": sha_bytes(after_path.read_bytes()), "trace_sha256": sha_bytes(trace_path.read_bytes()), + "verified_state_delta": {"path": "/records/alpha/status", "before": "pending", "after": "ready", "independently_asserted": True}, } write_json(output / "execution-receipt.json", receipt) +def env_tool_schema(): + return {"type": "object", "additionalProperties": False, "required": ["id", "status"], "properties": {"id": {"type": "string"}, "status": {"enum": ["ready"]}}} + + if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--output", default="generated") diff --git a/tests/fixtures/campaign-admission/uv-project/generated/execution-receipt.json b/tests/fixtures/campaign-admission/uv-project/generated/execution-receipt.json index 97e1a08f..de8e86ae 100644 --- a/tests/fixtures/campaign-admission/uv-project/generated/execution-receipt.json +++ b/tests/fixtures/campaign-admission/uv-project/generated/execution-receipt.json @@ -12,21 +12,444 @@ "generated" ], "before_state_sha256": "9e4f76c756726a6c01f052f18b08db9fa2e073cd5e074f7693d55159d5f99612", + "installed_distributions": [ + { + "name": "aiofiles", + "version": "25.1.0" + }, + { + "name": "aiohappyeyeballs", + "version": "2.7.1" + }, + { + "name": "aiohttp", + "version": "3.14.3" + }, + { + "name": "aiolimiter", + "version": "1.2.1" + }, + { + "name": "aiosignal", + "version": "1.4.0" + }, + { + "name": "annotated-doc", + "version": "0.0.5" + }, + { + "name": "annotated-types", + "version": "0.8.0" + }, + { + "name": "anthropic", + "version": "0.120.2" + }, + { + "name": "antlr4-python3-runtime", + "version": "4.13.2" + }, + { + "name": "anyio", + "version": "4.14.2" + }, + { + "name": "attrs", + "version": "26.1.0" + }, + { + "name": "certifi", + "version": "2026.7.22" + }, + { + "name": "cffi", + "version": "2.1.1" + }, + { + "name": "charset-normalizer", + "version": "3.4.9" + }, + { + "name": "click", + "version": "8.4.2" + }, + { + "name": "connect-python", + "version": "0.9.0" + }, + { + "name": "cryptography", + "version": "50.0.0" + }, + { + "name": "datasets", + "version": "5.0.1" + }, + { + "name": "dill", + "version": "0.4.1" + }, + { + "name": "distro", + "version": "1.9.0" + }, + { + "name": "docstring-parser", + "version": "0.18.0" + }, + { + "name": "filelock", + "version": "3.32.2" + }, + { + "name": "frozenlist", + "version": "1.8.0" + }, + { + "name": "fsspec", + "version": "2026.6.0" + }, + { + "name": "gepa", + "version": "0.1.4" + }, + { + "name": "griffelib", + "version": "2.1.0" + }, + { + "name": "h11", + "version": "0.16.0" + }, + { + "name": "hf-xet", + "version": "1.6.0" + }, + { + "name": "httpcore", + "version": "1.0.9" + }, + { + "name": "httpx", + "version": "0.28.1" + }, + { + "name": "httpx-sse", + "version": "0.4.3" + }, + { + "name": "huggingface-hub", + "version": "1.26.0" + }, + { + "name": "idna", + "version": "3.18" + }, + { + "name": "jinja2", + "version": "3.1.6" + }, + { + "name": "jiter", + "version": "0.16.0" + }, + { + "name": "jsonschema", + "version": "4.26.0" + }, + { + "name": "jsonschema-specifications", + "version": "2025.9.1" + }, + { + "name": "latex2sympy2-extended", + "version": "1.11.0" + }, + { + "name": "loguru", + "version": "0.7.3" + }, + { + "name": "markdown-it-py", + "version": "4.2.0" + }, + { + "name": "markupsafe", + "version": "3.0.3" + }, + { + "name": "math-verify", + "version": "0.9.0" + }, + { + "name": "mcp", + "version": "1.29.0" + }, + { + "name": "mdurl", + "version": "0.1.2" + }, + { + "name": "mpmath", + "version": "1.3.0" + }, + { + "name": "msgpack", + "version": "1.2.1" + }, + { + "name": "multidict", + "version": "6.7.1" + }, + { + "name": "multiprocess", + "version": "0.70.19" + }, + { + "name": "numpy", + "version": "2.5.1" + }, + { + "name": "openai", + "version": "2.53.0" + }, + { + "name": "openai-agents", + "version": "0.19.3" + }, + { + "name": "openai-harmony", + "version": "0.0.8" + }, + { + "name": "opentelemetry-api", + "version": "1.44.0" + }, + { + "name": "packaging", + "version": "26.2" + }, + { + "name": "pandas", + "version": "3.0.5" + }, + { + "name": "prime-pydantic-config", + "version": "0.4.2" + }, + { + "name": "prime-sandboxes", + "version": "0.2.34" + }, + { + "name": "prime-tunnel", + "version": "0.1.10" + }, + { + "name": "propcache", + "version": "0.5.2" + }, + { + "name": "protobuf", + "version": "7.35.1" + }, + { + "name": "pyarrow", + "version": "25.0.0" + }, + { + "name": "pycparser", + "version": "3.0" + }, + { + "name": "pydantic", + "version": "2.13.4" + }, + { + "name": "pydantic-core", + "version": "2.46.4" + }, + { + "name": "pydantic-settings", + "version": "2.14.2" + }, + { + "name": "pygments", + "version": "2.20.0" + }, + { + "name": "pyjwt", + "version": "2.13.0" + }, + { + "name": "pyqwest", + "version": "0.8.0" + }, + { + "name": "python-dateutil", + "version": "2.9.0.post0" + }, + { + "name": "python-dotenv", + "version": "1.2.2" + }, + { + "name": "python-multipart", + "version": "0.0.32" + }, + { + "name": "pyyaml", + "version": "6.0.3" + }, + { + "name": "pyzmq", + "version": "27.1.0" + }, + { + "name": "referencing", + "version": "0.37.0" + }, + { + "name": "regex", + "version": "2026.7.19" + }, + { + "name": "renderers", + "version": "0.1.8" + }, + { + "name": "requests", + "version": "2.34.2" + }, + { + "name": "rich", + "version": "15.0.0" + }, + { + "name": "rpds-py", + "version": "2026.6.3" + }, + { + "name": "safetensors", + "version": "0.8.0" + }, + { + "name": "setproctitle", + "version": "1.3.7" + }, + { + "name": "shellingham", + "version": "1.5.4" + }, + { + "name": "six", + "version": "1.17.0" + }, + { + "name": "sniffio", + "version": "1.3.1" + }, + { + "name": "sse-starlette", + "version": "3.4.6" + }, + { + "name": "starlette", + "version": "1.3.1" + }, + { + "name": "sympy", + "version": "1.14.0" + }, + { + "name": "tenacity", + "version": "9.1.4" + }, + { + "name": "tiktoken", + "version": "0.13.0" + }, + { + "name": "tokenizers", + "version": "0.22.2" + }, + { + "name": "tomli", + "version": "2.4.1" + }, + { + "name": "tomli-w", + "version": "1.2.0" + }, + { + "name": "tqdm", + "version": "4.70.0" + }, + { + "name": "transformers", + "version": "5.14.1" + }, + { + "name": "typer", + "version": "0.27.1" + }, + { + "name": "typing-extensions", + "version": "4.16.0" + }, + { + "name": "typing-inspection", + "version": "0.4.2" + }, + { + "name": "urllib3", + "version": "2.7.0" + }, + { + "name": "uvicorn", + "version": "0.52.1" + }, + { + "name": "uvloop", + "version": "0.22.1" + }, + { + "name": "verifiers", + "version": "0.2.1" + }, + { + "name": "websockets", + "version": "16.1.1" + }, + { + "name": "xxhash", + "version": "3.8.1" + }, + { + "name": "yarl", + "version": "1.24.5" + } + ], + "installed_distributions_sha256": "d1693d46acb2bd255e700e847358bdabc19b35879a8ff187ed038e6dee6b5d01", "interpreter": { + "executable_sha256": "a395f264e5612a2819662ed3e37fd30d39ed61179b98e5f86c3c783a008d8623", "implementation": "CPython", + "path": ".venv/bin/python3", + "path_kind": "project_relative", "version": "3.12.13" }, "mutated_candidate_sha256": "0ba2e4298634b3771db51d77ffca15af1c7e731fc15c290b60ab5c44097c1f6c", - "resolved_package_inventory_sha256": "be34de4d14a135dac01c2649f6447b4abebde8242ff51cbf6d8bba2835d7c8dd", "schema_version": "understudy.synthetic_verifiers_execution.v1", "seed_candidate_sha256": "4dbee206fc073f8db3e50fad210ca48772e481ad31ee37f33e638bca91db1914", - "trace_sha256": "a60d2d3f6096130e1c0d999a24ec2170e697f03892f078f6db58d17398483ddf", + "trace_sha256": "cd9ffc6c1bb68e006481e0789a4a63bdbbc8b4ee066a8083228106595591d25b", "verified_state_delta": { "after": "ready", "before": "pending", + "independently_asserted": true, "path": "/records/alpha/status" }, "verifiers": { + "git_revision": "ab65b6e8d34b03d162408d4bcb854430a86809e6", "module": "verifiers", "version": "0.2.1" } diff --git a/tests/fixtures/campaign-admission/uv-project/generated/overflow-receipt.json b/tests/fixtures/campaign-admission/uv-project/generated/overflow-receipt.json new file mode 100644 index 00000000..9aa3e053 --- /dev/null +++ b/tests/fixtures/campaign-admission/uv-project/generated/overflow-receipt.json @@ -0,0 +1,11 @@ +{ + "effective_max_tokens": 256, + "failed_before_sampling": true, + "failure": "OverlongPromptError", + "oversized_request_sha256": "a47b86e783052357b1268c9ce2b1d1943d197a330f7863a2c2c21664da05008a", + "requested_max_tokens": 256, + "sample_calls": 0, + "schema_version": "understudy.synthetic_overflow_probe.v1", + "tool_calls": 0, + "trajectory_steps": 0 +} diff --git a/tests/fixtures/campaign-admission/uv-project/generated/trace.json b/tests/fixtures/campaign-admission/uv-project/generated/trace.json index 5a3a2bc3..584d8d22 100644 --- a/tests/fixtures/campaign-admission/uv-project/generated/trace.json +++ b/tests/fixtures/campaign-admission/uv-project/generated/trace.json @@ -13,6 +13,10 @@ } ], "errors": [], + "execution": { + "tool_calls": 1, + "verifiers_trajectory_steps": 2 + }, "metrics": { "assertion_fraction": 1.0 }, @@ -39,7 +43,7 @@ { "arguments": "{\"id\":\"alpha\",\"status\":\"ready\"}", "id": "call-public-1", - "name": "world_toolset_set-record" + "name": "set-record" } ] }, diff --git a/tests/helpers/campaign-admission-fixture.mjs b/tests/helpers/campaign-admission-fixture.mjs index 5dc2adcc..28ff64c9 100644 --- a/tests/helpers/campaign-admission-fixture.mjs +++ b/tests/helpers/campaign-admission-fixture.mjs @@ -8,7 +8,7 @@ const sha = (value) => createHash("sha256").update(value).digest("hex"); export function baseManifest(mod) { const generated = "uv-project/generated"; - const artifacts = { request: bytes("request.json"), response: bytes("response.json"), tools: bytes("tools.json"), trace: bytes(`${generated}/trace.json`), executionReceipt: bytes(`${generated}/execution-receipt.json`), beforeState: bytes(`${generated}/before-state.json`), afterState: bytes(`${generated}/after-state.json`) }; + const artifacts = { request: bytes("request.json"), response: bytes("response.json"), tools: bytes("tools.json"), trace: bytes(`${generated}/trace.json`), executionReceipt: bytes(`${generated}/execution-receipt.json`), beforeState: bytes(`${generated}/before-state.json`), afterState: bytes(`${generated}/after-state.json`), overflowReceipt: bytes(`${generated}/overflow-receipt.json`) }; const trace = JSON.parse(artifacts.trace); const receipt = JSON.parse(artifacts.executionReceipt); const request = JSON.parse(artifacts.request); @@ -17,12 +17,17 @@ export function baseManifest(mod) { const lockHash = sha(bytes("uv-project/uv.lock")); const manifest = { schema_version: "understudy.campaign_admission.v1", campaign_id: "public-synthetic-campaign", - environment: { pyproject_sha256: sha(bytes("uv-project/pyproject.toml")), uv_lock_sha256: lockHash, uv_lock_check_command: "uv lock --check", uv_lock_check_exit_code: 0, uv_version: "0.12.1", python_version: receipt.interpreter.version, python_executable_sha256: "1".repeat(64), container_image_digest: `sha256:${"2".repeat(64)}`, resolved_packages: mod.parseUvLockPins(bytes("uv-project/uv.lock").toString("utf8")) }, + environment: { pyproject_sha256: sha(bytes("uv-project/pyproject.toml")), uv_lock_sha256: lockHash, uv_lock_check_command: "uv lock --check", uv_lock_check_exit_code: 0, uv_version: "0.12.1", python_version: receipt.interpreter.version, python_executable_sha256: receipt.interpreter.executable_sha256, installed_distributions_sha256: receipt.installed_distributions_sha256, container_image_digest: `sha256:${"2".repeat(64)}`, resolved_packages: mod.parseUvLockPins(bytes("uv-project/uv.lock").toString("utf8")) }, transport_fingerprints: mod.fingerprintTransport(artifacts), tool_steps: mod.fingerprintToolSteps(artifacts), - payload_parity: { messages_sha256: semantic(request.messages), tools_sha256: semantic(JSON.parse(artifacts.tools)), sampling_sha256: semantic(request.sampling), context_overflow_behavior: "fail" }, - workload_contract: { benchmark_prompt_sha256: semantic(fixedMessages), candidate_source: "outer_system_transcript", candidate_tag_sha256: receipt.mutated_candidate_sha256, policy_injection_count: 1, mcp_version: "1.29.0", tool_schema_sha256: semantic(JSON.parse(artifacts.tools)), package_inventory_sha256: lockHash }, + payload_parity: { messages_sha256: semantic(request.messages), tools_sha256: semantic(JSON.parse(artifacts.tools)), sampling_sha256: semantic(request.sampling), context_overflow_behavior: "fail", overflow_probe_receipt_sha256: sha(artifacts.overflowReceipt) }, + workload_contract: { benchmark_prompt_sha256: semantic(fixedMessages), candidate_source: "outer_system_transcript", candidate_tag_sha256: receipt.mutated_candidate_sha256, policy_injection_count: 1, verifiers_version: "0.2.1", verifiers_git_revision: "ab65b6e8d34b03d162408d4bcb854430a86809e6", mcp_version: "1.29.0", tool_schema_sha256: semantic(JSON.parse(artifacts.tools)), package_inventory_sha256: lockHash }, + optimizer_input: { input_bundle_sha256: "3".repeat(64) }, + endpoint_bundle: { bundle_kind: "policy", schema_version: "understudy.policy.v1", executable_bundle_sha256: "4".repeat(64), environment_sha256: lockHash, health_receipt_sha256: "5".repeat(64), model_attestation_sha256: "6".repeat(64), frozen: true, seed: false }, + candidate_lineage: { parent_candidate_sha256: "7".repeat(64), candidate_sha256: "0".repeat(64), prompt_sha256: semantic(fixedMessages), model_attestation_sha256: "6".repeat(64), checkpoint_sha256: "8".repeat(64) }, + context_gates: { source_context_sha256: "9".repeat(64), reflection_context_sha256: "a".repeat(64), source_context_present: true, reflection_context_present: true }, mutation_smoke: { runtime: trace.runtime, verifiers_version: trace.verifiers_version, task_count: 1, calls: trace.calls.length, nodes: trace.nodes.length, assertion_fraction: trace.metrics.assertion_fraction, seed_candidate_sha256: receipt.seed_candidate_sha256, mutated_candidate_sha256: receipt.mutated_candidate_sha256, eval_exit_code: 0, trace_artifact_sha256: sha(artifacts.trace), execution_receipt_sha256: sha(artifacts.executionReceipt), mutating_effects: [{ tool: "set-record", applied: true }] }, - spend: { campaign_total_usd: 100, prior_spend_usd: 10, allocations: { optimizer: { cap_usd: 20 }, endpoint: { cap_usd: 50 }, training: { cap_usd: 30 } }, transfers: [], charges: [{ charge_id: "optimizer-1", lane: "optimizer", amount_usd: 2, immutable_receipt_sha256: "6".repeat(64) }, { charge_id: "endpoint-1", lane: "endpoint", amount_usd: 3, immutable_receipt_sha256: "7".repeat(64) }, { charge_id: "training-1", lane: "training", amount_usd: 4, immutable_receipt_sha256: "8".repeat(64) }] }, + spend: { campaign_total_usd: 100, prior_spend_usd: 10, allocations: { optimizer: { cap_usd: 20 }, endpoint: { cap_usd: 40 }, training: { cap_usd: 30 } }, transfers: [], charges: [{ charge_id: "optimizer-1", lane: "optimizer", amount_usd: 2, immutable_receipt_sha256: "b".repeat(64) }, { charge_id: "endpoint-1", lane: "endpoint", amount_usd: 3, immutable_receipt_sha256: "c".repeat(64) }, { charge_id: "training-1", lane: "training", amount_usd: 4, immutable_receipt_sha256: "d".repeat(64) }] }, }; + manifest.candidate_lineage.candidate_sha256 = semantic({ parent_candidate_sha256: manifest.candidate_lineage.parent_candidate_sha256, prompt_sha256: manifest.candidate_lineage.prompt_sha256, model_attestation_sha256: manifest.candidate_lineage.model_attestation_sha256, checkpoint_sha256: manifest.candidate_lineage.checkpoint_sha256, executable_bundle_sha256: manifest.endpoint_bundle.executable_bundle_sha256 }); return { artifacts, manifest }; } From 3f2d2da5c746c08411a1fed19c403c8ef69ad7e6 Mon Sep 17 00:00:00 2001 From: luis manrique <166242911+lluisinthedesert@users.noreply.github.com> Date: Tue, 4 Aug 2026 05:15:03 -0700 Subject: [PATCH 4/8] restore smoke generator executable mode --- tests/fixtures/campaign-admission/uv-project/generate_smoke.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 tests/fixtures/campaign-admission/uv-project/generate_smoke.py diff --git a/tests/fixtures/campaign-admission/uv-project/generate_smoke.py b/tests/fixtures/campaign-admission/uv-project/generate_smoke.py old mode 100644 new mode 100755 From 923d2101dc5ed0e356975a7a169ab9e5993692e8 Mon Sep 17 00:00:00 2001 From: luis manrique <166242911+lluisinthedesert@users.noreply.github.com> Date: Tue, 4 Aug 2026 05:32:29 -0700 Subject: [PATCH 5/8] bind campaign admission to immutable evidence --- ...derstudy.campaign_admission.v1.schema.json | 10 +- src/campaign-admission/index.ts | 60 +- src/commands/campaigns.ts | 8 +- tests/campaign-admission-cli.test.mjs | 8 +- tests/campaign-admission.test.mjs | 75 + .../fixtures/campaign-admission/request.json | 2 +- .../uv-project-generic/.python-version | 1 + .../uv-project-generic/generate_smoke.py | 253 +++ .../generated/after-state.json | 7 + .../generated/applicable-lock.json | 418 ++++ .../generated/before-state.json | 7 + .../generated/campaign-evidence.json | 83 + .../generated/execution-receipt.json | 892 +++++++++ .../generated/overflow-receipt.json | 16 + .../uv-project-generic/generated/trace.json | 80 + .../uv-project-generic/pyproject.toml | 10 + .../uv-project-generic/uv.lock | 1693 +++++++++++++++++ .../uv-project/generate_smoke.py | 84 +- .../uv-project/generated/applicable-lock.json | 418 ++++ .../generated/campaign-evidence.json | 83 + .../generated/execution-receipt.json | 440 ++++- .../generated/overflow-receipt.json | 7 +- .../uv-project/generated/trace.json | 6 +- tests/helpers/campaign-admission-fixture.mjs | 23 +- 24 files changed, 4639 insertions(+), 45 deletions(-) create mode 100644 tests/fixtures/campaign-admission/uv-project-generic/.python-version create mode 100755 tests/fixtures/campaign-admission/uv-project-generic/generate_smoke.py create mode 100644 tests/fixtures/campaign-admission/uv-project-generic/generated/after-state.json create mode 100644 tests/fixtures/campaign-admission/uv-project-generic/generated/applicable-lock.json create mode 100644 tests/fixtures/campaign-admission/uv-project-generic/generated/before-state.json create mode 100644 tests/fixtures/campaign-admission/uv-project-generic/generated/campaign-evidence.json create mode 100644 tests/fixtures/campaign-admission/uv-project-generic/generated/execution-receipt.json create mode 100644 tests/fixtures/campaign-admission/uv-project-generic/generated/overflow-receipt.json create mode 100644 tests/fixtures/campaign-admission/uv-project-generic/generated/trace.json create mode 100644 tests/fixtures/campaign-admission/uv-project-generic/pyproject.toml create mode 100644 tests/fixtures/campaign-admission/uv-project-generic/uv.lock create mode 100644 tests/fixtures/campaign-admission/uv-project/generated/applicable-lock.json create mode 100644 tests/fixtures/campaign-admission/uv-project/generated/campaign-evidence.json diff --git a/schemas/understudy.campaign_admission.v1.schema.json b/schemas/understudy.campaign_admission.v1.schema.json index 4dfa07d5..2f8f0110 100644 --- a/schemas/understudy.campaign_admission.v1.schema.json +++ b/schemas/understudy.campaign_admission.v1.schema.json @@ -5,10 +5,13 @@ "description": "Public, fail-closed campaign admission evidence. References and hashes only; never embeds customer prompts, traces, credentials, or answer keys.", "type": "object", "additionalProperties": false, - "required": ["schema_version", "campaign_id", "environment", "transport_fingerprints", "tool_steps", "payload_parity", "workload_contract", "optimizer_input", "endpoint_bundle", "candidate_lineage", "context_gates", "mutation_smoke", "spend"], + "required": ["schema_version", "campaign_id", "workload_id", "request_id", "execution_id", "environment", "transport_fingerprints", "tool_steps", "payload_parity", "workload_contract", "optimizer_input", "endpoint_bundle", "candidate_lineage", "context_gates", "mutation_smoke", "spend"], "properties": { "schema_version": { "const": "understudy.campaign_admission.v1" }, "campaign_id": { "type": "string", "minLength": 1 }, + "workload_id": { "type": "string", "minLength": 1 }, + "request_id": { "type": "string", "minLength": 1 }, + "execution_id": { "type": "string", "minLength": 1 }, "environment": { "$ref": "#/$defs/environment" }, "transport_fingerprints": { "$ref": "#/$defs/fingerprints" }, "tool_steps": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/tool_step" } }, @@ -27,7 +30,7 @@ "exact_version": { "type": "string", "pattern": "^[0-9][0-9A-Za-z.!+_-]*$" }, "environment": { "type": "object", "additionalProperties": false, - "required": ["pyproject_sha256", "uv_lock_sha256", "uv_lock_check_command", "uv_lock_check_exit_code", "uv_version", "python_version", "python_executable_sha256", "installed_distributions_sha256", "resolved_packages", "container_image_digest"], + "required": ["pyproject_sha256", "uv_lock_sha256", "uv_lock_check_command", "uv_lock_check_exit_code", "uv_version", "python_version", "python_executable_sha256", "installed_distributions_sha256", "applicable_lock_artifact_sha256", "resolved_packages", "container_image_digest"], "properties": { "pyproject_sha256": { "$ref": "#/$defs/sha256" }, "uv_lock_sha256": { "$ref": "#/$defs/sha256" }, @@ -37,6 +40,7 @@ "python_version": { "$ref": "#/$defs/exact_version" }, "python_executable_sha256": { "$ref": "#/$defs/sha256" }, "installed_distributions_sha256": { "$ref": "#/$defs/sha256" }, + "applicable_lock_artifact_sha256": { "$ref": "#/$defs/sha256" }, "container_image_digest": { "$ref": "#/$defs/image_digest" }, "resolved_packages": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/package_pin" } } } @@ -81,7 +85,7 @@ }, "optimizer_input": { "type": "object", "additionalProperties": false, "required": ["input_bundle_sha256"], "properties": { "input_bundle_sha256": { "$ref": "#/$defs/sha256" } } }, "endpoint_bundle": { "type": "object", "additionalProperties": false, "required": ["bundle_kind", "schema_version", "executable_bundle_sha256", "environment_sha256", "health_receipt_sha256", "model_attestation_sha256", "frozen", "seed"], "properties": { "bundle_kind": { "enum": ["policy", "checkpoint"] }, "schema_version": { "type": "string", "minLength": 1 }, "executable_bundle_sha256": { "$ref": "#/$defs/sha256" }, "environment_sha256": { "$ref": "#/$defs/sha256" }, "health_receipt_sha256": { "$ref": "#/$defs/sha256" }, "model_attestation_sha256": { "$ref": "#/$defs/sha256" }, "frozen": { "const": true }, "seed": { "const": false } } }, - "candidate_lineage": { "type": "object", "additionalProperties": false, "required": ["parent_candidate_sha256", "candidate_sha256", "prompt_sha256", "model_attestation_sha256", "checkpoint_sha256"], "properties": { "parent_candidate_sha256": { "$ref": "#/$defs/sha256" }, "candidate_sha256": { "$ref": "#/$defs/sha256" }, "prompt_sha256": { "$ref": "#/$defs/sha256" }, "model_attestation_sha256": { "$ref": "#/$defs/sha256" }, "checkpoint_sha256": { "$ref": "#/$defs/sha256" } } }, + "candidate_lineage": { "type": "object", "additionalProperties": false, "required": ["parent_candidate_sha256", "candidate_sha256", "prompt_sha256", "model_attestation_sha256", "checkpoint_sha256", "lineage_artifact_sha256"], "properties": { "parent_candidate_sha256": { "$ref": "#/$defs/sha256" }, "candidate_sha256": { "$ref": "#/$defs/sha256" }, "prompt_sha256": { "$ref": "#/$defs/sha256" }, "model_attestation_sha256": { "$ref": "#/$defs/sha256" }, "checkpoint_sha256": { "$ref": "#/$defs/sha256" }, "lineage_artifact_sha256": { "$ref": "#/$defs/sha256" } } }, "context_gates": { "type": "object", "additionalProperties": false, "required": ["source_context_sha256", "reflection_context_sha256", "source_context_present", "reflection_context_present"], "properties": { "source_context_sha256": { "$ref": "#/$defs/sha256" }, "reflection_context_sha256": { "$ref": "#/$defs/sha256" }, "source_context_present": { "const": true }, "reflection_context_present": { "const": true } } }, "mutation_smoke": { "type": "object", "additionalProperties": false, diff --git a/src/campaign-admission/index.ts b/src/campaign-admission/index.ts index 5e48134f..8ac11fab 100644 --- a/src/campaign-admission/index.ts +++ b/src/campaign-admission/index.ts @@ -17,6 +17,8 @@ export type TransportArtifacts = { beforeState: Buffer; afterState: Buffer; overflowReceipt: Buffer; + campaignEvidence: Buffer; + applicableLock: Buffer; }; export type TransportFingerprints = { @@ -225,6 +227,7 @@ function validateExecutionReceipt(manifest: JsonObject, artifacts: TransportArti const smoke = object(manifest.mutation_smoke); if (smoke.execution_receipt_sha256 !== sha256Bytes(artifacts.executionReceipt)) errors.push("mutation_smoke.execution_receipt_sha256 does not match supplied receipt"); if (receipt.schema_version !== "understudy.synthetic_verifiers_execution.v1") errors.push("synthetic execution receipt schema is invalid"); + validateIdentity(manifest, receipt, "execution receipt", errors); const argv = receipt.argv; if (canonicalize(argv) !== canonicalize(["uv", "run", "--project", ".", "--locked", "python", "generate_smoke.py", "--output", "generated"])) errors.push("synthetic smoke must use exact locked-project uv argv"); if (Array.isArray(argv) && argv.includes("--no-project")) errors.push("synthetic smoke cannot use --no-project"); @@ -232,16 +235,26 @@ function validateExecutionReceipt(manifest: JsonObject, artifacts: TransportArti if (interpreter.implementation !== "CPython" || interpreter.version !== object(manifest.environment).python_version) errors.push("execution receipt interpreter does not match the admitted project"); if (interpreter.path_kind !== "project_relative" || typeof interpreter.path !== "string" || !/^\.venv\/bin\/python[0-9.]*$/.test(interpreter.path) || interpreter.executable_sha256 !== object(manifest.environment).python_executable_sha256) errors.push("execution receipt interpreter path/hash is not the locked project Python"); const installed = Array.isArray(receipt.installed_distributions) ? receipt.installed_distributions.map(object) : []; + const applicable = Array.isArray(receipt.applicable_locked_distributions) ? receipt.applicable_locked_distributions.map(object) : []; + let applicableArtifact: unknown = []; + try { applicableArtifact = JSON.parse(artifacts.applicableLock.toString("utf8")); } catch { errors.push("applicable lock artifact must be valid JSON"); } const declared = Array.isArray(object(manifest.environment).resolved_packages) ? (object(manifest.environment).resolved_packages as unknown[]).map(object) : []; - const installedPairs = installed.map((pin) => `${pin.name}==${pin.version}`).sort(); - const declaredPairs = new Set(declared.map((pin) => `${pin.name}==${pin.version}`)); - if (installedPairs.some((pin) => !declaredPairs.has(pin))) errors.push("inside-project installed distributions contain a package outside the exact lock inventory"); + if (canonicalize(installed) !== canonicalize(applicable)) errors.push("installed distributions do not equal the exact applicable locked project inventory"); + if (canonicalize(applicable) !== canonicalize(applicableArtifact)) errors.push("applicable locked distributions do not match the supplied uv-export artifact"); if (receipt.installed_distributions_sha256 !== sha256Bytes(Buffer.from(canonicalize(installed)))) errors.push("installed distribution inventory hash is invalid"); + if (receipt.applicable_locked_distributions_sha256 !== sha256Bytes(Buffer.from(canonicalize(applicable)))) errors.push("applicable locked distribution inventory hash is invalid"); + if (receipt.applicable_lock_artifact_sha256 !== sha256Bytes(artifacts.applicableLock) || receipt.applicable_lock_artifact_sha256 !== object(manifest.environment).applicable_lock_artifact_sha256) errors.push("applicable lock artifact is not hash-bound to environment and receipt"); + const exclusions = Array.isArray(receipt.lock_exclusions) ? receipt.lock_exclusions.map(object) : []; + if (typeof receipt.root_package_name !== "string" || !exclusions.some((item) => item.name === receipt.root_package_name && item.reason === "root-non-installable-no-emit-project") || !exclusions.some((item) => item.reason === "platform-marker-not-applicable")) errors.push("root/non-installable and platform lock exclusions must be explicit"); if (receipt.installed_distributions_sha256 !== object(manifest.environment).installed_distributions_sha256) errors.push("inside-project installed distribution inventory does not match the manifest"); + const installedVerifier = installed.find((pin) => pin.name === "verifiers"); + const lockedVerifier = declared.find((pin) => pin.name === "verifiers"); + if (!installedVerifier || !lockedVerifier || installedVerifier.version !== lockedVerifier.version || lockedVerifier.git_revision !== object(receipt.verifiers).git_revision) errors.push("installed Verifiers must match the exact locked version and VCS commit"); if (object(receipt.verifiers).version !== object(manifest.workload_contract).verifiers_version || object(receipt.verifiers).git_revision !== object(manifest.workload_contract).verifiers_git_revision) errors.push("execution receipt Verifiers version/commit does not match workload contract"); if (receipt.trace_sha256 !== sha256Bytes(artifacts.trace)) errors.push("execution receipt does not bind the supplied trace"); if (receipt.before_state_sha256 !== sha256Bytes(artifacts.beforeState) || receipt.after_state_sha256 !== sha256Bytes(artifacts.afterState)) errors.push("execution receipt does not bind before/after state"); if (receipt.seed_candidate_sha256 !== smoke.seed_candidate_sha256 || receipt.mutated_candidate_sha256 !== smoke.mutated_candidate_sha256) errors.push("candidate hashes are not bound to generated inputs"); + if (receipt.assertion_rubric !== "verifiers.Rubric" || receipt.assertion_fraction !== smoke.assertion_fraction) errors.push("assertion_fraction is not bound to the executed standard-Verifiers Rubric receipt"); const delta = object(receipt.verified_state_delta); if (delta.path !== "/records/alpha/status" || delta.before !== "pending" || delta.after !== "ready") errors.push("execution receipt does not verify the required state delta"); if (object(object(before.records).alpha).status !== "pending" || object(object(after.records).alpha).status !== "ready") errors.push("before/after state artifacts do not contain the verified mutation"); @@ -253,6 +266,8 @@ function validatePayloadParity(manifest: JsonObject, artifacts: TransportArtifac try { request = object(JSON.parse(artifacts.request.toString("utf8"))); trace = object(JSON.parse(artifacts.trace.toString("utf8"))); } catch { errors.push("payload parity artifacts must be valid JSON"); return; } const parity = object(manifest.payload_parity); + validateIdentity(manifest, request, "request artifact", errors); + validateIdentity(manifest, trace, "execution trace", errors); const calls = Array.isArray(trace.calls) ? trace.calls.map(object) : []; const call = calls[0] ?? {}; const requestMessages = request.messages; @@ -268,6 +283,7 @@ function validatePayloadParity(manifest: JsonObject, artifacts: TransportArtifac let overflow: JsonObject = {}; try { overflow = object(JSON.parse(artifacts.overflowReceipt.toString("utf8"))); } catch { errors.push("overflow probe receipt must be valid JSON"); } if (parity.overflow_probe_receipt_sha256 !== sha256Bytes(artifacts.overflowReceipt)) errors.push("overflow probe receipt hash does not match supplied evidence"); + validateIdentity(manifest, overflow, "overflow receipt", errors); if (overflow.schema_version !== "understudy.synthetic_overflow_probe.v1" || overflow.failure !== "OverlongPromptError" || overflow.failed_before_sampling !== true || overflow.sample_calls !== 0 || overflow.tool_calls !== 0) errors.push("oversized probe did not fail before sampling and tool execution"); if (overflow.requested_max_tokens !== requestSampling.max_tokens || overflow.effective_max_tokens !== requestSampling.max_tokens) errors.push("overflow probe changed requested max_tokens"); if (call.max_tokens !== requestSampling.max_tokens) errors.push("executed max_tokens differs from the requested payload"); @@ -295,11 +311,23 @@ function validatePayloadParity(manifest: JsonObject, artifacts: TransportArtifac if (!mcpPin || mcpPin.version !== workload.mcp_version) errors.push("MCP version must exactly match the supplied lock inventory"); } -function validateBundles(manifest: JsonObject, errors: string[]): void { +function validateIdentity(manifest: JsonObject, artifact: JsonObject, label: string, errors: string[]): void { + for (const field of ["campaign_id", "workload_id", "request_id", "execution_id"]) { + if (artifact[field] !== manifest[field]) errors.push(`${label} ${field} does not match admitted identity`); + } +} + +function validateBundles(manifest: JsonObject, artifacts: TransportArtifacts, errors: string[]): void { const optimizer = object(manifest.optimizer_input); const endpoint = object(manifest.endpoint_bundle); const lineage = object(manifest.candidate_lineage); const gates = object(manifest.context_gates); + let evidence: JsonObject = {}; + try { evidence = object(JSON.parse(artifacts.campaignEvidence.toString("utf8"))); } catch { errors.push("campaign evidence bundle must be valid JSON"); } + validateIdentity(manifest, evidence, "campaign evidence", errors); + const evidenceNames = ["optimizer_input", "executable_bundle", "health_receipt", "model_attestation", "checkpoint", "lineage", "source_context", "reflection_context"]; + for (const name of evidenceNames) validateIdentity(manifest, object(evidence[name]), `campaign evidence ${name}`, errors); + const derived = Object.fromEntries(evidenceNames.map((name) => [name, sha256Bytes(Buffer.from(canonicalize(object(evidence[name]))))])) as Record; for (const [path, value] of [ ["optimizer_input.input_bundle_sha256", optimizer.input_bundle_sha256], ["endpoint_bundle.executable_bundle_sha256", endpoint.executable_bundle_sha256], @@ -315,13 +343,26 @@ function validateBundles(manifest: JsonObject, errors: string[]): void { ["context_gates.reflection_context_sha256", gates.reflection_context_sha256], ] as [string, unknown][]) requireSha(errors, value, path); if (endpoint.frozen !== true || endpoint.seed !== false) errors.push("endpoint executable bundle must be a frozen non-seed candidate"); + if (optimizer.input_bundle_sha256 !== derived.optimizer_input) errors.push("optimizer input hash is not derived from supplied immutable evidence"); + if (endpoint.executable_bundle_sha256 !== derived.executable_bundle || endpoint.health_receipt_sha256 !== derived.health_receipt || endpoint.model_attestation_sha256 !== derived.model_attestation) errors.push("endpoint bundle hashes are not derived from supplied immutable evidence"); + if (lineage.checkpoint_sha256 !== derived.checkpoint || gates.source_context_sha256 !== derived.source_context || gates.reflection_context_sha256 !== derived.reflection_context) errors.push("lineage/context hashes are not derived from supplied immutable evidence"); + if (derived.lineage !== lineage.lineage_artifact_sha256) errors.push("candidate lineage artifact hash is not derived from supplied immutable evidence"); if (endpoint.executable_bundle_sha256 === optimizer.input_bundle_sha256) errors.push("optimizer input bundle must be distinct from the executable endpoint bundle"); if (endpoint.environment_sha256 !== object(manifest.environment).uv_lock_sha256) errors.push("endpoint bundle environment does not match the admitted locked project"); if (endpoint.model_attestation_sha256 !== lineage.model_attestation_sha256) errors.push("endpoint model attestation does not match candidate lineage"); + const executableEvidence = object(evidence.executable_bundle); + const healthEvidence = object(evidence.health_receipt); + if (executableEvidence.environment_sha256 !== endpoint.environment_sha256 || executableEvidence.model_attestation_sha256 !== endpoint.model_attestation_sha256 || executableEvidence.checkpoint_sha256 !== lineage.checkpoint_sha256 || executableEvidence.frozen !== true) errors.push("executable artifact does not match endpoint environment/model/checkpoint attestation"); + if (healthEvidence.status !== "healthy" || healthEvidence.executable_bundle_sha256 !== endpoint.executable_bundle_sha256 || healthEvidence.environment_sha256 !== endpoint.environment_sha256 || healthEvidence.model_attestation_sha256 !== endpoint.model_attestation_sha256) errors.push("health artifact does not attest the admitted executable endpoint"); + if (object(evidence.lineage).parent_candidate_sha256 !== lineage.parent_candidate_sha256 || object(evidence.lineage).prompt_sha256 !== lineage.prompt_sha256 || object(evidence.lineage).model_attestation_sha256 !== lineage.model_attestation_sha256 || object(evidence.lineage).checkpoint_sha256 !== lineage.checkpoint_sha256 || object(evidence.lineage).executable_bundle_sha256 !== endpoint.executable_bundle_sha256 || object(evidence.lineage).health_receipt_sha256 !== endpoint.health_receipt_sha256) errors.push("candidate lineage claims do not match supplied lineage artifact"); const expectedCandidate = sha256Bytes(Buffer.from(canonicalize({ parent_candidate_sha256: lineage.parent_candidate_sha256, prompt_sha256: lineage.prompt_sha256, model_attestation_sha256: lineage.model_attestation_sha256, checkpoint_sha256: lineage.checkpoint_sha256, executable_bundle_sha256: endpoint.executable_bundle_sha256 }))); if (lineage.candidate_sha256 !== expectedCandidate) errors.push("candidate mutation is not bound to parent, prompt, model, checkpoint, and executable bundle"); if (lineage.parent_candidate_sha256 === lineage.candidate_sha256) errors.push("candidate lineage is unchanged from its parent"); if (gates.source_context_present !== true || gates.reflection_context_present !== true || gates.source_context_sha256 === gates.reflection_context_sha256) errors.push("distinct source and reflection context gates are required"); + if (object(evidence.source_context).kind !== "source" || object(evidence.reflection_context).kind !== "reflection") errors.push("source/reflection context artifacts have invalid kinds"); + let overflow: JsonObject = {}; + try { overflow = object(JSON.parse(artifacts.overflowReceipt.toString("utf8"))); } catch { /* reported elsewhere */ } + if (overflow.executable_bundle_sha256 !== endpoint.executable_bundle_sha256) errors.push("overflow probe is not bound to the admitted executable endpoint bundle"); } function object(value: unknown): JsonObject { @@ -346,6 +387,7 @@ function validateEnvironment(manifest: JsonObject, errors: string[]): void { if (typeof environment.python_version !== "string" || !EXACT_VERSION.test(environment.python_version)) errors.push("environment.python_version must be exact"); requireSha(errors, environment.python_executable_sha256, "environment.python_executable_sha256"); requireSha(errors, environment.installed_distributions_sha256, "environment.installed_distributions_sha256"); + requireSha(errors, environment.applicable_lock_artifact_sha256, "environment.applicable_lock_artifact_sha256"); if (typeof environment.container_image_digest !== "string" || !IMAGE_DIGEST.test(environment.container_image_digest)) errors.push("environment.container_image_digest must be an immutable sha256 digest"); const pins = Array.isArray(environment.resolved_packages) ? environment.resolved_packages.map(object) : []; @@ -359,9 +401,7 @@ function validateEnvironment(manifest: JsonObject, errors: string[]): void { if (typeof pin.version !== "string" || !EXACT_VERSION.test(pin.version)) errors.push(`${prefix}.version must be exact`); if (pin.git_revision !== null && pin.git_revision !== undefined && (typeof pin.git_revision !== "string" || !GIT_REVISION.test(pin.git_revision))) errors.push(`${prefix}.git_revision must be a full 40-character commit`); } - if (!pins.some((pin) => pin.name === "verifiers" && pin.version === "0.2.1" && typeof pin.git_revision === "string" && GIT_REVISION.test(pin.git_revision))) { - errors.push("environment.resolved_packages must pin verifiers 0.2.1 to a full git revision"); - } + if (!pins.some((pin) => pin.name === "verifiers" && typeof pin.version === "string" && EXACT_VERSION.test(pin.version) && typeof pin.git_revision === "string" && GIT_REVISION.test(pin.git_revision))) errors.push("environment.resolved_packages must pin Verifiers to an exact version and full git revision"); } function validateSmoke(manifest: JsonObject, traceBytes: Uint8Array, errors: string[]): void { @@ -478,11 +518,11 @@ export function validateCampaignAdmission(manifest: unknown, artifacts: Transpor validateSmoke(value, artifacts.trace, errors); validateExecutionReceipt(value, artifacts, errors); validatePayloadParity(value, artifacts, errors); - validateBundles(value, errors); + validateBundles(value, artifacts, errors); const spend = validateSpend(value, errors); return { admission_only: true, compile_authorized: false, admitted: errors.length === 0, errors, fingerprints, tool_steps, effective_spend_caps_usd: spend.effective, cumulative_spend_usd: spend.cumulative }; } -export function readTransportArtifacts(paths: { request: string; response: string; tools: string; trace: string; executionReceipt: string; beforeState: string; afterState: string; overflowReceipt: string }): TransportArtifacts { - return { request: readFileSync(paths.request), response: readFileSync(paths.response), tools: readFileSync(paths.tools), trace: readFileSync(paths.trace), executionReceipt: readFileSync(paths.executionReceipt), beforeState: readFileSync(paths.beforeState), afterState: readFileSync(paths.afterState), overflowReceipt: readFileSync(paths.overflowReceipt) }; +export function readTransportArtifacts(paths: { request: string; response: string; tools: string; trace: string; executionReceipt: string; beforeState: string; afterState: string; overflowReceipt: string; campaignEvidence: string; applicableLock: string }): TransportArtifacts { + return { request: readFileSync(paths.request), response: readFileSync(paths.response), tools: readFileSync(paths.tools), trace: readFileSync(paths.trace), executionReceipt: readFileSync(paths.executionReceipt), beforeState: readFileSync(paths.beforeState), afterState: readFileSync(paths.afterState), overflowReceipt: readFileSync(paths.overflowReceipt), campaignEvidence: readFileSync(paths.campaignEvidence), applicableLock: readFileSync(paths.applicableLock) }; } diff --git a/src/commands/campaigns.ts b/src/commands/campaigns.ts index 9410bed2..24c9f6cc 100644 --- a/src/commands/campaigns.ts +++ b/src/commands/campaigns.ts @@ -24,8 +24,10 @@ export function registerCampaignsCommand(program: Command): void { .requiredOption("--before-state ", "Generated before-state artifact") .requiredOption("--after-state ", "Generated after-state artifact") .requiredOption("--overflow-receipt ", "Generated oversized-request failure receipt") + .requiredOption("--campaign-evidence ", "Generated immutable campaign evidence bundle") + .requiredOption("--applicable-lock ", "Generated platform-applicable uv lock inventory") .requiredOption("--smoke-generator ", "Provider-free generator inside the locked project") - .action((options: { manifest: string; project: string; request: string; response: string; tools: string; trace: string; executionReceipt: string; beforeState: string; afterState: string; overflowReceipt: string; smokeGenerator: string }) => { + .action((options: { manifest: string; project: string; request: string; response: string; tools: string; trace: string; executionReceipt: string; beforeState: string; afterState: string; overflowReceipt: string; campaignEvidence: string; applicableLock: string; smokeGenerator: string }) => { try { const project = resolve(options.project); const manifest = JSON.parse(readFileSync(resolve(options.manifest), "utf8")) as Record; @@ -44,11 +46,11 @@ export function registerCampaignsCommand(program: Command): void { if (declaredPins !== lockedPins) throw new Error("resolved package pins do not exactly match uv.lock"); const generator = resolve(options.smokeGenerator); if (generator !== join(project, "generate_smoke.py")) throw new Error("smoke generator must be generate_smoke.py inside the locked project"); - const comparisons = [["trace.json", options.trace], ["execution-receipt.json", options.executionReceipt], ["before-state.json", options.beforeState], ["after-state.json", options.afterState], ["overflow-receipt.json", options.overflowReceipt]] as const; + const comparisons = [["trace.json", options.trace], ["execution-receipt.json", options.executionReceipt], ["before-state.json", options.beforeState], ["after-state.json", options.afterState], ["overflow-receipt.json", options.overflowReceipt], ["campaign-evidence.json", options.campaignEvidence], ["applicable-lock.json", options.applicableLock]] as const; const expected = new Map(comparisons.map(([generated, supplied]) => [generated, readFileSync(resolve(supplied))])); execFileSync("uv", ["run", "--project", ".", "--locked", "python", "generate_smoke.py", "--output", "generated"], { cwd: project, stdio: "pipe" }); for (const [generated] of comparisons) if (!readFileSync(join(project, "generated", generated)).equals(expected.get(generated)!)) throw new Error(`generated ${generated} differs from supplied fixture`); - const result = validateCampaignAdmission(manifest, readTransportArtifacts({ request: resolve(options.request), response: resolve(options.response), tools: resolve(options.tools), trace: resolve(options.trace), executionReceipt: resolve(options.executionReceipt), beforeState: resolve(options.beforeState), afterState: resolve(options.afterState), overflowReceipt: resolve(options.overflowReceipt) })); + const result = validateCampaignAdmission(manifest, readTransportArtifacts({ request: resolve(options.request), response: resolve(options.response), tools: resolve(options.tools), trace: resolve(options.trace), executionReceipt: resolve(options.executionReceipt), beforeState: resolve(options.beforeState), afterState: resolve(options.afterState), overflowReceipt: resolve(options.overflowReceipt), campaignEvidence: resolve(options.campaignEvidence), applicableLock: resolve(options.applicableLock) })); process.stdout.write(`${JSON.stringify(result, null, 2)}\n`); if (!result.admitted) process.exitCode = 1; } catch (error) { diff --git a/tests/campaign-admission-cli.test.mjs b/tests/campaign-admission-cli.test.mjs index 918ea256..fc1620ed 100644 --- a/tests/campaign-admission-cli.test.mjs +++ b/tests/campaign-admission-cli.test.mjs @@ -7,11 +7,11 @@ import { it } from "node:test"; import { baseManifest } from "./helpers/campaign-admission-fixture.mjs"; const fixture = resolve("tests/fixtures/campaign-admission"); -it("campaigns admit reruns the exact locked generator and verifies its bytes", async (t) => { +for (const projectName of ["uv-project", "uv-project-generic"]) it(`campaigns admit reruns the exact locked ${projectName} generator and verifies its bytes`, async (t) => { if (spawnSync("uv", ["--version"]).status !== 0) return t.skip("uv is unavailable"); const mod = await import("../dist/campaign-admission/index.js"); - const { manifest } = baseManifest(mod); - const project = join(fixture, "uv-project"); + const { manifest } = baseManifest(mod, projectName); + const project = join(fixture, projectName); manifest.environment.uv_version = execFileSync("uv", ["--version"], { encoding: "utf8" }).trim().match(/^uv\s+(\S+)/)[1]; const generated = join(project, "generated"); const temp = mkdtempSync(join(tmpdir(), "campaign-admission-cli-")); @@ -23,6 +23,8 @@ it("campaigns admit reruns the exact locked generator and verifies its bytes", a "--trace", join(generated, "trace.json"), "--execution-receipt", join(generated, "execution-receipt.json"), "--before-state", join(generated, "before-state.json"), "--after-state", join(generated, "after-state.json"), "--overflow-receipt", join(generated, "overflow-receipt.json"), + "--campaign-evidence", join(generated, "campaign-evidence.json"), + "--applicable-lock", join(generated, "applicable-lock.json"), "--smoke-generator", join(project, "generate_smoke.py")]; const run = spawnSync("node", args, { encoding: "utf8", timeout: 30_000 }); assert.equal(run.status, 0, `${run.stderr}\n${run.stdout}`); diff --git a/tests/campaign-admission.test.mjs b/tests/campaign-admission.test.mjs index 1c1a4e59..9240238a 100644 --- a/tests/campaign-admission.test.mjs +++ b/tests/campaign-admission.test.mjs @@ -140,6 +140,15 @@ describe("campaign admission", () => { assert.deepEqual(mod.publishedSchemaErrors(manifest).filter((error) => error.includes("verifiers_version")), []); }); + it("admits a genuinely different locked Verifiers 0.2.2.dev77 fixture", async () => { + const mod = await import("../dist/campaign-admission/index.js"); + const { manifest, artifacts } = baseManifest(mod, "uv-project-generic"); + assert.equal(manifest.workload_contract.verifiers_version, "0.2.2.dev77"); + assert.equal(manifest.workload_contract.verifiers_git_revision, "61e7394d45109d142deec768c3c459ab98111e91"); + const result = mod.validateCampaignAdmission(manifest, artifacts); + assert.equal(result.admitted, true, result.errors.join("\n")); + }); + it("rejects unbound executable bundles, candidate lineage, and context gates", async () => { const mod = await import("../dist/campaign-admission/index.js"); const { manifest, artifacts } = baseManifest(mod); @@ -150,4 +159,70 @@ describe("campaign admission", () => { assert.equal(result.admitted, false); assert.match(result.errors.join("\n"), /endpoint bundle environment|model attestation|context gates/); }); + + it("rejects campaign and workload identity substitution across immutable evidence", async () => { + const mod = await import("../dist/campaign-admission/index.js"); + for (const field of ["campaign_id", "workload_id"]) { + const { manifest, artifacts } = baseManifest(mod); + manifest[field] = `substituted-${field}`; + const result = mod.validateCampaignAdmission(manifest, artifacts); + assert.equal(result.admitted, false); + assert.match(result.errors.join("\n"), new RegExp(`${field} does not match admitted identity`)); + } + }); + + it("rejects arbitrary bundle and context hashes not derived from supplied artifacts", async () => { + const mod = await import("../dist/campaign-admission/index.js"); + const { manifest, artifacts } = baseManifest(mod); + manifest.optimizer_input.input_bundle_sha256 = "e".repeat(64); + manifest.endpoint_bundle.health_receipt_sha256 = "f".repeat(64); + manifest.context_gates.source_context_sha256 = "1".repeat(64); + const result = mod.validateCampaignAdmission(manifest, artifacts); + assert.equal(result.admitted, false); + assert.match(result.errors.join("\n"), /not derived from supplied immutable evidence/); + }); + + it("rejects omitted installed packages and missing Verifiers after receipt rehash", async () => { + const mod = await import("../dist/campaign-admission/index.js"); + for (const packageName of ["aiofiles", "verifiers"]) { + const { manifest, artifacts } = baseManifest(mod); + const receipt = JSON.parse(artifacts.executionReceipt); + receipt.installed_distributions = receipt.installed_distributions.filter((item) => item.name !== packageName); + receipt.installed_distributions_sha256 = mod.semanticJsonSha256(Buffer.from(JSON.stringify(receipt.installed_distributions)), "installed"); + manifest.environment.installed_distributions_sha256 = receipt.installed_distributions_sha256; + const changed = { ...artifacts, executionReceipt: Buffer.from(`${JSON.stringify(receipt)}\n`) }; + manifest.mutation_smoke.execution_receipt_sha256 = mod.sha256Bytes(changed.executionReceipt); + const result = mod.validateCampaignAdmission(manifest, changed); + assert.equal(result.admitted, false); + assert.match(result.errors.join("\n"), /exact applicable locked project inventory|installed Verifiers/); + } + }); + + it("rejects mismatched runtime and fabricated assertion metrics after artifact rehash", async () => { + const mod = await import("../dist/campaign-admission/index.js"); + { + const { manifest, artifacts } = baseManifest(mod); + const trace = JSON.parse(artifacts.trace); + trace.verifiers_version = "9.9.9"; + const changed = { ...artifacts, trace: Buffer.from(`${JSON.stringify(trace)}\n`) }; + manifest.transport_fingerprints = mod.fingerprintTransport(changed); + manifest.mutation_smoke.trace_artifact_sha256 = mod.sha256Bytes(changed.trace); + const result = mod.validateCampaignAdmission(manifest, changed); + assert.equal(result.admitted, false); + assert.match(result.errors.join("\n"), /does not match the admitted standard-Verifiers version|does not bind the supplied trace/); + } + { + const { manifest, artifacts } = baseManifest(mod); + const trace = JSON.parse(artifacts.trace); + trace.metrics.assertion_fraction = 0.5; + trace.rewards.assertion_fraction = 0.5; + const changed = { ...artifacts, trace: Buffer.from(`${JSON.stringify(trace)}\n`) }; + manifest.transport_fingerprints = mod.fingerprintTransport(changed); + manifest.mutation_smoke.trace_artifact_sha256 = mod.sha256Bytes(changed.trace); + manifest.mutation_smoke.assertion_fraction = 0.5; + const result = mod.validateCampaignAdmission(manifest, changed); + assert.equal(result.admitted, false); + assert.match(result.errors.join("\n"), /standard-Verifiers Rubric receipt|does not bind the supplied trace/); + } + }); }); diff --git a/tests/fixtures/campaign-admission/request.json b/tests/fixtures/campaign-admission/request.json index c5fd1dfc..d86aaa40 100644 --- a/tests/fixtures/campaign-admission/request.json +++ b/tests/fixtures/campaign-admission/request.json @@ -1 +1 @@ -{"messages":[{"role":"system","content":"Only inspect the synthetic record.\nSet record alpha to ready with set-record, then report success."},{"role":"user","content":"Set synthetic record alpha to ready."}],"model":"synthetic-local","sampling":{"max_tokens":256,"temperature":0}} +{"campaign_id":"public-synthetic-campaign","workload_id":"cedar-public-synthetic","request_id":"request-public-1","execution_id":"execution-public-1","messages":[{"role":"system","content":"Only inspect the synthetic record.\nSet record alpha to ready with set-record, then report success."},{"role":"user","content":"Set synthetic record alpha to ready."}],"model":"synthetic-local","sampling":{"max_tokens":256,"temperature":0}} diff --git a/tests/fixtures/campaign-admission/uv-project-generic/.python-version b/tests/fixtures/campaign-admission/uv-project-generic/.python-version new file mode 100644 index 00000000..28d9a01b --- /dev/null +++ b/tests/fixtures/campaign-admission/uv-project-generic/.python-version @@ -0,0 +1 @@ +3.12.13 diff --git a/tests/fixtures/campaign-admission/uv-project-generic/generate_smoke.py b/tests/fixtures/campaign-admission/uv-project-generic/generate_smoke.py new file mode 100755 index 00000000..fe7487d5 --- /dev/null +++ b/tests/fixtures/campaign-admission/uv-project-generic/generate_smoke.py @@ -0,0 +1,253 @@ +#!/usr/bin/env python3 +"""Generate provider-free evidence by executing pinned Verifiers 0.2.1.""" + +import argparse +import asyncio +import hashlib +import importlib.metadata +import json +import os +import platform +import sys +import subprocess +import tomllib +from pathlib import Path + +import verifiers as vf +from datasets import Dataset +from packaging.markers import default_environment +from packaging.requirements import Requirement +from verifiers.clients import Client +from verifiers.types import AssistantMessage, Response, ResponseMessage, ToolCall + +ARGV = ["uv", "run", "--project", ".", "--locked", "python", "generate_smoke.py", "--output", "generated"] +SEED = "Only inspect the synthetic record." +CANDIDATE = "Set record alpha to ready with set-record, then report success." +MESSAGES = [ + {"role": "system", "content": f"{SEED}\n{CANDIDATE}"}, + {"role": "user", "content": "Set synthetic record alpha to ready."}, +] +SAMPLING = {"max_tokens": 256, "temperature": 0} +ARGUMENTS = '{"id":"alpha","status":"ready"}' +CALL_ID = "call-public-1" +CAMPAIGN_ID = "public-synthetic-campaign" +WORKLOAD_ID = "cedar-public-synthetic" +REQUEST_ID = "request-public-1" +EXECUTION_ID = "execution-public-1" + + +def identity(): + return {"campaign_id": CAMPAIGN_ID, "workload_id": WORKLOAD_ID, "request_id": REQUEST_ID, "execution_id": EXECUTION_ID} + + +def canonical(value): + return json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=False) + + +def sha_bytes(value): + return hashlib.sha256(value).hexdigest() + + +def write_json(path, value): + path.write_text(json.dumps(value, sort_keys=True, indent=2) + "\n", encoding="utf-8") + + +class SyntheticClient(Client): + def __init__(self, *, overflow_limit=None): + super().__init__(object()) + self.sample_calls = 0 + self.overflow_limit = overflow_limit + + def setup_client(self, config): + return object() + + async def to_native_tool(self, tool): + return tool + + async def to_native_prompt(self, messages): + return messages, {} + + async def get_native_response(self, prompt, model, sampling_args, tools=None, **kwargs): + raise AssertionError("the synthetic client overrides get_response") + + async def raise_from_native_response(self, response): + return None + + async def from_native_response(self, response): + return response + + async def close(self): + return None + + async def get_response(self, prompt, model, sampling_args, tools=None, **kwargs): + if self.overflow_limit is not None and len(canonical([m.model_dump() for m in prompt])) > self.overflow_limit: + raise vf.OverlongPromptError("synthetic context limit exceeded") + self.sample_calls += 1 + if self.sample_calls == 1: + message = ResponseMessage(role="assistant", content=None, finish_reason="tool_calls", is_truncated=False, tool_calls=[ToolCall(id=CALL_ID, name="set-record", arguments=ARGUMENTS)]) + else: + message = ResponseMessage(role="assistant", content="done", finish_reason="stop", is_truncated=False) + return Response(id=f"synthetic-{self.sample_calls}", created=0, model=model, usage=None, message=message) + + +async def execute_mutation(): + records = {"alpha": {"status": "pending"}} + tool_calls = 0 + + def set_record(id: str, status: str) -> str: + """Mutate a public synthetic record.""" + nonlocal tool_calls + tool_calls += 1 + before = records[id]["status"] + records[id]["status"] = status + return canonical({"ok": True, "applied": before != status, "before": before, "after": status}) + set_record.__name__ = "set-record" + + async def assertion_fraction(state): + if records["alpha"]["status"] != "ready": + return 0.0 + tool_messages = [message for step in state["trajectory"] for message in step["prompt"] if getattr(message, "role", None) == "tool"] + return 1.0 if any(json.loads(message.content).get("after") == "ready" for message in tool_messages) else 0.0 + + dataset = Dataset.from_list([{"prompt": MESSAGES, "answer": "ready"}]) + env = vf.ToolEnv(tools=[set_record], dataset=dataset, max_turns=2, sampling_args=SAMPLING) + assertion_rubric = vf.Rubric(funcs=[assertion_fraction]) + env.add_rubric(assertion_rubric) + client = SyntheticClient() + before = {"records": json.loads(json.dumps(records))} + state = await env.rollout({"prompt": MESSAGES, "example_id": 0, "answer": "ready"}, client, "synthetic-local", SAMPLING) + await assertion_rubric.score_rollout(state) + assertion = state["metrics"].get("assertion_fraction") + after = {"records": json.loads(json.dumps(records))} + if tool_calls != 1 or assertion != 1.0 or before["records"]["alpha"]["status"] != "pending" or after["records"]["alpha"]["status"] != "ready": + raise RuntimeError("Verifiers ToolEnv did not execute the required state delta exactly once") + completion = state["trajectory"][0]["completion"][0] + result = state["trajectory"][1]["prompt"][-1] + return before, after, state, completion, result, tool_calls, assertion + + +async def execute_overflow_probe(executable_bundle_sha256): + tool_calls = 0 + + def set_record(id: str, status: str) -> str: + nonlocal tool_calls + tool_calls += 1 + return canonical({"ok": True}) + set_record.__name__ = "set-record" + + oversized = [{"role": "user", "content": "x" * 4096}] + env = vf.ToolEnv(tools=[set_record], dataset=Dataset.from_list([{"prompt": oversized}]), max_turns=1, sampling_args=SAMPLING) + client = SyntheticClient(overflow_limit=128) + state = await env.rollout({"prompt": oversized, "example_id": 0}, client, "synthetic-local", SAMPLING) + failure = "OverlongPromptError" if state.get("prompt_too_long") else (type(state.get("error")).__name__ if state.get("error") else None) + if failure != "OverlongPromptError" or client.sample_calls != 0 or tool_calls != 0 or state["trajectory"]: + raise RuntimeError(f"oversized Verifiers probe did not fail before sampling/tool execution: failure={failure} samples={client.sample_calls} tools={tool_calls} trajectory={len(state['trajectory'])} error={state.get('error')!r}") + return { + **identity(), + "executable_bundle_sha256": executable_bundle_sha256, + "schema_version": "understudy.synthetic_overflow_probe.v1", + "failure": failure, + "failed_before_sampling": True, + "sample_calls": client.sample_calls, + "tool_calls": tool_calls, + "trajectory_steps": len(state["trajectory"]), + "oversized_request_sha256": sha_bytes(canonical(oversized).encode()), + "requested_max_tokens": SAMPLING["max_tokens"], + "effective_max_tokens": state["sampling_args"]["max_tokens"], + } + + +async def generate(output): + before, after, state, completion, result, tool_calls, assertion = await execute_mutation() + output.mkdir(parents=True, exist_ok=True) + before_path, after_path, trace_path = output / "before-state.json", output / "after-state.json", output / "trace.json" + write_json(before_path, before) + write_json(after_path, after) + optimizer_input = {**identity(), "kind": "optimizer-input", "component": "actor", "source": "public-synthetic"} + model_attestation = {**identity(), "model": "synthetic-local", "provider": "provider-free"} + checkpoint = {**identity(), "checkpoint": "synthetic-checkpoint-v1"} + environment_sha256 = sha_bytes(Path("uv.lock").read_bytes()) + model_sha256, checkpoint_sha256 = sha_bytes(canonical(model_attestation).encode()), sha_bytes(canonical(checkpoint).encode()) + executable_bundle = {**identity(), "kind": "policy", "schema_version": "understudy.policy.v1", "policy": CANDIDATE, "frozen": True, "environment_sha256": environment_sha256, "model_attestation_sha256": model_sha256, "checkpoint_sha256": checkpoint_sha256} + executable_sha256 = sha_bytes(canonical(executable_bundle).encode()) + health_receipt = {**identity(), "status": "healthy", "route": "synthetic-local", "executable_bundle_sha256": executable_sha256, "environment_sha256": environment_sha256, "model_attestation_sha256": model_sha256} + lineage = {**identity(), "parent_candidate_sha256": sha_bytes(SEED.encode()), "prompt_sha256": sha_bytes(canonical(MESSAGES).encode()), "model_attestation_sha256": model_sha256, "checkpoint_sha256": checkpoint_sha256, "executable_bundle_sha256": executable_sha256, "health_receipt_sha256": sha_bytes(canonical(health_receipt).encode())} + evidence = { + "schema_version": "understudy.synthetic_campaign_evidence.v1", **identity(), + "optimizer_input": optimizer_input, "executable_bundle": executable_bundle, "health_receipt": health_receipt, + "model_attestation": model_attestation, "checkpoint": checkpoint, "lineage": lineage, + "source_context": {**identity(), "kind": "source", "context": "public synthetic source evidence"}, + "reflection_context": {**identity(), "kind": "reflection", "context": "public synthetic reflection evidence"}, + } + write_json(output / "campaign-evidence.json", evidence) + overflow = await execute_overflow_probe(sha_bytes(canonical(executable_bundle).encode())) + write_json(output / "overflow-receipt.json", overflow) + tools = [{"type": "function", "function": {"name": "set-record", "description": "Mutate a public synthetic record.", "parameters": env_tool_schema()}}] + trace = { + "runtime": "standard-verifiers", "verifiers_version": vf.__version__, **identity(), + "task": {"data": {"task_id": "public-synthetic-mutation-1", "split": "train"}}, + "rewards": {"assertion_fraction": assertion}, "metrics": {"assertion_fraction": assertion}, "errors": [], "ok": True, + "calls": [{"node": 2, "model": "synthetic-local", "endpoint": "/chat/completions", "finish_reason": "tool_calls", "messages_sha256": sha_bytes(canonical(MESSAGES).encode()), "tools_sha256": sha_bytes(canonical(tools).encode()), "sampling_sha256": sha_bytes(canonical(SAMPLING).encode()), "max_tokens": 256, "context_overflow_behavior": "fail"}], + "nodes": [ + {"message": MESSAGES[0], "sampled": False}, {"parent": 0, "message": MESSAGES[1], "sampled": False}, + {"parent": 1, "message": completion.model_dump(exclude_none=True), "sampled": True}, + {"parent": 2, "message": {**result.model_dump(exclude_none=True), "name": "world_toolset_set-record"}, "sampled": False}, + ], + "execution": {"verifiers_trajectory_steps": len(state["trajectory"]), "tool_calls": tool_calls}, + } + write_json(trace_path, trace) + installed = sorted(({"name": d.metadata["Name"].lower().replace("_", "-"), "version": d.version} for d in importlib.metadata.distributions()), key=lambda x: (x["name"], x["version"])) + installed_by_name = {item["name"]: item["version"] for item in installed} + exported = subprocess.run(["uv", "export", "--project", ".", "--locked", "--format", "requirements-txt", "--no-hashes", "--no-emit-project", "--no-annotate", "--no-header"], check=True, capture_output=True, text=True).stdout + applicable = [] + for line in exported.splitlines(): + if not line.strip() or line.startswith((" ", "-")): + continue + requirement = Requirement(line.rstrip(" \\")) + if requirement.marker is not None and not requirement.marker.evaluate(default_environment()): + continue + name = requirement.name.lower().replace("_", "-") + version = installed_by_name.get(name) + if version is None: + raise RuntimeError(f"applicable locked distribution {name} is not installed") + applicable.append({"name": name, "version": version}) + applicable.sort(key=lambda x: (x["name"], x["version"])) + if installed != applicable: + raise RuntimeError("installed distributions do not equal uv-exported applicable lock inventory") + applicable_path = output / "applicable-lock.json" + write_json(applicable_path, applicable) + executable = str(Path(sys.executable).absolute()) + project_root = str(Path.cwd().resolve()) + if not executable.startswith(str(Path(project_root, ".venv").absolute()) + os.sep): + raise RuntimeError("generator is not running inside the exact project .venv") + verifiers_dist = importlib.metadata.distribution("verifiers") + direct_url = json.loads(verifiers_dist.read_text("direct_url.json") or "{}") + verifiers_commit = direct_url.get("vcs_info", {}).get("commit_id") + if not isinstance(verifiers_commit, str) or len(verifiers_commit) != 40: + raise RuntimeError("installed Verifiers distribution lacks an exact git commit") + root_name = tomllib.loads(Path("pyproject.toml").read_text(encoding="utf-8"))["project"]["name"] + receipt = { + "schema_version": "understudy.synthetic_verifiers_execution.v1", **identity(), "argv": ARGV, + "interpreter": {"implementation": platform.python_implementation(), "version": platform.python_version(), "path": str(Path(executable).relative_to(project_root)), "path_kind": "project_relative", "executable_sha256": sha_bytes(Path(executable).read_bytes())}, + "installed_distributions": installed, "installed_distributions_sha256": sha_bytes(canonical(installed).encode()), + "applicable_locked_distributions": applicable, "applicable_locked_distributions_sha256": sha_bytes(canonical(applicable).encode()), + "applicable_lock_artifact_sha256": sha_bytes(applicable_path.read_bytes()), + "root_package_name": root_name, + "lock_exclusions": [{"name": root_name, "reason": "root-non-installable-no-emit-project"}, {"reason": "platform-marker-not-applicable"}], + "verifiers": {"version": vf.__version__, "module": "verifiers", "git_revision": verifiers_commit}, + "seed_candidate_sha256": sha_bytes(SEED.encode()), "mutated_candidate_sha256": sha_bytes(CANDIDATE.encode()), + "before_state_sha256": sha_bytes(before_path.read_bytes()), "after_state_sha256": sha_bytes(after_path.read_bytes()), "trace_sha256": sha_bytes(trace_path.read_bytes()), + "assertion_fraction": assertion, "assertion_rubric": "verifiers.Rubric", "verified_state_delta": {"path": "/records/alpha/status", "before": "pending", "after": "ready", "independently_asserted": True}, + } + write_json(output / "execution-receipt.json", receipt) + + +def env_tool_schema(): + return {"type": "object", "additionalProperties": False, "required": ["id", "status"], "properties": {"id": {"type": "string"}, "status": {"enum": ["ready"]}}} + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--output", default="generated") + args = parser.parse_args() + asyncio.run(generate(Path(args.output))) diff --git a/tests/fixtures/campaign-admission/uv-project-generic/generated/after-state.json b/tests/fixtures/campaign-admission/uv-project-generic/generated/after-state.json new file mode 100644 index 00000000..492eea14 --- /dev/null +++ b/tests/fixtures/campaign-admission/uv-project-generic/generated/after-state.json @@ -0,0 +1,7 @@ +{ + "records": { + "alpha": { + "status": "ready" + } + } +} diff --git a/tests/fixtures/campaign-admission/uv-project-generic/generated/applicable-lock.json b/tests/fixtures/campaign-admission/uv-project-generic/generated/applicable-lock.json new file mode 100644 index 00000000..91acf506 --- /dev/null +++ b/tests/fixtures/campaign-admission/uv-project-generic/generated/applicable-lock.json @@ -0,0 +1,418 @@ +[ + { + "name": "aiofiles", + "version": "25.1.0" + }, + { + "name": "aiohappyeyeballs", + "version": "2.7.1" + }, + { + "name": "aiohttp", + "version": "3.14.3" + }, + { + "name": "aiolimiter", + "version": "1.2.1" + }, + { + "name": "aiosignal", + "version": "1.4.0" + }, + { + "name": "annotated-doc", + "version": "0.0.5" + }, + { + "name": "annotated-types", + "version": "0.8.0" + }, + { + "name": "anthropic", + "version": "0.120.2" + }, + { + "name": "antlr4-python3-runtime", + "version": "4.13.2" + }, + { + "name": "anyio", + "version": "4.14.2" + }, + { + "name": "attrs", + "version": "26.1.0" + }, + { + "name": "certifi", + "version": "2026.7.22" + }, + { + "name": "cffi", + "version": "2.1.1" + }, + { + "name": "charset-normalizer", + "version": "3.4.9" + }, + { + "name": "click", + "version": "8.4.2" + }, + { + "name": "connect-python", + "version": "0.9.0" + }, + { + "name": "cryptography", + "version": "50.0.0" + }, + { + "name": "datasets", + "version": "5.0.1" + }, + { + "name": "dill", + "version": "0.4.1" + }, + { + "name": "distro", + "version": "1.9.0" + }, + { + "name": "docstring-parser", + "version": "0.18.0" + }, + { + "name": "filelock", + "version": "3.32.2" + }, + { + "name": "frozenlist", + "version": "1.8.0" + }, + { + "name": "fsspec", + "version": "2026.6.0" + }, + { + "name": "gepa", + "version": "0.1.4" + }, + { + "name": "griffelib", + "version": "2.1.0" + }, + { + "name": "h11", + "version": "0.16.0" + }, + { + "name": "hf-xet", + "version": "1.6.0" + }, + { + "name": "httpcore", + "version": "1.0.9" + }, + { + "name": "httpx", + "version": "0.28.1" + }, + { + "name": "httpx-sse", + "version": "0.4.3" + }, + { + "name": "huggingface-hub", + "version": "1.26.0" + }, + { + "name": "idna", + "version": "3.18" + }, + { + "name": "jinja2", + "version": "3.1.6" + }, + { + "name": "jiter", + "version": "0.16.0" + }, + { + "name": "jsonschema", + "version": "4.26.0" + }, + { + "name": "jsonschema-specifications", + "version": "2025.9.1" + }, + { + "name": "latex2sympy2-extended", + "version": "1.11.0" + }, + { + "name": "loguru", + "version": "0.7.3" + }, + { + "name": "markdown-it-py", + "version": "4.2.0" + }, + { + "name": "markupsafe", + "version": "3.0.3" + }, + { + "name": "math-verify", + "version": "0.9.0" + }, + { + "name": "mcp", + "version": "1.29.0" + }, + { + "name": "mdurl", + "version": "0.1.2" + }, + { + "name": "mpmath", + "version": "1.3.0" + }, + { + "name": "msgpack", + "version": "1.2.1" + }, + { + "name": "multidict", + "version": "6.7.1" + }, + { + "name": "multiprocess", + "version": "0.70.19" + }, + { + "name": "numpy", + "version": "2.5.1" + }, + { + "name": "openai", + "version": "2.53.0" + }, + { + "name": "openai-agents", + "version": "0.19.3" + }, + { + "name": "openai-harmony", + "version": "0.0.8" + }, + { + "name": "opentelemetry-api", + "version": "1.44.0" + }, + { + "name": "packaging", + "version": "26.2" + }, + { + "name": "pandas", + "version": "3.0.5" + }, + { + "name": "prime-pydantic-config", + "version": "0.4.2" + }, + { + "name": "prime-sandboxes", + "version": "0.2.34" + }, + { + "name": "prime-tunnel", + "version": "0.1.10" + }, + { + "name": "propcache", + "version": "0.5.2" + }, + { + "name": "protobuf", + "version": "7.35.1" + }, + { + "name": "pyarrow", + "version": "25.0.0" + }, + { + "name": "pycparser", + "version": "3.0" + }, + { + "name": "pydantic", + "version": "2.13.4" + }, + { + "name": "pydantic-core", + "version": "2.46.4" + }, + { + "name": "pydantic-settings", + "version": "2.14.2" + }, + { + "name": "pygments", + "version": "2.20.0" + }, + { + "name": "pyjwt", + "version": "2.13.0" + }, + { + "name": "pyqwest", + "version": "0.8.0" + }, + { + "name": "python-dateutil", + "version": "2.9.0.post0" + }, + { + "name": "python-dotenv", + "version": "1.2.2" + }, + { + "name": "python-multipart", + "version": "0.0.32" + }, + { + "name": "pyyaml", + "version": "6.0.3" + }, + { + "name": "pyzmq", + "version": "27.1.0" + }, + { + "name": "referencing", + "version": "0.37.0" + }, + { + "name": "regex", + "version": "2026.7.19" + }, + { + "name": "renderers", + "version": "0.1.9.dev10" + }, + { + "name": "requests", + "version": "2.34.2" + }, + { + "name": "rich", + "version": "15.0.0" + }, + { + "name": "rpds-py", + "version": "2026.6.3" + }, + { + "name": "safetensors", + "version": "0.8.0" + }, + { + "name": "setproctitle", + "version": "1.3.7" + }, + { + "name": "shellingham", + "version": "1.5.4" + }, + { + "name": "six", + "version": "1.17.0" + }, + { + "name": "sniffio", + "version": "1.3.1" + }, + { + "name": "sse-starlette", + "version": "3.4.6" + }, + { + "name": "starlette", + "version": "1.3.1" + }, + { + "name": "sympy", + "version": "1.14.0" + }, + { + "name": "tenacity", + "version": "9.1.4" + }, + { + "name": "tiktoken", + "version": "0.13.0" + }, + { + "name": "tokenizers", + "version": "0.22.2" + }, + { + "name": "tomli", + "version": "2.4.1" + }, + { + "name": "tomli-w", + "version": "1.2.0" + }, + { + "name": "tqdm", + "version": "4.70.0" + }, + { + "name": "transformers", + "version": "5.14.1" + }, + { + "name": "typer", + "version": "0.27.1" + }, + { + "name": "typing-extensions", + "version": "4.16.0" + }, + { + "name": "typing-inspection", + "version": "0.4.2" + }, + { + "name": "urllib3", + "version": "2.7.0" + }, + { + "name": "uvicorn", + "version": "0.52.1" + }, + { + "name": "uvloop", + "version": "0.22.1" + }, + { + "name": "verifiers", + "version": "0.2.2.dev77" + }, + { + "name": "websockets", + "version": "16.1.1" + }, + { + "name": "xxhash", + "version": "3.8.1" + }, + { + "name": "yarl", + "version": "1.24.5" + } +] diff --git a/tests/fixtures/campaign-admission/uv-project-generic/generated/before-state.json b/tests/fixtures/campaign-admission/uv-project-generic/generated/before-state.json new file mode 100644 index 00000000..1e43e886 --- /dev/null +++ b/tests/fixtures/campaign-admission/uv-project-generic/generated/before-state.json @@ -0,0 +1,7 @@ +{ + "records": { + "alpha": { + "status": "pending" + } + } +} diff --git a/tests/fixtures/campaign-admission/uv-project-generic/generated/campaign-evidence.json b/tests/fixtures/campaign-admission/uv-project-generic/generated/campaign-evidence.json new file mode 100644 index 00000000..0e7bef5e --- /dev/null +++ b/tests/fixtures/campaign-admission/uv-project-generic/generated/campaign-evidence.json @@ -0,0 +1,83 @@ +{ + "campaign_id": "public-synthetic-campaign", + "checkpoint": { + "campaign_id": "public-synthetic-campaign", + "checkpoint": "synthetic-checkpoint-v1", + "execution_id": "execution-public-1", + "request_id": "request-public-1", + "workload_id": "cedar-public-synthetic" + }, + "executable_bundle": { + "campaign_id": "public-synthetic-campaign", + "checkpoint_sha256": "267de74365c7b4321821fb7924ff0598c6c7a69abc38fa11bb889755ac5c09af", + "environment_sha256": "4495bb127a29363986a6cd3296cd5db49ce6f0f768dbea16723c7c48cdd70d5e", + "execution_id": "execution-public-1", + "frozen": true, + "kind": "policy", + "model_attestation_sha256": "c889573d7bc391c0df3d5d3d4cfec9d7a4ec006b34e934eb6f19bf55ef3e6c87", + "policy": "Set record alpha to ready with set-record, then report success.", + "request_id": "request-public-1", + "schema_version": "understudy.policy.v1", + "workload_id": "cedar-public-synthetic" + }, + "execution_id": "execution-public-1", + "health_receipt": { + "campaign_id": "public-synthetic-campaign", + "environment_sha256": "4495bb127a29363986a6cd3296cd5db49ce6f0f768dbea16723c7c48cdd70d5e", + "executable_bundle_sha256": "c2c8a323b8015162a33344491ba882c67e5fe2e3b6089b0ff3769ae3a0862d00", + "execution_id": "execution-public-1", + "model_attestation_sha256": "c889573d7bc391c0df3d5d3d4cfec9d7a4ec006b34e934eb6f19bf55ef3e6c87", + "request_id": "request-public-1", + "route": "synthetic-local", + "status": "healthy", + "workload_id": "cedar-public-synthetic" + }, + "lineage": { + "campaign_id": "public-synthetic-campaign", + "checkpoint_sha256": "267de74365c7b4321821fb7924ff0598c6c7a69abc38fa11bb889755ac5c09af", + "executable_bundle_sha256": "c2c8a323b8015162a33344491ba882c67e5fe2e3b6089b0ff3769ae3a0862d00", + "execution_id": "execution-public-1", + "health_receipt_sha256": "4d05f751c4a74eeb2775665fe10cfab44af0a944eb1e4ea26cbc7bcb348d8c29", + "model_attestation_sha256": "c889573d7bc391c0df3d5d3d4cfec9d7a4ec006b34e934eb6f19bf55ef3e6c87", + "parent_candidate_sha256": "4dbee206fc073f8db3e50fad210ca48772e481ad31ee37f33e638bca91db1914", + "prompt_sha256": "6f71099eedf6d5b161ceea52fa0663b0c104b5729a77d3a5f4264967b5853808", + "request_id": "request-public-1", + "workload_id": "cedar-public-synthetic" + }, + "model_attestation": { + "campaign_id": "public-synthetic-campaign", + "execution_id": "execution-public-1", + "model": "synthetic-local", + "provider": "provider-free", + "request_id": "request-public-1", + "workload_id": "cedar-public-synthetic" + }, + "optimizer_input": { + "campaign_id": "public-synthetic-campaign", + "component": "actor", + "execution_id": "execution-public-1", + "kind": "optimizer-input", + "request_id": "request-public-1", + "source": "public-synthetic", + "workload_id": "cedar-public-synthetic" + }, + "reflection_context": { + "campaign_id": "public-synthetic-campaign", + "context": "public synthetic reflection evidence", + "execution_id": "execution-public-1", + "kind": "reflection", + "request_id": "request-public-1", + "workload_id": "cedar-public-synthetic" + }, + "request_id": "request-public-1", + "schema_version": "understudy.synthetic_campaign_evidence.v1", + "source_context": { + "campaign_id": "public-synthetic-campaign", + "context": "public synthetic source evidence", + "execution_id": "execution-public-1", + "kind": "source", + "request_id": "request-public-1", + "workload_id": "cedar-public-synthetic" + }, + "workload_id": "cedar-public-synthetic" +} diff --git a/tests/fixtures/campaign-admission/uv-project-generic/generated/execution-receipt.json b/tests/fixtures/campaign-admission/uv-project-generic/generated/execution-receipt.json new file mode 100644 index 00000000..f6b9319b --- /dev/null +++ b/tests/fixtures/campaign-admission/uv-project-generic/generated/execution-receipt.json @@ -0,0 +1,892 @@ +{ + "after_state_sha256": "578c4dc9e95cf9ef87e1ccd5f2236a61cc2faf0a120d16f52f871643f3675a34", + "applicable_lock_artifact_sha256": "068760dfb2d550852f70a0c759e4af1f5fec30577b510ecc1571c8136fd4fdf6", + "applicable_locked_distributions": [ + { + "name": "aiofiles", + "version": "25.1.0" + }, + { + "name": "aiohappyeyeballs", + "version": "2.7.1" + }, + { + "name": "aiohttp", + "version": "3.14.3" + }, + { + "name": "aiolimiter", + "version": "1.2.1" + }, + { + "name": "aiosignal", + "version": "1.4.0" + }, + { + "name": "annotated-doc", + "version": "0.0.5" + }, + { + "name": "annotated-types", + "version": "0.8.0" + }, + { + "name": "anthropic", + "version": "0.120.2" + }, + { + "name": "antlr4-python3-runtime", + "version": "4.13.2" + }, + { + "name": "anyio", + "version": "4.14.2" + }, + { + "name": "attrs", + "version": "26.1.0" + }, + { + "name": "certifi", + "version": "2026.7.22" + }, + { + "name": "cffi", + "version": "2.1.1" + }, + { + "name": "charset-normalizer", + "version": "3.4.9" + }, + { + "name": "click", + "version": "8.4.2" + }, + { + "name": "connect-python", + "version": "0.9.0" + }, + { + "name": "cryptography", + "version": "50.0.0" + }, + { + "name": "datasets", + "version": "5.0.1" + }, + { + "name": "dill", + "version": "0.4.1" + }, + { + "name": "distro", + "version": "1.9.0" + }, + { + "name": "docstring-parser", + "version": "0.18.0" + }, + { + "name": "filelock", + "version": "3.32.2" + }, + { + "name": "frozenlist", + "version": "1.8.0" + }, + { + "name": "fsspec", + "version": "2026.6.0" + }, + { + "name": "gepa", + "version": "0.1.4" + }, + { + "name": "griffelib", + "version": "2.1.0" + }, + { + "name": "h11", + "version": "0.16.0" + }, + { + "name": "hf-xet", + "version": "1.6.0" + }, + { + "name": "httpcore", + "version": "1.0.9" + }, + { + "name": "httpx", + "version": "0.28.1" + }, + { + "name": "httpx-sse", + "version": "0.4.3" + }, + { + "name": "huggingface-hub", + "version": "1.26.0" + }, + { + "name": "idna", + "version": "3.18" + }, + { + "name": "jinja2", + "version": "3.1.6" + }, + { + "name": "jiter", + "version": "0.16.0" + }, + { + "name": "jsonschema", + "version": "4.26.0" + }, + { + "name": "jsonschema-specifications", + "version": "2025.9.1" + }, + { + "name": "latex2sympy2-extended", + "version": "1.11.0" + }, + { + "name": "loguru", + "version": "0.7.3" + }, + { + "name": "markdown-it-py", + "version": "4.2.0" + }, + { + "name": "markupsafe", + "version": "3.0.3" + }, + { + "name": "math-verify", + "version": "0.9.0" + }, + { + "name": "mcp", + "version": "1.29.0" + }, + { + "name": "mdurl", + "version": "0.1.2" + }, + { + "name": "mpmath", + "version": "1.3.0" + }, + { + "name": "msgpack", + "version": "1.2.1" + }, + { + "name": "multidict", + "version": "6.7.1" + }, + { + "name": "multiprocess", + "version": "0.70.19" + }, + { + "name": "numpy", + "version": "2.5.1" + }, + { + "name": "openai", + "version": "2.53.0" + }, + { + "name": "openai-agents", + "version": "0.19.3" + }, + { + "name": "openai-harmony", + "version": "0.0.8" + }, + { + "name": "opentelemetry-api", + "version": "1.44.0" + }, + { + "name": "packaging", + "version": "26.2" + }, + { + "name": "pandas", + "version": "3.0.5" + }, + { + "name": "prime-pydantic-config", + "version": "0.4.2" + }, + { + "name": "prime-sandboxes", + "version": "0.2.34" + }, + { + "name": "prime-tunnel", + "version": "0.1.10" + }, + { + "name": "propcache", + "version": "0.5.2" + }, + { + "name": "protobuf", + "version": "7.35.1" + }, + { + "name": "pyarrow", + "version": "25.0.0" + }, + { + "name": "pycparser", + "version": "3.0" + }, + { + "name": "pydantic", + "version": "2.13.4" + }, + { + "name": "pydantic-core", + "version": "2.46.4" + }, + { + "name": "pydantic-settings", + "version": "2.14.2" + }, + { + "name": "pygments", + "version": "2.20.0" + }, + { + "name": "pyjwt", + "version": "2.13.0" + }, + { + "name": "pyqwest", + "version": "0.8.0" + }, + { + "name": "python-dateutil", + "version": "2.9.0.post0" + }, + { + "name": "python-dotenv", + "version": "1.2.2" + }, + { + "name": "python-multipart", + "version": "0.0.32" + }, + { + "name": "pyyaml", + "version": "6.0.3" + }, + { + "name": "pyzmq", + "version": "27.1.0" + }, + { + "name": "referencing", + "version": "0.37.0" + }, + { + "name": "regex", + "version": "2026.7.19" + }, + { + "name": "renderers", + "version": "0.1.9.dev10" + }, + { + "name": "requests", + "version": "2.34.2" + }, + { + "name": "rich", + "version": "15.0.0" + }, + { + "name": "rpds-py", + "version": "2026.6.3" + }, + { + "name": "safetensors", + "version": "0.8.0" + }, + { + "name": "setproctitle", + "version": "1.3.7" + }, + { + "name": "shellingham", + "version": "1.5.4" + }, + { + "name": "six", + "version": "1.17.0" + }, + { + "name": "sniffio", + "version": "1.3.1" + }, + { + "name": "sse-starlette", + "version": "3.4.6" + }, + { + "name": "starlette", + "version": "1.3.1" + }, + { + "name": "sympy", + "version": "1.14.0" + }, + { + "name": "tenacity", + "version": "9.1.4" + }, + { + "name": "tiktoken", + "version": "0.13.0" + }, + { + "name": "tokenizers", + "version": "0.22.2" + }, + { + "name": "tomli", + "version": "2.4.1" + }, + { + "name": "tomli-w", + "version": "1.2.0" + }, + { + "name": "tqdm", + "version": "4.70.0" + }, + { + "name": "transformers", + "version": "5.14.1" + }, + { + "name": "typer", + "version": "0.27.1" + }, + { + "name": "typing-extensions", + "version": "4.16.0" + }, + { + "name": "typing-inspection", + "version": "0.4.2" + }, + { + "name": "urllib3", + "version": "2.7.0" + }, + { + "name": "uvicorn", + "version": "0.52.1" + }, + { + "name": "uvloop", + "version": "0.22.1" + }, + { + "name": "verifiers", + "version": "0.2.2.dev77" + }, + { + "name": "websockets", + "version": "16.1.1" + }, + { + "name": "xxhash", + "version": "3.8.1" + }, + { + "name": "yarl", + "version": "1.24.5" + } + ], + "applicable_locked_distributions_sha256": "46ff9d184de9cd214ede0519d4b7ddd84ad273c013ff5ffa8263213e5de86367", + "argv": [ + "uv", + "run", + "--project", + ".", + "--locked", + "python", + "generate_smoke.py", + "--output", + "generated" + ], + "assertion_fraction": 1.0, + "assertion_rubric": "verifiers.Rubric", + "before_state_sha256": "9e4f76c756726a6c01f052f18b08db9fa2e073cd5e074f7693d55159d5f99612", + "campaign_id": "public-synthetic-campaign", + "execution_id": "execution-public-1", + "installed_distributions": [ + { + "name": "aiofiles", + "version": "25.1.0" + }, + { + "name": "aiohappyeyeballs", + "version": "2.7.1" + }, + { + "name": "aiohttp", + "version": "3.14.3" + }, + { + "name": "aiolimiter", + "version": "1.2.1" + }, + { + "name": "aiosignal", + "version": "1.4.0" + }, + { + "name": "annotated-doc", + "version": "0.0.5" + }, + { + "name": "annotated-types", + "version": "0.8.0" + }, + { + "name": "anthropic", + "version": "0.120.2" + }, + { + "name": "antlr4-python3-runtime", + "version": "4.13.2" + }, + { + "name": "anyio", + "version": "4.14.2" + }, + { + "name": "attrs", + "version": "26.1.0" + }, + { + "name": "certifi", + "version": "2026.7.22" + }, + { + "name": "cffi", + "version": "2.1.1" + }, + { + "name": "charset-normalizer", + "version": "3.4.9" + }, + { + "name": "click", + "version": "8.4.2" + }, + { + "name": "connect-python", + "version": "0.9.0" + }, + { + "name": "cryptography", + "version": "50.0.0" + }, + { + "name": "datasets", + "version": "5.0.1" + }, + { + "name": "dill", + "version": "0.4.1" + }, + { + "name": "distro", + "version": "1.9.0" + }, + { + "name": "docstring-parser", + "version": "0.18.0" + }, + { + "name": "filelock", + "version": "3.32.2" + }, + { + "name": "frozenlist", + "version": "1.8.0" + }, + { + "name": "fsspec", + "version": "2026.6.0" + }, + { + "name": "gepa", + "version": "0.1.4" + }, + { + "name": "griffelib", + "version": "2.1.0" + }, + { + "name": "h11", + "version": "0.16.0" + }, + { + "name": "hf-xet", + "version": "1.6.0" + }, + { + "name": "httpcore", + "version": "1.0.9" + }, + { + "name": "httpx", + "version": "0.28.1" + }, + { + "name": "httpx-sse", + "version": "0.4.3" + }, + { + "name": "huggingface-hub", + "version": "1.26.0" + }, + { + "name": "idna", + "version": "3.18" + }, + { + "name": "jinja2", + "version": "3.1.6" + }, + { + "name": "jiter", + "version": "0.16.0" + }, + { + "name": "jsonschema", + "version": "4.26.0" + }, + { + "name": "jsonschema-specifications", + "version": "2025.9.1" + }, + { + "name": "latex2sympy2-extended", + "version": "1.11.0" + }, + { + "name": "loguru", + "version": "0.7.3" + }, + { + "name": "markdown-it-py", + "version": "4.2.0" + }, + { + "name": "markupsafe", + "version": "3.0.3" + }, + { + "name": "math-verify", + "version": "0.9.0" + }, + { + "name": "mcp", + "version": "1.29.0" + }, + { + "name": "mdurl", + "version": "0.1.2" + }, + { + "name": "mpmath", + "version": "1.3.0" + }, + { + "name": "msgpack", + "version": "1.2.1" + }, + { + "name": "multidict", + "version": "6.7.1" + }, + { + "name": "multiprocess", + "version": "0.70.19" + }, + { + "name": "numpy", + "version": "2.5.1" + }, + { + "name": "openai", + "version": "2.53.0" + }, + { + "name": "openai-agents", + "version": "0.19.3" + }, + { + "name": "openai-harmony", + "version": "0.0.8" + }, + { + "name": "opentelemetry-api", + "version": "1.44.0" + }, + { + "name": "packaging", + "version": "26.2" + }, + { + "name": "pandas", + "version": "3.0.5" + }, + { + "name": "prime-pydantic-config", + "version": "0.4.2" + }, + { + "name": "prime-sandboxes", + "version": "0.2.34" + }, + { + "name": "prime-tunnel", + "version": "0.1.10" + }, + { + "name": "propcache", + "version": "0.5.2" + }, + { + "name": "protobuf", + "version": "7.35.1" + }, + { + "name": "pyarrow", + "version": "25.0.0" + }, + { + "name": "pycparser", + "version": "3.0" + }, + { + "name": "pydantic", + "version": "2.13.4" + }, + { + "name": "pydantic-core", + "version": "2.46.4" + }, + { + "name": "pydantic-settings", + "version": "2.14.2" + }, + { + "name": "pygments", + "version": "2.20.0" + }, + { + "name": "pyjwt", + "version": "2.13.0" + }, + { + "name": "pyqwest", + "version": "0.8.0" + }, + { + "name": "python-dateutil", + "version": "2.9.0.post0" + }, + { + "name": "python-dotenv", + "version": "1.2.2" + }, + { + "name": "python-multipart", + "version": "0.0.32" + }, + { + "name": "pyyaml", + "version": "6.0.3" + }, + { + "name": "pyzmq", + "version": "27.1.0" + }, + { + "name": "referencing", + "version": "0.37.0" + }, + { + "name": "regex", + "version": "2026.7.19" + }, + { + "name": "renderers", + "version": "0.1.9.dev10" + }, + { + "name": "requests", + "version": "2.34.2" + }, + { + "name": "rich", + "version": "15.0.0" + }, + { + "name": "rpds-py", + "version": "2026.6.3" + }, + { + "name": "safetensors", + "version": "0.8.0" + }, + { + "name": "setproctitle", + "version": "1.3.7" + }, + { + "name": "shellingham", + "version": "1.5.4" + }, + { + "name": "six", + "version": "1.17.0" + }, + { + "name": "sniffio", + "version": "1.3.1" + }, + { + "name": "sse-starlette", + "version": "3.4.6" + }, + { + "name": "starlette", + "version": "1.3.1" + }, + { + "name": "sympy", + "version": "1.14.0" + }, + { + "name": "tenacity", + "version": "9.1.4" + }, + { + "name": "tiktoken", + "version": "0.13.0" + }, + { + "name": "tokenizers", + "version": "0.22.2" + }, + { + "name": "tomli", + "version": "2.4.1" + }, + { + "name": "tomli-w", + "version": "1.2.0" + }, + { + "name": "tqdm", + "version": "4.70.0" + }, + { + "name": "transformers", + "version": "5.14.1" + }, + { + "name": "typer", + "version": "0.27.1" + }, + { + "name": "typing-extensions", + "version": "4.16.0" + }, + { + "name": "typing-inspection", + "version": "0.4.2" + }, + { + "name": "urllib3", + "version": "2.7.0" + }, + { + "name": "uvicorn", + "version": "0.52.1" + }, + { + "name": "uvloop", + "version": "0.22.1" + }, + { + "name": "verifiers", + "version": "0.2.2.dev77" + }, + { + "name": "websockets", + "version": "16.1.1" + }, + { + "name": "xxhash", + "version": "3.8.1" + }, + { + "name": "yarl", + "version": "1.24.5" + } + ], + "installed_distributions_sha256": "46ff9d184de9cd214ede0519d4b7ddd84ad273c013ff5ffa8263213e5de86367", + "interpreter": { + "executable_sha256": "a395f264e5612a2819662ed3e37fd30d39ed61179b98e5f86c3c783a008d8623", + "implementation": "CPython", + "path": ".venv/bin/python3", + "path_kind": "project_relative", + "version": "3.12.13" + }, + "lock_exclusions": [ + { + "name": "understudy-campaign-admission-generic-smoke", + "reason": "root-non-installable-no-emit-project" + }, + { + "reason": "platform-marker-not-applicable" + } + ], + "mutated_candidate_sha256": "0ba2e4298634b3771db51d77ffca15af1c7e731fc15c290b60ab5c44097c1f6c", + "request_id": "request-public-1", + "root_package_name": "understudy-campaign-admission-generic-smoke", + "schema_version": "understudy.synthetic_verifiers_execution.v1", + "seed_candidate_sha256": "4dbee206fc073f8db3e50fad210ca48772e481ad31ee37f33e638bca91db1914", + "trace_sha256": "4d47c8afd537dd8377d8b349ca7b67900f7b2d3fd2e406606c07bc57204b5938", + "verified_state_delta": { + "after": "ready", + "before": "pending", + "independently_asserted": true, + "path": "/records/alpha/status" + }, + "verifiers": { + "git_revision": "61e7394d45109d142deec768c3c459ab98111e91", + "module": "verifiers", + "version": "0.2.2.dev77" + }, + "workload_id": "cedar-public-synthetic" +} diff --git a/tests/fixtures/campaign-admission/uv-project-generic/generated/overflow-receipt.json b/tests/fixtures/campaign-admission/uv-project-generic/generated/overflow-receipt.json new file mode 100644 index 00000000..bc9f55a2 --- /dev/null +++ b/tests/fixtures/campaign-admission/uv-project-generic/generated/overflow-receipt.json @@ -0,0 +1,16 @@ +{ + "campaign_id": "public-synthetic-campaign", + "effective_max_tokens": 256, + "executable_bundle_sha256": "c2c8a323b8015162a33344491ba882c67e5fe2e3b6089b0ff3769ae3a0862d00", + "execution_id": "execution-public-1", + "failed_before_sampling": true, + "failure": "OverlongPromptError", + "oversized_request_sha256": "a47b86e783052357b1268c9ce2b1d1943d197a330f7863a2c2c21664da05008a", + "request_id": "request-public-1", + "requested_max_tokens": 256, + "sample_calls": 0, + "schema_version": "understudy.synthetic_overflow_probe.v1", + "tool_calls": 0, + "trajectory_steps": 0, + "workload_id": "cedar-public-synthetic" +} diff --git a/tests/fixtures/campaign-admission/uv-project-generic/generated/trace.json b/tests/fixtures/campaign-admission/uv-project-generic/generated/trace.json new file mode 100644 index 00000000..f99c3c43 --- /dev/null +++ b/tests/fixtures/campaign-admission/uv-project-generic/generated/trace.json @@ -0,0 +1,80 @@ +{ + "calls": [ + { + "context_overflow_behavior": "fail", + "endpoint": "/chat/completions", + "finish_reason": "tool_calls", + "max_tokens": 256, + "messages_sha256": "6f71099eedf6d5b161ceea52fa0663b0c104b5729a77d3a5f4264967b5853808", + "model": "synthetic-local", + "node": 2, + "sampling_sha256": "b779b17d306d67fbd5b415e6b2e82d89e0dc2c4f2e35c57901f7114d3bbd0562", + "tools_sha256": "ad4cc5e9dc6e0a8481d7b6b890033bd33fc457c49a875d458d27e4299b761b64" + } + ], + "campaign_id": "public-synthetic-campaign", + "errors": [], + "execution": { + "tool_calls": 1, + "verifiers_trajectory_steps": 2 + }, + "execution_id": "execution-public-1", + "metrics": { + "assertion_fraction": 1.0 + }, + "nodes": [ + { + "message": { + "content": "Only inspect the synthetic record.\nSet record alpha to ready with set-record, then report success.", + "role": "system" + }, + "sampled": false + }, + { + "message": { + "content": "Set synthetic record alpha to ready.", + "role": "user" + }, + "parent": 0, + "sampled": false + }, + { + "message": { + "role": "assistant", + "tool_calls": [ + { + "arguments": "{\"id\":\"alpha\",\"status\":\"ready\"}", + "id": "call-public-1", + "name": "set-record" + } + ] + }, + "parent": 1, + "sampled": true + }, + { + "message": { + "content": "{\"after\":\"ready\",\"applied\":true,\"before\":\"pending\",\"ok\":true}", + "name": "world_toolset_set-record", + "role": "tool", + "tool_call_id": "call-public-1" + }, + "parent": 2, + "sampled": false + } + ], + "ok": true, + "request_id": "request-public-1", + "rewards": { + "assertion_fraction": 1.0 + }, + "runtime": "standard-verifiers", + "task": { + "data": { + "split": "train", + "task_id": "public-synthetic-mutation-1" + } + }, + "verifiers_version": "0.2.2.dev77", + "workload_id": "cedar-public-synthetic" +} diff --git a/tests/fixtures/campaign-admission/uv-project-generic/pyproject.toml b/tests/fixtures/campaign-admission/uv-project-generic/pyproject.toml new file mode 100644 index 00000000..d75dc083 --- /dev/null +++ b/tests/fixtures/campaign-admission/uv-project-generic/pyproject.toml @@ -0,0 +1,10 @@ +[project] +name = "understudy-campaign-admission-generic-smoke" +version = "0.0.0" +requires-python = "==3.12.*" +dependencies = [ + "verifiers @ git+https://github.com/PrimeIntellect-ai/verifiers.git@61e7394d45109d142deec768c3c459ab98111e91", +] + +[tool.uv] +override-dependencies = ["mcp==1.29.0"] diff --git a/tests/fixtures/campaign-admission/uv-project-generic/uv.lock b/tests/fixtures/campaign-admission/uv-project-generic/uv.lock new file mode 100644 index 00000000..7b632277 --- /dev/null +++ b/tests/fixtures/campaign-admission/uv-project-generic/uv.lock @@ -0,0 +1,1693 @@ +version = 1 +revision = 3 +requires-python = "==3.12.*" +resolution-markers = [ + "sys_platform == 'win32'", + "sys_platform == 'emscripten'", + "sys_platform != 'emscripten' and sys_platform != 'win32'", +] + +[manifest] +overrides = [{ name = "mcp", specifier = "==1.29.0" }] + +[[package]] +name = "aiofiles" +version = "25.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/41/c3/534eac40372d8ee36ef40df62ec129bee4fdb5ad9706e58a29be53b2c970/aiofiles-25.1.0.tar.gz", hash = "sha256:a8d728f0a29de45dc521f18f07297428d56992a742f0cd2701ba86e44d23d5b2", size = 46354, upload-time = "2025-10-09T20:51:04.358Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl", hash = "sha256:abe311e527c862958650f9438e859c1fa7568a141b22abcd015e120e86a85695", size = 14668, upload-time = "2025-10-09T20:51:03.174Z" }, +] + +[[package]] +name = "aiohappyeyeballs" +version = "2.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ce/f4/eec0465c2f67b2664688d0240b3212d5196fd89e741df67ddb81f8d35658/aiohappyeyeballs-2.7.1.tar.gz", hash = "sha256:065665c041c42a5938ed220bdcd7230f22527fbec085e1853d2402c8a3615d9d", size = 24757, upload-time = "2026-07-01T17:11:55.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl", hash = "sha256:9243213661e29250eb41368e5daa826fc017156c3b8a11440826b2e3ed376472", size = 15038, upload-time = "2026-07-01T17:11:54.055Z" }, +] + +[[package]] +name = "aiohttp" +version = "3.14.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "propcache" }, + { name = "typing-extensions" }, + { name = "yarl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/d9/22ce5786ac0c1653ae8b6c23bded02c1686d11f0dbb45b31ce128e0df985/aiohttp-3.14.3.tar.gz", hash = "sha256:9491196535a88924a60afd5b5f434b5b203b6cc616250878dbdb223a8f7844bc", size = 7971213, upload-time = "2026-07-23T01:57:27.037Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/d4/eb96299230e20acf2efae207cb8d69051f1f68e357e5ea5e479bf6fb097a/aiohttp-3.14.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:39aded8c7f3b935b54aab1d8d73c70ec0ee2d3ec3b943e0e86611bc150ba47f5", size = 754690, upload-time = "2026-07-23T01:53:47.332Z" }, + { url = "https://files.pythonhosted.org/packages/88/11/e7a70a209eb9a067c0d3212b518a0134e3484f5178c7533878b6b514d469/aiohttp-3.14.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5bcb6ff3fdab1258a192679ff1a05d44f59626430aa05cd1a9d2447423599228", size = 509484, upload-time = "2026-07-23T01:53:51.159Z" }, + { url = "https://files.pythonhosted.org/packages/30/07/4bbc222cc8dbe31d4c3e8a5baad2286e4d42026ac0c570027b89afce6344/aiohttp-3.14.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:617105e2c3018ee38d0c8ce5ee3c84f621a6d8b9f723202aacaff28449ca91ee", size = 511949, upload-time = "2026-07-23T01:53:55.083Z" }, + { url = "https://files.pythonhosted.org/packages/54/b9/42e74c46b7b7c794b995bbc1f573fb48950c38b19d8600c62a6804ee2d67/aiohttp-3.14.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f631fe87a6f30df5fbe6d79640b25e4cffb38c31c7fb6f10871517b84b0f8c1a", size = 1765282, upload-time = "2026-07-23T01:53:59.662Z" }, + { url = "https://files.pythonhosted.org/packages/6b/ed/62bc4d74363ad346d518e0720363a949f63e2e23439a79eb5813d4d29bb3/aiohttp-3.14.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a94dbaae5ae27bd849c93570669bff91e0510f33a80805738e3de72a7be0447b", size = 1741511, upload-time = "2026-07-23T01:54:04.063Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9f/181e8a8bc79e47d13c7fc4540bd7a3b729d9505609c61f392a8dd2fbfe55/aiohttp-3.14.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8f2f1c4c032c7cedd7d8da6f54c97b70266c6570c3108d3fdffee7188bb70529", size = 1810680, upload-time = "2026-07-23T01:54:09.882Z" }, + { url = "https://files.pythonhosted.org/packages/5c/9a/dec94d6ad694552fe3424e3f1928d7a606a5d9d9433a04e7ecdd9d38ae7f/aiohttp-3.14.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ea05e1f97ceea523942d9b2a7d7c0359d781d683d6b043f5943a602b14da4787", size = 1905646, upload-time = "2026-07-23T01:54:13.475Z" }, + { url = "https://files.pythonhosted.org/packages/52/b7/7cd31f29d6055bd711ae6e669367fba6f5ae9de463910a793e30556a8db7/aiohttp-3.14.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:543906c127fb1d929b95076db19b83fa2d46751006ff1e23b093aa5ac4d8db42", size = 1792122, upload-time = "2026-07-23T01:54:15.752Z" }, + { url = "https://files.pythonhosted.org/packages/66/73/10b1ef93afa61f4963c746257b70ced619cf31a4798671de5fdb2608501d/aiohttp-3.14.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0a5ff2dfbb9ce645fa5b8ef3e02c6c0b9cc3f6030ff863d0c51fffc50cb5541b", size = 1591127, upload-time = "2026-07-23T01:54:19.489Z" }, + { url = "https://files.pythonhosted.org/packages/49/ed/3b203fa6de1b338c14acdc06bf6ca9b043b7944f005966958c2ced932cde/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:041badb8f84396357c4d3ad26de6afd7a32b112f43d3c63045c0c8278cfd2043", size = 1725210, upload-time = "2026-07-23T01:54:24.129Z" }, + { url = "https://files.pythonhosted.org/packages/28/b7/1c2aab8c706436dcc28598452488ac9cd7c409da815237c28c27d58993e6/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:530125ee1163c4219af35dc3aa1206e541e7b31b6efc1a3f93b70a136f65d427", size = 1764848, upload-time = "2026-07-23T01:54:27.973Z" }, + { url = "https://files.pythonhosted.org/packages/54/50/94c28f08b131c4bf10984ea2c7a536c9920608bb2d6e7f95642c30cc87b7/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c8653fd547c93a61aadc612007790f5555cdd18946fa48cf45e26d8ea4ea473d", size = 1777102, upload-time = "2026-07-23T01:54:31.775Z" }, + { url = "https://files.pythonhosted.org/packages/13/d4/e7d09ba7d345fb2d74440fd2fa033c5e079fac05552927705986f41a364f/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:89176250f686cb9853c0fb7ead90e639e915b84a6f43eedc2a4e7ec21f1037f0", size = 1580205, upload-time = "2026-07-23T01:54:34.518Z" }, + { url = "https://files.pythonhosted.org/packages/a3/84/072a91d68e1e1eb587985b54baab94221277f877e8ef274fc213a0ceae28/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3a26434dafe408229ff3403458ca58de24fb51936504decac49ce6755f77e59d", size = 1797219, upload-time = "2026-07-23T01:54:36.995Z" }, + { url = "https://files.pythonhosted.org/packages/e0/eb/aad34e897e668424d6e995da5dff8a4a09af93363d3392488772957a63aa/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d1558173930a5a8d3069cee5c92fc91c87c4dbcb099debbb3622053717145a19", size = 1768629, upload-time = "2026-07-23T01:54:40.103Z" }, + { url = "https://files.pythonhosted.org/packages/b6/2b/6bb88ddba0fecd9122aa3ebcad25996cf6c083a4a7040dbb3a4f97972af6/aiohttp-3.14.3-cp312-cp312-win32.whl", hash = "sha256:16100ad3ab8d649fdfbee87602d9d2dcdca9df0b9eda8a1b5fdc0d41f96da559", size = 451481, upload-time = "2026-07-23T01:54:42.547Z" }, + { url = "https://files.pythonhosted.org/packages/76/9b/f2f8f108da17ecef2cc3efc424e8b7ad3782b1a8360f7b8eae8ced84f6ea/aiohttp-3.14.3-cp312-cp312-win_amd64.whl", hash = "sha256:33a2d7c28d33797a2e99923dffa63f83d908a19b6bf26cfe80fa790aa5e1a75a", size = 476845, upload-time = "2026-07-23T01:54:44.853Z" }, + { url = "https://files.pythonhosted.org/packages/3e/44/28dac80a8941b604f4da10ce21097614ca1bf905ce93dca28d8d7de9c1e7/aiohttp-3.14.3-cp312-cp312-win_arm64.whl", hash = "sha256:362a3fd481769cac1a824514bcd86fda51c65e8fe6e051099e008fddde6db17c", size = 448050, upload-time = "2026-07-23T01:54:47.087Z" }, +] + +[[package]] +name = "aiolimiter" +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/23/b52debf471f7a1e42e362d959a3982bdcb4fe13a5d46e63d28868807a79c/aiolimiter-1.2.1.tar.gz", hash = "sha256:e02a37ea1a855d9e832252a105420ad4d15011505512a1a1d814647451b5cca9", size = 7185, upload-time = "2024-12-08T15:31:51.496Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/ba/df6e8e1045aebc4778d19b8a3a9bc1808adb1619ba94ca354d9ba17d86c3/aiolimiter-1.2.1-py3-none-any.whl", hash = "sha256:d3f249e9059a20badcb56b61601a83556133655c11d1eb3dd3e04ff069e5f3c7", size = 6711, upload-time = "2024-12-08T15:31:49.874Z" }, +] + +[[package]] +name = "aiosignal" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "frozenlist" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, +] + +[[package]] +name = "annotated-doc" +version = "0.0.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/8e/38aa427ed5402449e226975b649c5dc73ccadfefeb95e6aecb8f8ea4b6b6/annotated_doc-0.0.5.tar.gz", hash = "sha256:c7e58ce09192557605d8bbd92836d7e1d520ac9580096042c0bfd197efacf1bb", size = 10758, upload-time = "2026-07-28T13:50:58.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl", hash = "sha256:117bac03a25ede5df5440e855b32d556049ca169ead221505badf432fed4b101", size = 5302, upload-time = "2026-07-28T13:50:57.239Z" }, +] + +[[package]] +name = "annotated-types" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5f/56/a8120250d128bed162cd73c76d45f6ef9991f3e068f62a8ee060afa3104a/annotated_types-0.8.0.tar.gz", hash = "sha256:13b2beaad985e05e2d6407ee4c4f35590b11f8d693a258a561055cac8f64cab7", size = 15893, upload-time = "2026-07-23T20:16:13.995Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl", hash = "sha256:f072f4d804ea359e4eaf198b1af7a8b0943881a87f31bb764f8bf219bb9419e0", size = 13427, upload-time = "2026-07-23T20:16:12.938Z" }, +] + +[[package]] +name = "anthropic" +version = "0.120.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "docstring-parser" }, + { name = "httpx" }, + { name = "jiter" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d7/10/4ca013cb166f226bd89e0aeb0fcaff94f45ddf716d4925ce89475d3c587b/anthropic-0.120.2.tar.gz", hash = "sha256:9722efc10c27a30a69f5338ddacdb35bc6a64297a4e4ba729bf83af873d5fb3a", size = 1008421, upload-time = "2026-07-28T17:38:26.986Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/af/0f5db57b9397a0f3b7fc204cbef143401a7cadaf982330f97f1ce3d39f34/anthropic-0.120.2-py3-none-any.whl", hash = "sha256:0f0bc2b381dc0eb41c8d886b815d79c2041cd2374f83aed36f574b6dc9c579c1", size = 1022851, upload-time = "2026-07-28T17:38:25.466Z" }, +] + +[[package]] +name = "antlr4-python3-runtime" +version = "4.13.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/33/5f/2cdf6f7aca3b20d3f316e9f505292e1f256a32089bd702034c29ebde6242/antlr4_python3_runtime-4.13.2.tar.gz", hash = "sha256:909b647e1d2fc2b70180ac586df3933e38919c85f98ccc656a96cd3f25ef3916", size = 117467, upload-time = "2024-08-03T19:00:12.757Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/03/a851e84fcbb85214dc637b6378121ef9a0dd61b4c65264675d8a5c9b1ae7/antlr4_python3_runtime-4.13.2-py3-none-any.whl", hash = "sha256:fe3835eb8d33daece0e799090eda89719dbccee7aa39ef94eed3818cafa5a7e8", size = 144462, upload-time = "2024-08-03T19:00:11.134Z" }, +] + +[[package]] +name = "anyio" +version = "4.14.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/cc/a381afa6efea9f496eff839d4a6a1aed3bfafc7b3ab4b0d1b243a12573dd/anyio-4.14.2.tar.gz", hash = "sha256:cfa139f3ed1a23ee8f88a145ddb5ac7605b8bbfd8592baacd7ce3d8bb4313c7f", size = 260176, upload-time = "2026-07-12T20:29:07.082Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size = 125813, upload-time = "2026-07-12T20:29:05.763Z" }, +] + +[[package]] +name = "attrs" +version = "26.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" }, +] + +[[package]] +name = "certifi" +version = "2026.7.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/c2/24167ea9858356b47a87a50d39908bfdb72ceeefe0041586e704e5376b3a/certifi-2026.7.22.tar.gz", hash = "sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55", size = 138112, upload-time = "2026-07-22T03:35:12.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl", hash = "sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775", size = 136983, upload-time = "2026-07-22T03:35:11.276Z" }, +] + +[[package]] +name = "cffi" +version = "2.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9e/ef/008a1939e372c06329a3fce4279c02f328488f3526744906eeec3da7ad5f/cffi-2.1.1.tar.gz", hash = "sha256:dd31f52ea1086513bb9df30f8fcee9b8918323ae067a3d5b78bc826a000712be", size = 530807, upload-time = "2026-08-03T21:21:18.939Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/69/43965eccfdead3b9220015fd1320e117be8c6ed01a62ffab76eeb752f5d5/cffi-2.1.1-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:c8c69575568085ba0b1b10c0249d779a214aea6f6522e949a0fc9fb0fcb449d0", size = 184821, upload-time = "2026-08-03T21:19:44.887Z" }, + { url = "https://files.pythonhosted.org/packages/54/7d/16e5a096677b5e313ca80cd5e5170efa3ea44624a82bb111925522da64b1/cffi-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f81b3b8f3d4e343550fa4baa0e479bba9f2d29ce9c2e9b51d1ce1718d7442fcf", size = 184719, upload-time = "2026-08-03T21:19:46.129Z" }, + { url = "https://files.pythonhosted.org/packages/56/e6/8941622732edec876dd17d0453dce07317ae96db34f2ec1436c9d3785986/cffi-2.1.1-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:811bd1e21d32de12efca32393a0ab3f5133b54fce9bd44b8bd77ab07da14bf6a", size = 214799, upload-time = "2026-08-03T21:19:47.218Z" }, + { url = "https://files.pythonhosted.org/packages/44/de/f98430906df1545ffde0d543dd124a7a439bc2cd32b36b9c53f805df7333/cffi-2.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:68e62fe11f30d5ca8289242866f0a5291402d8529ca2178ab8afc5c9694ae890", size = 222389, upload-time = "2026-08-03T21:19:48.331Z" }, + { url = "https://files.pythonhosted.org/packages/6a/5b/717f1526b9957b34456313c31645c5b82b8fb5c3fe9e4752999be7128bfc/cffi-2.1.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:4a7c934f7360e8cd64fe9efadcbd10c7c6364f531e432b9a4bf5ccbc9e0e8b50", size = 210249, upload-time = "2026-08-03T21:19:49.543Z" }, + { url = "https://files.pythonhosted.org/packages/64/b3/f8aa4f3e34986c7e4ec45072d1b1b9dd295b6b18007b45518d79726dd725/cffi-2.1.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:3143d81e29e1e20a9ce10901ec369012947876596f75a222235965f2b7ae832e", size = 208775, upload-time = "2026-08-03T21:19:50.918Z" }, + { url = "https://files.pythonhosted.org/packages/b1/db/dceb9dd5b231e1da801793f8acc9f3c52a7e1afe40bb1aae37e02b0faad5/cffi-2.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c1453022f490d2459a11819d83ad1d586e9ff65a12ac3e705ffebd46d3685dcf", size = 221822, upload-time = "2026-08-03T21:19:52.054Z" }, + { url = "https://files.pythonhosted.org/packages/a0/d2/6cd24ae3be000a634109c247d1475d62e5616d0dc78c82770942ec384248/cffi-2.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:208f941bb9d18e768138677f0a6d2ce01f590df56043dda1df1535ac57c88517", size = 225232, upload-time = "2026-08-03T21:19:53.109Z" }, + { url = "https://files.pythonhosted.org/packages/cb/52/3fa190537004dd7f0ab860a6dc7c0175b8667f68d1e618a46f5498d30250/cffi-2.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:210019b6c7cf07f081b4c54635c8cf744377001350e29cc0f81c4377b4797735", size = 223597, upload-time = "2026-08-03T21:19:54.515Z" }, + { url = "https://files.pythonhosted.org/packages/80/fb/0bb75b7039588c074b37ae99f40d9bfddf990ecb2fbc346ebccd2e56b9be/cffi-2.1.1-cp312-cp312-win32.whl", hash = "sha256:046bfc24911b37851ee1b51aab8bffe713d89c68c6a057b09484ce9fd5f69b4e", size = 175292, upload-time = "2026-08-03T21:19:55.566Z" }, + { url = "https://files.pythonhosted.org/packages/d9/79/615cc094e2fb508cade7de88d3b4f6c4ec2bab695c97bce9153dc65aadf5/cffi-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:f53e442b08449d42821fa4a4fba000095af9f62742a500f978a9f557ec44339a", size = 185919, upload-time = "2026-08-03T21:19:56.89Z" }, + { url = "https://files.pythonhosted.org/packages/70/c6/d0ea84713fe46b243a436a18fcd47d639732747e21635c8a27191b06dc30/cffi-2.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:7bde5e4cc5c10140859842b9d383af292b22639a4dffb725314baf45968cef80", size = 180093, upload-time = "2026-08-03T21:19:58.155Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/2a/23f34ec9d04624958e137efdc394888716353190e75f25dd22c7a2c7a8aa/charset_normalizer-3.4.9.tar.gz", hash = "sha256:673611bbd43f0810bec0b0f028ddeaaa501190339cac411f347ac76917c3ae7b", size = 152439, upload-time = "2026-07-07T14:34:58.454Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/4a/ecbd131485c07fcdfad54e28946d513e3da22ef3b4bd854dcafae54ec739/charset_normalizer-3.4.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:45b0cc4e3556cd875e09102988d1ab8356c998b596c9fced84547c8138b487a0", size = 319300, upload-time = "2026-07-07T14:33:15.666Z" }, + { url = "https://files.pythonhosted.org/packages/ec/96/5d9364e3342d69f3a045e1777bc47c85c383e6e9466d561b33fdb419d1f9/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b2aff1c7b3884512b9512c3eaadd9bab39fb45042ffaaa1dd08ff2b9f8109d9", size = 215802, upload-time = "2026-07-07T14:33:17.031Z" }, + { url = "https://files.pythonhosted.org/packages/4b/4c/5361f9aa7f2cb58d94f2ab831b3d493f69efb1d239654b4744e3c09527cb/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9104ed0bd76a429d46f9ec0dbc9b08ad1d2dcdf2b00a5a0daa1c145329b35b44", size = 237171, upload-time = "2026-07-07T14:33:18.576Z" }, + { url = "https://files.pythonhosted.org/packages/50/78/ce342ca4ff30b2eb49fe6d9578df85974f90c67d294113e94efdd9664cbd/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7b86a2b16095d250c6f58b3d9b2eee6f4147754344f3dab0922f7c9bf7d226c9", size = 233075, upload-time = "2026-07-07T14:33:20.084Z" }, + { url = "https://files.pythonhosted.org/packages/01/c4/4fa4c8b3097a11f3c5f09a35b72ed6855fb1d332469504962ab7bafcc702/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e226f6218febc71f6c1fc2fafb91c226f75bdc1d8fb12d66823716e891608fd", size = 224256, upload-time = "2026-07-07T14:33:21.747Z" }, + { url = "https://files.pythonhosted.org/packages/87/3a/ad914516df7e358a81aae018caa5e0470ba827fa6d763b1d2e87d920a5f6/charset_normalizer-3.4.9-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:90c44bc373b7687f6948b693cceaea1348ae0975d7474746559494468e3c1d84", size = 208784, upload-time = "2026-07-07T14:33:23.313Z" }, + { url = "https://files.pythonhosted.org/packages/d7/74/3c12f9755717dfe5c5c87da63f35d765fa0c00382ec26bf23f7fae34f2ba/charset_normalizer-3.4.9-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cdef90ae47919cae358d8ab15797a800ed41da7aba5d72419fb510729e2ed4b", size = 219928, upload-time = "2026-07-07T14:33:24.814Z" }, + { url = "https://files.pythonhosted.org/packages/33/9a/895095b83e7907abd6d3d99aad3a38ad0d9686cc186cb0c94c24320fe63e/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:60f44ade2cf573dad7a277e6f8ca9a51a21dda572b13bd7d8539bb3cd5dbedde", size = 218489, upload-time = "2026-07-07T14:33:26.42Z" }, + { url = "https://files.pythonhosted.org/packages/a1/34/ef5c05f412f42520d7709b7d3784d19640839eb7366ded1755511585429f/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a1786910334ed46ab1dd73222f2cd1e05c2c3bb39f6dddb4f8b36fc382058a39", size = 210267, upload-time = "2026-07-07T14:33:27.952Z" }, + { url = "https://files.pythonhosted.org/packages/83/dc/9b29fa4412b318bf3bfea985c35d67eb55e04b59a7c3f2237168b0e0be6f/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:03d07803992c6c7bbc976327f34b18b6160327fc81cb82c9d504720ac0be3b62", size = 226030, upload-time = "2026-07-07T14:33:29.397Z" }, + { url = "https://files.pythonhosted.org/packages/0e/42/6dbc00b8cd16011691203e33570fa42ed5746599a2e878112d16eab403a3/charset_normalizer-3.4.9-cp312-cp312-win32.whl", hash = "sha256:78841cccf1af7b40f6f716338d50c0902dbe88d9f800b3c973b7a9a0a693a642", size = 151185, upload-time = "2026-07-07T14:33:30.781Z" }, + { url = "https://files.pythonhosted.org/packages/80/cc/f920afd1a23c58ccd53c1d36085a71893a4737ff5e66e0371efab6809850/charset_normalizer-3.4.9-cp312-cp312-win_amd64.whl", hash = "sha256:4b3dac63058cc36820b0dd072f89898604e2d39686fe05321729d00d8ac185a0", size = 162557, upload-time = "2026-07-07T14:33:32.176Z" }, + { url = "https://files.pythonhosted.org/packages/f0/e6/0386d43a261ff4e4b30c5857af7df877254b46bec7b9d1b74b6bf969a90b/charset_normalizer-3.4.9-cp312-cp312-win_arm64.whl", hash = "sha256:78fa18e436a1a0e58dbd7e02fc4473f3f32cceb12df9dfca542d075961c307d2", size = 152665, upload-time = "2026-07-07T14:33:33.711Z" }, + { url = "https://files.pythonhosted.org/packages/98/2b/f97f1c193fb855c345d678f5077d6926034db0722df74c8f057020e05a25/charset_normalizer-3.4.9-py3-none-any.whl", hash = "sha256:68e5f26a1ad57ded6d1cfb85331d1c1a195314756471d97758c48498bb4dcdf5", size = 64538, upload-time = "2026-07-07T14:34:56.993Z" }, +] + +[[package]] +name = "click" +version = "8.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/76/d4/81420972a676e8ffea40450d8c8c92943e7218a78fe9b64359836cc9876b/click-8.4.2.tar.gz", hash = "sha256:9a6cea6e60b17ebe0a44c5cc636d94f09bd66142c1cd7d8b4cd731c4917a15f6", size = 338000, upload-time = "2026-06-24T17:45:15.148Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl", hash = "sha256:e6f9f66136c816745b9d65817da91d61d957fb16e02e4dcd0552553c5a197b76", size = 119243, upload-time = "2026-06-24T17:45:13.73Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "connect-python" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, + { name = "pyqwest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/fc/0e4798c53e2754f5de36ecf4d198706cb23711d603df6c008f6e7b5b21ae/connect_python-0.9.0.tar.gz", hash = "sha256:a188ec843b0f5953b7e1b88061af50ad91c9aaa2e982d7a89a63ae5c1fff932e", size = 46094, upload-time = "2026-03-19T02:40:42.279Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/15/5b42df2d9d34e5103f2b69e4f6a4aeb47c52589eaac8d53eb5b0a40eabaa/connect_python-0.9.0-py3-none-any.whl", hash = "sha256:896171fa7236d4e1557e3f7eee76daa8c9dd762f2c21662515f2060f1b542574", size = 63381, upload-time = "2026-03-19T02:40:40.743Z" }, +] + +[[package]] +name = "cryptography" +version = "50.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/41/6cbdcf9142d00fe82836fbb51e503e58088575cf7a0fe1dbff6695bf0840/cryptography-50.0.0.tar.gz", hash = "sha256:eeac2acb5a20ed25e0ad6d1df9891a520b78b404266b6d11778f25d5d691a6c9", size = 880201, upload-time = "2026-07-31T14:25:10.11Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl", hash = "sha256:031e2d5dd4bb9caa3ca9c82e5a197fd8ae680232cee62603d1a813f3f07e3d03", size = 4001252, upload-time = "2026-07-31T14:23:33.331Z" }, + { url = "https://files.pythonhosted.org/packages/57/ef/8f2df13c7216bcad3e1c74e07f6e193d93e998e114f524a53877c9af27ad/cryptography-50.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fd9192b7b70c573d7f214eb1ae35e00d359f6f5e4b27c7e21e30de1fc6204645", size = 4719554, upload-time = "2026-07-31T14:23:35.611Z" }, + { url = "https://files.pythonhosted.org/packages/d9/41/029086c34d91052fc3b88bcc8056f709a7c915c7a23b235a54eb800b1c97/cryptography-50.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:06a32a980526a6ab9a4b9bf8f7385800791e2bb960903cb6b530e4817509a3b7", size = 4702130, upload-time = "2026-07-31T14:23:37.635Z" }, + { url = "https://files.pythonhosted.org/packages/7d/ff/b6ce0954962e7f7b969f850a883744197bb3910bdfd7b6da162eab7d9f68/cryptography-50.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:a1b30560f2acc95aa8b2e06e716a13dbfc97314747b80d9707e307f77b40d6b3", size = 4725244, upload-time = "2026-07-31T14:23:39.471Z" }, + { url = "https://files.pythonhosted.org/packages/06/1e/63a1027cb7fec360a182208e1b7767d5aa1fe57be3d6aa856e69a321edc0/cryptography-50.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:8d89f3976b10b4ce31118de72329025f70d2c6ead14a8217c5514dd2c6d5a78f", size = 5342265, upload-time = "2026-07-31T14:23:41.286Z" }, + { url = "https://files.pythonhosted.org/packages/6b/72/a1116d683a6d7ece94590013882515de087edf9ef0e6292aae615a44df73/cryptography-50.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:b42a28c1844fd9de8f3f7d540e36b66f3a9c83fceac7170ebc7a6a19edd9dcae", size = 4734609, upload-time = "2026-07-31T14:23:43.139Z" }, + { url = "https://files.pythonhosted.org/packages/15/37/36a9c479bbe49acea2636c7fd3360d20f7b7e079c300352011c44850b181/cryptography-50.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:900131fafd8aead39ac7dd3a7e833be754c17a95cfd91221636949fe4eb0aa8a", size = 4356517, upload-time = "2026-07-31T14:23:44.939Z" }, + { url = "https://files.pythonhosted.org/packages/32/98/8a151d64367204cbc63ec65d37502f1d9c53cf4bfc6ec3c532614dbec60d/cryptography-50.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:07949c449a1abcf60d1ee6e88956d89404c7df3c8258f46589e912988e551987", size = 4724529, upload-time = "2026-07-31T14:23:46.93Z" }, + { url = "https://files.pythonhosted.org/packages/22/f6/ec13b470172126464a86bf54d2294a46d29837fc51ba3e45d4047946fb5e/cryptography-50.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:f89831ef99dd7dd169ab06d63a831adb9e20a87aac6d380266bbda5823349169", size = 5299852, upload-time = "2026-07-31T14:23:48.851Z" }, + { url = "https://files.pythonhosted.org/packages/da/3a/f05e32c99d440c9bb891ea0e36c9091891e36be5a9a87ab2ee6ea20729f6/cryptography-50.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:82148ec5bddac30b51a5b3c1945075f896fa022cb93f8e4a01e9f6ee95292c5f", size = 4734462, upload-time = "2026-07-31T14:23:50.861Z" }, + { url = "https://files.pythonhosted.org/packages/ca/dc/bd72b26be8953f80625f63151efd38eee71c76ca6cf591c08ff34615a79e/cryptography-50.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1489e263a8048bb8b6a8bac662eb2d402ea5d2b7b4699b72f385f1e2772db105", size = 4852708, upload-time = "2026-07-31T14:23:52.715Z" }, + { url = "https://files.pythonhosted.org/packages/27/20/c930314a2ab476d15dec966ec87e2e9637bb02b06106b12c0396c57bb603/cryptography-50.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7cec5b856506da6defb290f30c9ee687d5f5e8cb0bd3f6459dde43b0b4fa40ef", size = 5004179, upload-time = "2026-07-31T14:23:54.887Z" }, + { url = "https://files.pythonhosted.org/packages/32/2e/c9db68a0c4bfa28e310707527c0ee3a2bd254104d2e02e68f368e197aa4c/cryptography-50.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:bd1c592e4d5974f0d08d4888e432157adba757c66da0246918e43677fafa2d30", size = 3840395, upload-time = "2026-07-31T14:23:56.677Z" }, + { url = "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:ccdc4a71a4dabae05de219404f9f4abc38e3b58422177ff93d0da05967dafa07", size = 4036009, upload-time = "2026-07-31T14:24:24.122Z" }, + { url = "https://files.pythonhosted.org/packages/ff/c6/7a6202a534e32103a285b7834a120869557fe198d51d7cfe59754c8bda9c/cryptography-50.0.0-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:910e1d2668e7de9648f2bcee30e180db2a6b15c30f887d7c4c93ddf96e3992e3", size = 4745252, upload-time = "2026-07-31T14:24:26.118Z" }, + { url = "https://files.pythonhosted.org/packages/85/4f/0fa8c2f4428198f15d9ff8d63400e27afbf94ce833f6108da1eb3753f945/cryptography-50.0.0-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a91296cb61e8df6f86d0c19cc4068228da256bf59bf86049fbd821084565327f", size = 4728939, upload-time = "2026-07-31T14:24:27.994Z" }, + { url = "https://files.pythonhosted.org/packages/d1/63/54dd723490ba2dc09b299682c10b38db38f159728bcaae8c591b8af2f22d/cryptography-50.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e722f16708d854fe924790e051061f6704a472c3bac347b6fd88033ea8dd0dc5", size = 4748483, upload-time = "2026-07-31T14:24:30.254Z" }, + { url = "https://files.pythonhosted.org/packages/1d/dd/7c77d26285cc7f6991efce64a0f5b4f9383bfa5dd8c5033003eaf7db4cdb/cryptography-50.0.0-cp39-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:d764dcf130c428ef66786f866dd750f53182bc608813489915e9fc106bb0c82f", size = 5367599, upload-time = "2026-07-31T14:24:32.457Z" }, + { url = "https://files.pythonhosted.org/packages/46/c9/f60aed34c013f317f92817b6c171c2d22a78270fa41109bd4b08af26b194/cryptography-50.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:105110f43a471dbd0060b9c9516cb8a6a79233631a04cc2ba16f28323ac6e025", size = 4762647, upload-time = "2026-07-31T14:24:34.599Z" }, + { url = "https://files.pythonhosted.org/packages/be/f3/f9a0173b139372c3a48ed98154b45cc6b9de17c789d5ab552e621c293609/cryptography-50.0.0-cp39-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:828743d939e9629bc267b8e2d08d8bb67cd4319c771a33d4b18b22dd8fb7440a", size = 4385197, upload-time = "2026-07-31T14:24:36.647Z" }, + { url = "https://files.pythonhosted.org/packages/d8/36/83bb81f6e569bc38e1e4a7bc80f29b46bb9601920bc455fc8e888f5d5742/cryptography-50.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:2a8183b489dc1f7f80f135780fadc1108f14b31b8a40411c7a5b17425f65f28b", size = 4748095, upload-time = "2026-07-31T14:24:39.493Z" }, + { url = "https://files.pythonhosted.org/packages/6b/16/d3008eff98c764979865834c3d386d4fd041b5f52e7f34fc29ac1a5eb515/cryptography-50.0.0-cp39-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:6e7d61120573a7f2cd94cc095f9e81f6967c61ccdf194285aa143ecec8e0b708", size = 5325948, upload-time = "2026-07-31T14:24:41.556Z" }, + { url = "https://files.pythonhosted.org/packages/9c/f8/d97f9603efda3888187bfdb893f26c41be4735c10631d05d284ee6b047c4/cryptography-50.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:37fdb0d0111f1e2ff07139dfb79f1b49531f8e213c46f1163dd7642979b58c47", size = 4762400, upload-time = "2026-07-31T14:24:43.636Z" }, + { url = "https://files.pythonhosted.org/packages/64/a2/4615c8f7d81a00b1d6e6afe19f694e1543582349fb5f4076f6cb5dc36485/cryptography-50.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87f62a3d3b9888ed0fdde100ec06aa61ca9cd44bad9057d1dff9a516b5f5bb9", size = 4878208, upload-time = "2026-07-31T14:24:45.522Z" }, + { url = "https://files.pythonhosted.org/packages/d2/1a/efcfb02f91407149a0dacffffab791f7e19bf6385f63b3666dc8b5e5c9c8/cryptography-50.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:65c2c3add92b45fd0709db8594536aea39c2a67af0e27ffcf049c498501140b7", size = 5037050, upload-time = "2026-07-31T14:24:47.697Z" }, + { url = "https://files.pythonhosted.org/packages/57/30/4a22984d4f1bdfb8c054f07a92bc176b97a3134cc1d6c4b3bffb1f3688b4/cryptography-50.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:d24fead1d4d076e1bfb006dcec392074a3cd8d7b4fc8a595aa64073b2b7a96ba", size = 3874135, upload-time = "2026-07-31T14:24:50.085Z" }, +] + +[[package]] +name = "datasets" +version = "5.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dill" }, + { name = "filelock" }, + { name = "fsspec", extra = ["http"] }, + { name = "httpx" }, + { name = "huggingface-hub" }, + { name = "multiprocess" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pandas" }, + { name = "pyarrow" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "tqdm" }, + { name = "xxhash" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0a/5b/836516269d4f618efe621661cfb6f9acc57e6f95265db3efaee48a5ffe04/datasets-5.0.1.tar.gz", hash = "sha256:ce22bb851efd7494f08aad33b940803784434f6e77763d00679a0dc45fcf686a", size = 641498, upload-time = "2026-07-28T11:09:12.016Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/0b/98fc6eb83333508ca5f44c52b3e287ea8137a0ad582714e2cbc67a02154b/datasets-5.0.1-py3-none-any.whl", hash = "sha256:9fbf73688f8c18f7529b4fe592abd04015f81d1e58001e4bac73ffb2b39d7cc4", size = 559079, upload-time = "2026-07-28T11:09:10.266Z" }, +] + +[[package]] +name = "dill" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/81/e1/56027a71e31b02ddc53c7d65b01e68edf64dea2932122fe7746a516f75d5/dill-0.4.1.tar.gz", hash = "sha256:423092df4182177d4d8ba8290c8a5b640c66ab35ec7da59ccfa00f6fa3eea5fa", size = 187315, upload-time = "2026-01-19T02:36:56.85Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl", hash = "sha256:1e1ce33e978ae97fcfcff5638477032b801c46c7c65cf717f95fbc2248f79a9d", size = 120019, upload-time = "2026-01-19T02:36:55.663Z" }, +] + +[[package]] +name = "distro" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, +] + +[[package]] +name = "docstring-parser" +version = "0.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/4d/f332313098c1de1b2d2ff91cf2674415cc7cddab2ca1b01ae29774bd5fdf/docstring_parser-0.18.0.tar.gz", hash = "sha256:292510982205c12b1248696f44959db3cdd1740237a968ea1e2e7a900eeb2015", size = 29341, upload-time = "2026-04-14T04:09:19.867Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl", hash = "sha256:b3fcbed555c47d8479be0796ef7e19c2670d428d72e96da63f3a40122860374b", size = 22484, upload-time = "2026-04-14T04:09:18.638Z" }, +] + +[[package]] +name = "filelock" +version = "3.32.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/57/3ba6e6cb097f85b855b00163d169f35365f44277df044dcf96d55b8f62a3/filelock-3.32.2.tar.gz", hash = "sha256:c33351e1f49cae33414acbc6d56784e6ecee82514ec90795da1161fc4836b5b8", size = 217172, upload-time = "2026-07-29T22:46:04.895Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/e8/72f8cef9fdfeffe06213fe8508039396ee48daa0e3259457ed766173bfd6/filelock-3.32.2-py3-none-any.whl", hash = "sha256:87dd94cf281e586d135fa51132b8e3d9a598b316e90377a288663c9321036c82", size = 98830, upload-time = "2026-07-29T22:46:03.52Z" }, +] + +[[package]] +name = "frozenlist" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/29/948b9aa87e75820a38650af445d2ef2b6b8a6fab1a23b6bb9e4ef0be2d59/frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1", size = 87782, upload-time = "2025-10-06T05:36:06.649Z" }, + { url = "https://files.pythonhosted.org/packages/64/80/4f6e318ee2a7c0750ed724fa33a4bdf1eacdc5a39a7a24e818a773cd91af/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b", size = 50594, upload-time = "2025-10-06T05:36:07.69Z" }, + { url = "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4", size = 50448, upload-time = "2025-10-06T05:36:08.78Z" }, + { url = "https://files.pythonhosted.org/packages/6a/bd/d91c5e39f490a49df14320f4e8c80161cfcce09f1e2cde1edd16a551abb3/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383", size = 242411, upload-time = "2025-10-06T05:36:09.801Z" }, + { url = "https://files.pythonhosted.org/packages/8f/83/f61505a05109ef3293dfb1ff594d13d64a2324ac3482be2cedc2be818256/frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4", size = 243014, upload-time = "2025-10-06T05:36:11.394Z" }, + { url = "https://files.pythonhosted.org/packages/d8/cb/cb6c7b0f7d4023ddda30cf56b8b17494eb3a79e3fda666bf735f63118b35/frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8", size = 234909, upload-time = "2025-10-06T05:36:12.598Z" }, + { url = "https://files.pythonhosted.org/packages/31/c5/cd7a1f3b8b34af009fb17d4123c5a778b44ae2804e3ad6b86204255f9ec5/frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b", size = 250049, upload-time = "2025-10-06T05:36:14.065Z" }, + { url = "https://files.pythonhosted.org/packages/c0/01/2f95d3b416c584a1e7f0e1d6d31998c4a795f7544069ee2e0962a4b60740/frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52", size = 256485, upload-time = "2025-10-06T05:36:15.39Z" }, + { url = "https://files.pythonhosted.org/packages/ce/03/024bf7720b3abaebcff6d0793d73c154237b85bdf67b7ed55e5e9596dc9a/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29", size = 237619, upload-time = "2025-10-06T05:36:16.558Z" }, + { url = "https://files.pythonhosted.org/packages/69/fa/f8abdfe7d76b731f5d8bd217827cf6764d4f1d9763407e42717b4bed50a0/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3", size = 250320, upload-time = "2025-10-06T05:36:17.821Z" }, + { url = "https://files.pythonhosted.org/packages/f5/3c/b051329f718b463b22613e269ad72138cc256c540f78a6de89452803a47d/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143", size = 246820, upload-time = "2025-10-06T05:36:19.046Z" }, + { url = "https://files.pythonhosted.org/packages/0f/ae/58282e8f98e444b3f4dd42448ff36fa38bef29e40d40f330b22e7108f565/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608", size = 250518, upload-time = "2025-10-06T05:36:20.763Z" }, + { url = "https://files.pythonhosted.org/packages/8f/96/007e5944694d66123183845a106547a15944fbbb7154788cbf7272789536/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa", size = 239096, upload-time = "2025-10-06T05:36:22.129Z" }, + { url = "https://files.pythonhosted.org/packages/66/bb/852b9d6db2fa40be96f29c0d1205c306288f0684df8fd26ca1951d461a56/frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf", size = 39985, upload-time = "2025-10-06T05:36:23.661Z" }, + { url = "https://files.pythonhosted.org/packages/b8/af/38e51a553dd66eb064cdf193841f16f077585d4d28394c2fa6235cb41765/frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746", size = 44591, upload-time = "2025-10-06T05:36:24.958Z" }, + { url = "https://files.pythonhosted.org/packages/a7/06/1dc65480ab147339fecc70797e9c2f69d9cea9cf38934ce08df070fdb9cb/frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd", size = 40102, upload-time = "2025-10-06T05:36:26.333Z" }, + { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, +] + +[[package]] +name = "fsspec" +version = "2026.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/10/a1/ae4e3e5003468d6391d2c77b6fa1cd73bd5d13511d81c642d7b28ac90ed4/fsspec-2026.6.0.tar.gz", hash = "sha256:f5bac145310fe30e16e1471bd6840b2d990d609e872251d7e674241822abf01a", size = 313646, upload-time = "2026-06-16T01:57:28.105Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/22/4222d7ddf3da30f363edaa98e329c2bce6c65497c9cb2810931c8b2c0fbc/fsspec-2026.6.0-py3-none-any.whl", hash = "sha256:02e0b71817df9b2169dc30a16832045764def1191b43dcff5bb85bdee212d2a1", size = 203949, upload-time = "2026-06-16T01:57:26.358Z" }, +] + +[package.optional-dependencies] +http = [ + { name = "aiohttp" }, +] + +[[package]] +name = "gepa" +version = "0.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/95/56/925779e5690971f1b022f7d107caf015c33ec09560261273ec137e23a8f2/gepa-0.1.4.tar.gz", hash = "sha256:6dd153a676ae5481764860d19286a9c0e8ddb5ef70d7f13044faf24978bdb6b8", size = 351343, upload-time = "2026-07-15T14:53:59.929Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/77/5b3a281cfd9caaa9e68349b434cf27f1ca448003ee0067a1ae2184dc52d1/gepa-0.1.4-py3-none-any.whl", hash = "sha256:12b971039599625c156d2231f6d72a29c31a22e9c237689459b5f1a3c353f532", size = 290167, upload-time = "2026-07-15T14:53:58.422Z" }, +] + +[[package]] +name = "griffelib" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/33/e4/8d187ea29c2e30b3a09505c567513077d6117861bde1fbd997a167f262ec/griffelib-2.1.0.tar.gz", hash = "sha256:762a186d2c6fd6794d4ea20d428d597ffb857cb56b66421651cbba15bdd5e813", size = 216234, upload-time = "2026-06-19T12:05:42.278Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/d3/5268aeabf2ad82658c4e2ff3a060648d0f02f3926cb53247c0e4d0dab49e/griffelib-2.1.0-py3-none-any.whl", hash = "sha256:cc7b3d2d2865ad0b909fcc38086e3f554b5ea7acbaa7bbb7ecaa3f5dfb7d9f00", size = 142560, upload-time = "2026-06-19T12:05:38.742Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "hf-xet" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/ab/522a2ab67f27971a9d48ca666d4fca85ef7d5282d142e31fd087e27b1bbe/hf_xet-1.6.0.tar.gz", hash = "sha256:2e58454a340b3556dfa4972d5451aff4fba8dd42a236600ba1a1d2b1514f0fef", size = 920527, upload-time = "2026-08-03T22:33:13.243Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/50/7afa2c9c787405864fc47a0d1bbc02c62e9101947ed43c1f43899fc7d91d/hf_xet-1.6.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:633dc0cd71d32da58ab8c03ad38e2fac452c15c2b0a2866ebf6ededfe0a5061d", size = 4071729, upload-time = "2026-08-03T22:33:00.721Z" }, + { url = "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:f0906082d9932ae0c0057fa194041c22b4e2cdb46b2592ef3b91f020d62a081a", size = 3876287, upload-time = "2026-08-03T22:33:02.251Z" }, + { url = "https://files.pythonhosted.org/packages/67/4e/a28359bf1c1ecf11eba22123168c138698f7cb576ac678f5a2e16cd5da08/hf_xet-1.6.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d62671bb130879cef0ee4c9ebe47a14af6c66ec53e6d84dc15936e5ffdfac82f", size = 4464663, upload-time = "2026-08-03T22:33:03.802Z" }, + { url = "https://files.pythonhosted.org/packages/9a/69/1f0cbc2fb22ae6082d094f743d1b8945a3f36f6089cb95f42b7ee348cda7/hf_xet-1.6.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:0e6e21fa3cdfcdcd76748564bf593870a5e013f47d97cf10aed63aa222cff5b7", size = 4262538, upload-time = "2026-08-03T22:33:05.287Z" }, + { url = "https://files.pythonhosted.org/packages/d1/3a/4f4f2301ade26e404462d3336fa11f7958d914cabbabdd6e03c3c5d5658c/hf_xet-1.6.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4fc74352a17015bd0ee90038bc9efe38db894cde45f268b6712b04fce8cd0acb", size = 4460520, upload-time = "2026-08-03T22:33:06.81Z" }, + { url = "https://files.pythonhosted.org/packages/ab/5f/311725e2a905534dfee2dcb5b08414f249147f1f12252bfc2bd24caa075c/hf_xet-1.6.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8fb4f71cba6129110c3374a33f919001ff130488fc23553698e34cc1c2a1198c", size = 4675937, upload-time = "2026-08-03T22:33:08.616Z" }, + { url = "https://files.pythonhosted.org/packages/98/b7/8c59a66d15205024662f1d66968136f13893f96df1ddc5087e2e281fc95f/hf_xet-1.6.0-cp38-abi3-win_amd64.whl", hash = "sha256:fb4fadde1b2b70bf4c0c14a6dccbe7194b1c28947fefd5bbe3fed9d940676c3b", size = 4033128, upload-time = "2026-08-03T22:33:10.171Z" }, + { url = "https://files.pythonhosted.org/packages/73/63/ca511b6f802f28cf3489b280fe77475bcca8de85e81a6299d7916b5b5555/hf_xet-1.6.0-cp38-abi3-win_arm64.whl", hash = "sha256:3dc3e35441ba395006af5aaacc40ef2e603c51ef46c3530b9156185f00935ea3", size = 3859359, upload-time = "2026-08-03T22:33:11.725Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "httpx-sse" +version = "0.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/4c/751061ffa58615a32c31b2d82e8482be8dd4a89154f003147acee90f2be9/httpx_sse-0.4.3.tar.gz", hash = "sha256:9b1ed0127459a66014aec3c56bebd93da3c1bc8bb6618c8082039a44889a755d", size = 15943, upload-time = "2025-10-10T21:48:22.271Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl", hash = "sha256:0ac1c9fe3c0afad2e0ebb25a934a59f4c7823b60792691f779fad2c5568830fc", size = 8960, upload-time = "2025-10-10T21:48:21.158Z" }, +] + +[[package]] +name = "huggingface-hub" +version = "1.26.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "filelock" }, + { name = "fsspec" }, + { name = "hf-xet", marker = "platform_machine == 'AMD64' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" }, + { name = "httpx" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/82/db/3582597f8be0d34bd6881365a26d390854f12893eabdd62dd36de9df5a47/huggingface_hub-1.26.0.tar.gz", hash = "sha256:c8cd4e2df1ba9402f77fce9b509ec1d52debb502551789473f34016acc14e361", size = 936665, upload-time = "2026-07-30T14:12:04.156Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/97/bb/63a644c75b545f3ff394b822e9bd1c4a9586489c618b77a4d8a44a33a23b/huggingface_hub-1.26.0-py3-none-any.whl", hash = "sha256:e8cca670caa5d8dfa7e45bf45e86b466698198cd8150c021bcdb4a86b9252364", size = 780357, upload-time = "2026-07-30T14:12:01.998Z" }, +] + +[[package]] +name = "idna" +version = "3.18" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711, upload-time = "2026-06-02T14:34:07.794Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "jiter" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/1f/10936e16d8860c70698a1aa939a46aa0224813b782bce4e000e637da0b2d/jiter-0.16.0.tar.gz", hash = "sha256:7b24c3492c5f4f84a37946ad9cf504910cf6a782d6a4e0689b6673c5894b4a1c", size = 176431, upload-time = "2026-06-29T13:05:13.657Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/2b/52ace16ed031354f0539749a49e4bf33797d82bea5137910835fa4b09793/jiter-0.16.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:67c3bc1760f8c99d805dcab4e644027142a53b1d5d861f18780ebdbd5d40b72a", size = 306943, upload-time = "2026-06-29T13:03:14.035Z" }, + { url = "https://files.pythonhosted.org/packages/94/2e/34957c2c1b661c252ba9bcc60ae0bddc27e0f7202c6073326a13c5390eec/jiter-0.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5af7780e4a26bd7d0d989592bf9ef12ebf806b74ab709223ecca37c749872ea9", size = 307779, upload-time = "2026-06-29T13:03:15.418Z" }, + { url = "https://files.pythonhosted.org/packages/88/6c/59bd309cab4460c54cf1079f3eb7fe7af6a4c895c5c957a53378693bad2b/jiter-0.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5bf78d0e05e45cfdd66558893938d59afe3d1b1a824a202039b20e607d25a72", size = 335826, upload-time = "2026-06-29T13:03:17.11Z" }, + { url = "https://files.pythonhosted.org/packages/3b/8c/f5ef7b65f0df47afa16596969defb281ebb86e96df346d62be6fd853d620/jiter-0.16.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f4444a83f946605990c98f625cdd3d2725bfb818158760c5748c653170a20e0e", size = 362573, upload-time = "2026-06-29T13:03:18.781Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0b/ace4354da061ee38844a0c27dc2c21eecd27aea119e8da324bea987522d0/jiter-0.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3a23f0e4f957e1be65752d2dfac9a5a06b1917af8dc85deb639c3b9d02e31290", size = 457979, upload-time = "2026-06-29T13:03:20.293Z" }, + { url = "https://files.pythonhosted.org/packages/55/40/c0253d3772eb9dcd8e6606ee9b2d53ec8e5b814589c47f140aa585f21eaa/jiter-0.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c22a488f7b9218e245a0025a9ba6b100e2e54700831cf4cf16833a27fba3ad01", size = 372302, upload-time = "2026-06-29T13:03:21.739Z" }, + { url = "https://files.pythonhosted.org/packages/a8/d2/4839422241aa12860ce597b20068727094ba0bc480723c74924ca5bad483/jiter-0.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46add52f4ad47a08bfb1219f3e673da972191489a33016edefdb5ea55bfa8c48", size = 343805, upload-time = "2026-06-29T13:03:23.384Z" }, + { url = "https://files.pythonhosted.org/packages/e2/59/e196888a05befdda7dbe299b722d56f2f6eec65402bc34c0a3306d595feb/jiter-0.16.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:9c8a956fd72c2cf1e730d01ea080341f13aa0a97a4a33b51abebe725b7ae9ca9", size = 351107, upload-time = "2026-06-29T13:03:24.815Z" }, + { url = "https://files.pythonhosted.org/packages/ec/74/4cd9e0fca65232136400354b630fbfcd2de634e22ccbb96567725981b548/jiter-0.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:561926e0573ffe4a32498420a76d64b16c513e1ab413b9d28158a8764ac701e5", size = 388441, upload-time = "2026-06-29T13:03:26.266Z" }, + { url = "https://files.pythonhosted.org/packages/d9/8c/554691e48bc711299c0a293dd8a6179e24b2d66a54dc295421fcf64569c0/jiter-0.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:44d019fa8cdaf89bf29c71b39e3712143fdd0ac76725c6ef954f9957a5ea8730", size = 516354, upload-time = "2026-06-29T13:03:28.02Z" }, + { url = "https://files.pythonhosted.org/packages/a4/cb/01e9d69dc2cc6759d4f91e230b34489c4fdb2518992650633f9e20bece89/jiter-0.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0df91907609837f33341b8e6fe73b95991fdaa57caf1a0fbd343dffe826f386f", size = 547880, upload-time = "2026-06-29T13:03:29.534Z" }, + { url = "https://files.pythonhosted.org/packages/79/70/2953195f1c6ad00f49fa67e13df7e60acb3dd4f387101bc15abccddd905e/jiter-0.16.0-cp312-cp312-win32.whl", hash = "sha256:51d7b836acb0108d7c77df1742332cac2a1fa04a74d6dacec46e7091f0e91274", size = 203473, upload-time = "2026-06-29T13:03:31.025Z" }, + { url = "https://files.pythonhosted.org/packages/2d/05/2909a8b10699a4d560f8c502b6b2c5f3991b682b1922c1eedda242b225bd/jiter-0.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:1878349266f8ee36ecb1375cc5ba2f115f35fd9f0a1a4119e725e379126647f7", size = 196905, upload-time = "2026-06-29T13:03:32.472Z" }, + { url = "https://files.pythonhosted.org/packages/e9/a9/6b82bb1c8d7790d602489b967b982a909e5d092875a6c2ade96444c8dfc5/jiter-0.16.0-cp312-cp312-win_arm64.whl", hash = "sha256:2ed5738ae4af18271a51a528b8811b0cbfa4a1858de9d83359e4169855d6a331", size = 190618, upload-time = "2026-06-29T13:03:34.672Z" }, + { url = "https://files.pythonhosted.org/packages/98/ab/664fd8c4be028b2bedd3d2ff08769c4ede23d0dbc87a77c62384a0515b5d/jiter-0.16.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:f17d61a28b4b3e0e3e2ba98490c70501403b4d196f78732439160e7fd3678127", size = 303106, upload-time = "2026-06-29T13:05:07.118Z" }, + { url = "https://files.pythonhosted.org/packages/1a/07/421f1d5b65493a76e16027b848aba6a7d28073ae75944fa4289cc914d39f/jiter-0.16.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:96e38eea538c8ddf853a35727c7be0741c76c13f04148ac5c116222f50ece3b3", size = 304658, upload-time = "2026-06-29T13:05:08.708Z" }, + { url = "https://files.pythonhosted.org/packages/0a/db/bba1155f01a01c3c37a89425d571da751bbedf5c54247b831a04cb971798/jiter-0.16.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d284fb8d94d5855d60c44fefcab4bf966f1da6fada73992b01f6f0c9bc0c6702", size = 339719, upload-time = "2026-06-29T13:05:10.41Z" }, + { url = "https://files.pythonhosted.org/packages/78/f7/18a1afcd64f35314b68c1f23afcd9994d0bc13e65cc77517afff4e83986d/jiter-0.16.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64d613743df53199b1aa256a7d328340da6d7078aac7705a7db9d7a791e9cfd2", size = 343885, upload-time = "2026-06-29T13:05:12.087Z" }, +] + +[[package]] +name = "jsonschema" +version = "4.26.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload-time = "2026-01-07T13:41:05.306Z" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2025.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, +] + +[[package]] +name = "latex2sympy2-extended" +version = "1.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "antlr4-python3-runtime" }, + { name = "sympy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/30/75/456da2da05f6380ea96e6ea804ab2c03e41fc3ed80052307fe8efe6ea20e/latex2sympy2_extended-1.11.0.tar.gz", hash = "sha256:9695657c81b50abba2636638638618db59f4663ed2a4a12d62cef74a40e28fec", size = 207023, upload-time = "2026-01-10T01:43:21.319Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/61/f75cd1fa54d8434276126034aed54dd120747de9a8fa013cdd79545ccbeb/latex2sympy2_extended-1.11.0-py3-none-any.whl", hash = "sha256:aebb77d52ce269e25028e4bea89ddb14d242ba36bcf7b636496fb5fd9728d234", size = 209050, upload-time = "2026-01-10T01:43:19.458Z" }, +] + +[[package]] +name = "loguru" +version = "0.7.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "win32-setctime", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3a/05/a1dae3dffd1116099471c643b8924f5aa6524411dc6c63fdae648c4f1aca/loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6", size = 63559, upload-time = "2024-12-06T11:20:56.608Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c", size = 61595, upload-time = "2024-12-06T11:20:54.538Z" }, +] + +[[package]] +name = "markdown-it-py" +version = "4.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687, upload-time = "2026-05-07T12:08:27.182Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, +] + +[[package]] +name = "math-verify" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "latex2sympy2-extended" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4f/12/b8d13b581e110ac2f724a2351a8361a70fa36d057eb945d6379e8747c256/math_verify-0.9.0.tar.gz", hash = "sha256:45ac6c61344ba056b9e99a660a4bc8d044ed408f730aed68c60435aa5eec4645", size = 60329, upload-time = "2026-01-10T01:48:33.056Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/76/6b4969bccc842b6567f7e6ee015684b9428a9b7fcbdf479e73716f43597f/math_verify-0.9.0-py3-none-any.whl", hash = "sha256:3703e7c4885354027fa84409d762a596a2906d1fd4deb78361876bd905a76194", size = 29967, upload-time = "2026-01-10T01:48:31.674Z" }, +] + +[[package]] +name = "mcp" +version = "1.29.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "httpx" }, + { name = "httpx-sse" }, + { name = "jsonschema" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "pyjwt", extra = ["crypto"] }, + { name = "python-multipart" }, + { name = "pywin32", marker = "sys_platform == 'win32'" }, + { name = "sse-starlette" }, + { name = "starlette" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, + { name = "uvicorn", marker = "sys_platform != 'emscripten'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/30/d3/f9acc21dfc886e4f78e2add1a47db46ce16884346afde53f8a064c02c891/mcp-1.29.0.tar.gz", hash = "sha256:52d01f334de1868cc3bb2d6604931126a67631f99a6c5d3b82ba47290315ec36", size = 643148, upload-time = "2026-07-28T13:41:41.939Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl", hash = "sha256:f5a075bb611f23d6f4d080c6a1699fa62772eebc562ba9e66b306ddde1c755f7", size = 223436, upload-time = "2026-07-28T13:41:40.337Z" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + +[[package]] +name = "mpmath" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, +] + +[[package]] +name = "msgpack" +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/31/f9/c0a1c127f9049db9155afc316952ea571720dd01833ff5e4d7e8e6352dbb/msgpack-1.2.1.tar.gz", hash = "sha256:04c721c2c7448767e9e3f2520a475663d8ee0f09c31890f6d2bd70fd636a9647", size = 183960, upload-time = "2026-06-18T16:13:52.594Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/dd/9e8cbd8f5582ca4b590336f2b91ee5662f6a6ca562b565abaf696a0f81ff/msgpack-1.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2ef59c659f289eddf8aa6623823f19fa2f40a4029266889eac7a2505dd210c35", size = 83531, upload-time = "2026-06-18T16:12:58.249Z" }, + { url = "https://files.pythonhosted.org/packages/50/2e/ebdb85a8da151397a2790363676b7ed7c125924fe618e4c6d8befb0cc62c/msgpack-1.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d3567748a5107cb40cdf66a275430c2f87c07777698f4bfd25c35f44d533258c", size = 82657, upload-time = "2026-06-18T16:12:59.396Z" }, + { url = "https://files.pythonhosted.org/packages/26/aa/753ad8b007b464e1d8aa0c8e650b9c5f4f725e658fc5ac8a7635c55b7f6e/msgpack-1.2.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60926b75d00c8e816ef98f3034f484a8bc64242d66839cef4cf7e503142316a0", size = 410634, upload-time = "2026-06-18T16:13:00.383Z" }, + { url = "https://files.pythonhosted.org/packages/6a/fd/6adabd4f6d5e686f97dd02ce7fce3fe4cf672cbac36b8f67ff4040e8ad8b/msgpack-1.2.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:020e881a764b20d8d7ca1a54fc01b8175519d108e3c3f194fddc200bda95951a", size = 419989, upload-time = "2026-06-18T16:13:01.776Z" }, + { url = "https://files.pythonhosted.org/packages/5a/cc/85039b7b0eb168aaad7383a23c97e291a11f08351cb45a606ce865e4e3f1/msgpack-1.2.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4202c74688ca06591f78cb18988228bd4cca2cc75d57b60008372892d2f1e6e6", size = 377544, upload-time = "2026-06-18T16:13:03.637Z" }, + { url = "https://files.pythonhosted.org/packages/ed/bf/35963899493b32030c85fc513b723ae66144ac70c11ebc52e889e16e3d99/msgpack-1.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8b267ce94efb76fbd1b3373511420074ee3187f0f7811bf394531de13294735a", size = 400842, upload-time = "2026-06-18T16:13:05.012Z" }, + { url = "https://files.pythonhosted.org/packages/a6/df/8e2ac970c8f99264cd9997d1c73df5466bc19da3301d7dc5500862a9b089/msgpack-1.2.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e4f1d0f8f98ade9634e01fb704a408f9336c0a8f1117b369f5db83dc7551d8b1", size = 374108, upload-time = "2026-06-18T16:13:06.232Z" }, + { url = "https://files.pythonhosted.org/packages/17/dd/fa8bd265110dfa51c20cb529f9e6d240a16fafe7e645004c6af2d01353ba/msgpack-1.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f02cf17a6ca1abe29b5f980644f7551f94d71f2011509b26d8625ce038f0df64", size = 414939, upload-time = "2026-06-18T16:13:07.478Z" }, + { url = "https://files.pythonhosted.org/packages/2e/b9/8377a5ad8953fc0437c70cc98d9ae29f27fe5ac5109fbec0812085865735/msgpack-1.2.1-cp312-cp312-win32.whl", hash = "sha256:0c0d9802354507bcba62af19c17918e3eb437cc25e6f50657d511b5856a77aac", size = 64504, upload-time = "2026-06-18T16:13:08.822Z" }, + { url = "https://files.pythonhosted.org/packages/57/7f/ce1e377df7e62461fefd9eb23bfb93a4a523f40a517b377b8f844d836828/msgpack-1.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:5c24aa15d5963051e1a5c62b12c50cd705992502b5ec1f3bece6046f33c9fc24", size = 71421, upload-time = "2026-06-18T16:13:09.828Z" }, + { url = "https://files.pythonhosted.org/packages/8f/32/ebfe84c9929f08f188d56c7a2fd913406a9ddad76a634697c1c43b8112e6/msgpack-1.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:4227224aaec8f7fbcbfbd4272319347b2bb4030366502600f8c45588c5187b07", size = 64775, upload-time = "2026-06-18T16:13:11.056Z" }, +] + +[[package]] +name = "multidict" +version = "6.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010, upload-time = "2026-01-26T02:46:45.979Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/9c/f20e0e2cf80e4b2e4b1c365bf5fe104ee633c751a724246262db8f1a0b13/multidict-6.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a90f75c956e32891a4eda3639ce6dd86e87105271f43d43442a3aedf3cddf172", size = 76893, upload-time = "2026-01-26T02:43:52.754Z" }, + { url = "https://files.pythonhosted.org/packages/fe/cf/18ef143a81610136d3da8193da9d80bfe1cb548a1e2d1c775f26b23d024a/multidict-6.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fccb473e87eaa1382689053e4a4618e7ba7b9b9b8d6adf2027ee474597128cd", size = 45456, upload-time = "2026-01-26T02:43:53.893Z" }, + { url = "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0fa96985700739c4c7853a43c0b3e169360d6855780021bfc6d0f1ce7c123e7", size = 43872, upload-time = "2026-01-26T02:43:55.041Z" }, + { url = "https://files.pythonhosted.org/packages/cf/3b/d6bd75dc4f3ff7c73766e04e705b00ed6dbbaccf670d9e05a12b006f5a21/multidict-6.7.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cb2a55f408c3043e42b40cc8eecd575afa27b7e0b956dfb190de0f8499a57a53", size = 251018, upload-time = "2026-01-26T02:43:56.198Z" }, + { url = "https://files.pythonhosted.org/packages/fd/80/c959c5933adedb9ac15152e4067c702a808ea183a8b64cf8f31af8ad3155/multidict-6.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb0ce7b2a32d09892b3dd6cc44877a0d02a33241fafca5f25c8b6b62374f8b75", size = 258883, upload-time = "2026-01-26T02:43:57.499Z" }, + { url = "https://files.pythonhosted.org/packages/86/85/7ed40adafea3d4f1c8b916e3b5cc3a8e07dfcdcb9cd72800f4ed3ca1b387/multidict-6.7.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c3a32d23520ee37bf327d1e1a656fec76a2edd5c038bf43eddfa0572ec49c60b", size = 242413, upload-time = "2026-01-26T02:43:58.755Z" }, + { url = "https://files.pythonhosted.org/packages/d2/57/b8565ff533e48595503c785f8361ff9a4fde4d67de25c207cd0ba3befd03/multidict-6.7.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9c90fed18bffc0189ba814749fdcc102b536e83a9f738a9003e569acd540a733", size = 268404, upload-time = "2026-01-26T02:44:00.216Z" }, + { url = "https://files.pythonhosted.org/packages/e0/50/9810c5c29350f7258180dfdcb2e52783a0632862eb334c4896ac717cebcb/multidict-6.7.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:da62917e6076f512daccfbbde27f46fed1c98fee202f0559adec8ee0de67f71a", size = 269456, upload-time = "2026-01-26T02:44:02.202Z" }, + { url = "https://files.pythonhosted.org/packages/f3/8d/5e5be3ced1d12966fefb5c4ea3b2a5b480afcea36406559442c6e31d4a48/multidict-6.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde23ef6ed9db7eaee6c37dcec08524cb43903c60b285b172b6c094711b3961", size = 256322, upload-time = "2026-01-26T02:44:03.56Z" }, + { url = "https://files.pythonhosted.org/packages/31/6e/d8a26d81ac166a5592782d208dd90dfdc0a7a218adaa52b45a672b46c122/multidict-6.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3758692429e4e32f1ba0df23219cd0b4fc0a52f476726fff9337d1a57676a582", size = 253955, upload-time = "2026-01-26T02:44:04.845Z" }, + { url = "https://files.pythonhosted.org/packages/59/4c/7c672c8aad41534ba619bcd4ade7a0dc87ed6b8b5c06149b85d3dd03f0cd/multidict-6.7.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:398c1478926eca669f2fd6a5856b6de9c0acf23a2cb59a14c0ba5844fa38077e", size = 251254, upload-time = "2026-01-26T02:44:06.133Z" }, + { url = "https://files.pythonhosted.org/packages/7b/bd/84c24de512cbafbdbc39439f74e967f19570ce7924e3007174a29c348916/multidict-6.7.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c102791b1c4f3ab36ce4101154549105a53dc828f016356b3e3bcae2e3a039d3", size = 252059, upload-time = "2026-01-26T02:44:07.518Z" }, + { url = "https://files.pythonhosted.org/packages/fa/ba/f5449385510825b73d01c2d4087bf6d2fccc20a2d42ac34df93191d3dd03/multidict-6.7.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a088b62bd733e2ad12c50dad01b7d0166c30287c166e137433d3b410add807a6", size = 263588, upload-time = "2026-01-26T02:44:09.382Z" }, + { url = "https://files.pythonhosted.org/packages/d7/11/afc7c677f68f75c84a69fe37184f0f82fce13ce4b92f49f3db280b7e92b3/multidict-6.7.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3d51ff4785d58d3f6c91bdbffcb5e1f7ddfda557727043aa20d20ec4f65e324a", size = 259642, upload-time = "2026-01-26T02:44:10.73Z" }, + { url = "https://files.pythonhosted.org/packages/2b/17/ebb9644da78c4ab36403739e0e6e0e30ebb135b9caf3440825001a0bddcb/multidict-6.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc5907494fccf3e7d3f94f95c91d6336b092b5fc83811720fae5e2765890dfba", size = 251377, upload-time = "2026-01-26T02:44:12.042Z" }, + { url = "https://files.pythonhosted.org/packages/ca/a4/840f5b97339e27846c46307f2530a2805d9d537d8b8bd416af031cad7fa0/multidict-6.7.1-cp312-cp312-win32.whl", hash = "sha256:28ca5ce2fd9716631133d0e9a9b9a745ad7f60bac2bccafb56aa380fc0b6c511", size = 41887, upload-time = "2026-01-26T02:44:14.245Z" }, + { url = "https://files.pythonhosted.org/packages/80/31/0b2517913687895f5904325c2069d6a3b78f66cc641a86a2baf75a05dcbb/multidict-6.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcee94dfbd638784645b066074b338bc9cc155d4b4bffa4adce1615c5a426c19", size = 46053, upload-time = "2026-01-26T02:44:15.371Z" }, + { url = "https://files.pythonhosted.org/packages/0c/5b/aba28e4ee4006ae4c7df8d327d31025d760ffa992ea23812a601d226e682/multidict-6.7.1-cp312-cp312-win_arm64.whl", hash = "sha256:ba0a9fb644d0c1a2194cf7ffb043bd852cea63a57f66fbd33959f7dae18517bf", size = 43307, upload-time = "2026-01-26T02:44:16.852Z" }, + { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" }, +] + +[[package]] +name = "multiprocess" +version = "0.70.19" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dill" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a2/f2/e783ac7f2aeeed14e9e12801f22529cc7e6b7ab80928d6dcce4e9f00922d/multiprocess-0.70.19.tar.gz", hash = "sha256:952021e0e6c55a4a9fe4cd787895b86e239a40e76802a789d6305398d3975897", size = 2079989, upload-time = "2026-01-19T06:47:39.744Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/45/8004d1e6b9185c1a444d6b55ac5682acf9d98035e54386d967366035a03a/multiprocess-0.70.19-py310-none-any.whl", hash = "sha256:97404393419dcb2a8385910864eedf47a3cadf82c66345b44f036420eb0b5d87", size = 134948, upload-time = "2026-01-19T06:47:32.325Z" }, + { url = "https://files.pythonhosted.org/packages/86/c2/dec9722dc3474c164a0b6bcd9a7ed7da542c98af8cabce05374abab35edd/multiprocess-0.70.19-py311-none-any.whl", hash = "sha256:928851ae7973aea4ce0eaf330bbdafb2e01398a91518d5c8818802845564f45c", size = 144457, upload-time = "2026-01-19T06:47:33.711Z" }, + { url = "https://files.pythonhosted.org/packages/71/70/38998b950a97ea279e6bd657575d22d1a2047256caf707d9a10fbce4f065/multiprocess-0.70.19-py312-none-any.whl", hash = "sha256:3a56c0e85dd5025161bac5ce138dcac1e49174c7d8e74596537e729fd5c53c28", size = 150281, upload-time = "2026-01-19T06:47:35.037Z" }, + { url = "https://files.pythonhosted.org/packages/7e/82/69e539c4c2027f1e1697e09aaa2449243085a0edf81ae2c6341e84d769b6/multiprocess-0.70.19-py39-none-any.whl", hash = "sha256:0d4b4397ed669d371c81dcd1ef33fd384a44d6c3de1bd0ca7ac06d837720d3c5", size = 133477, upload-time = "2026-01-19T06:47:38.619Z" }, +] + +[[package]] +name = "numpy" +version = "2.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/22/fd/89965aa4ac08c74998539fcbf24fa3540f3e15237fbeb6bcf9c908f4aade/numpy-2.5.1.tar.gz", hash = "sha256:a48a113e6afea91f5608793bafa7ef2ad481fefbda87ec5069f483de61cb9fa3", size = 20755553, upload-time = "2026-07-04T17:08:00.933Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/7b/14687aa674250e5e546f616f486b0d56d3631cd5b2415739141ce40bdcea/numpy-2.5.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2c889b56fe48b1018f764b0eec8df59ab654e9148aa91faa12596043500de277", size = 16801574, upload-time = "2026-07-04T17:06:12.423Z" }, + { url = "https://files.pythonhosted.org/packages/e1/19/cc5bb2a3f2913d27d6dbb2c78d25921fabaedc6741d4a5a615a11f3c5bf3/numpy-2.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ab451b59c5643c570974c43aef780703ef1d3b4965d2be07afd530615a9358d1", size = 11772250, upload-time = "2026-07-04T17:06:15.726Z" }, + { url = "https://files.pythonhosted.org/packages/42/77/fdf34a71dd30f54979b18603bee915e0aaf825b07afe79acd60b04b691e2/numpy-2.5.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:78798bd5b9ad744056af8efa90e3b9ddaa53272a0848a483084a1cc0a13b2dc0", size = 5331516, upload-time = "2026-07-04T17:06:17.913Z" }, + { url = "https://files.pythonhosted.org/packages/ce/e2/eb7efa015b4cce41e2517bf182a7fce0d7d5b9d9ed76a29bfa0f4fe4505c/numpy-2.5.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:2ae0ca40bcb22d6ba59c1dfd5446f49940b0f2d821fde133f10dda11f816b84e", size = 6664863, upload-time = "2026-07-04T17:06:20.02Z" }, + { url = "https://files.pythonhosted.org/packages/a9/4b/a2b32dd94ee9ffbeecb28152240042a3949db33b1c834d44090b80e1b3b8/numpy-2.5.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:61ac47e772e6b8ea489e1d2f441a34c5c3ac17327e7ce294cbdf535795ad4e75", size = 15167977, upload-time = "2026-07-04T17:06:21.621Z" }, + { url = "https://files.pythonhosted.org/packages/b8/a9/6e73d68500f80773f65f0654ea932019d6694329a0eb0ed0533de38df376/numpy-2.5.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:59fda5e192b570217ec2580c96f00e9a7e12ef6866a900eb089b62c1a32545ca", size = 16672469, upload-time = "2026-07-04T17:06:24.064Z" }, + { url = "https://files.pythonhosted.org/packages/24/7d/ad3e59015135f5261c95fd4cafeff159c955febd83a99a1d9250c4233815/numpy-2.5.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f7119ebff1a9829e9f431a4f9d28e703023bb6b9fe7c8f724467dbfc27c94ab3", size = 16527531, upload-time = "2026-07-04T17:06:26.69Z" }, + { url = "https://files.pythonhosted.org/packages/83/d0/a39b2fbcde9cb17a1dac678f254b33a6336298af9df338824c685425d5e8/numpy-2.5.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e824c2acf8862052246be5a44c15da1777940c60d010dd2aab897824d9c430f9", size = 18431940, upload-time = "2026-07-04T17:06:29.521Z" }, + { url = "https://files.pythonhosted.org/packages/04/12/cff070947791c1ed425ff76413189adbdc2fbe215eba7ce7fa454a03c7f8/numpy-2.5.1-cp312-cp312-win32.whl", hash = "sha256:08d60c810432eb83360958dea0999ac4cfb94531ea8efcbf0b7f277c2068aeb2", size = 6066764, upload-time = "2026-07-04T17:06:32.571Z" }, + { url = "https://files.pythonhosted.org/packages/65/66/53f31807a48a750f9d748da273bc3fcedd12b27ff1f3e373bfec55ef2dc0/numpy-2.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:f7d60026c0bdb1380e83bfa7a0419c4577ee4b9a08880afcb6dadeb74c649fa2", size = 12430966, upload-time = "2026-07-04T17:06:34.926Z" }, + { url = "https://files.pythonhosted.org/packages/2b/2a/d1a88066b1c14186f5d3c0d18c94f17b064511982bab0578d49ee9d43c29/numpy-2.5.1-cp312-cp312-win_arm64.whl", hash = "sha256:17a25e09640602e10bc8de0e6fa2b3fd68eedd84ba6d7842dc8f32f9ab87bd0b", size = 10350488, upload-time = "2026-07-04T17:06:37.785Z" }, +] + +[[package]] +name = "openai" +version = "2.53.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "httpx" }, + { name = "jiter" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/cf/36e3e7235fdf6d125c052acc0970924611b17a20a4fe580596faf4566a65/openai-2.53.0.tar.gz", hash = "sha256:baf5802ad08980e1d9d561e1b996e800c8bcd14af5847c6d0e7a5cc59e4d4116", size = 1099435, upload-time = "2026-08-03T21:42:01.664Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/0f/cc6afea3542a5142c5d8fc8211c5e059a8375105d004a41dfa2c7948dbb0/openai-2.53.0-py3-none-any.whl", hash = "sha256:c694ffc747a3c4d1663ef2b07b811315a476164ee5efa3a993967349ebca7618", size = 1659829, upload-time = "2026-08-03T21:41:59.581Z" }, +] + +[[package]] +name = "openai-agents" +version = "0.19.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "griffelib" }, + { name = "mcp" }, + { name = "openai" }, + { name = "pydantic" }, + { name = "requests" }, + { name = "typing-extensions" }, + { name = "websockets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bf/ae/0424f85df059ae94f6bad55dcd3841177ddb8b40c15cd1e236e422c4b1bd/openai_agents-0.19.3.tar.gz", hash = "sha256:738a05c20d1d3f985e4f0fb28f155513829fb3fef636108b6a770bde136b1cb1", size = 5752641, upload-time = "2026-08-04T07:18:31.805Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/56/fc626c963029ffbba70c05090a6cb5be830bd6afc35eb527f579f5d80145/openai_agents-0.19.3-py3-none-any.whl", hash = "sha256:f86c3a8fff9e2cf50ebdc17dfd656bbdfb9c8ed465041185439244f27cd358d7", size = 962587, upload-time = "2026-08-04T07:18:29.149Z" }, +] + +[[package]] +name = "openai-harmony" +version = "0.0.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3e/92/2d038d096f29179c7c9571b431f9e739f87a487121901725e23fe338dd9d/openai_harmony-0.0.8.tar.gz", hash = "sha256:6e43f98e6c242fa2de6f8ea12eab24af63fa2ed3e89c06341fb9d92632c5cbdf", size = 284777, upload-time = "2025-11-05T19:07:06.727Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/c6/2502f416d46be3ec08bb66d696cccffb57781a499e3ff2e4d7c174af4e8f/openai_harmony-0.0.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:029ec25ca74abe48fdb58eb9fdd2a8c1618581fc33ce8e5653f8a1ffbfbd9326", size = 2627806, upload-time = "2025-11-05T19:06:57.063Z" }, + { url = "https://files.pythonhosted.org/packages/d3/d2/ce6953ca87db9cae3e775024184da7d1c5cb88cead19a2d75b42f00a959c/openai_harmony-0.0.8-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4f709815924ec325b9a890e6ab2bbb0ceec8e319a4e257328eb752cf36b2efc", size = 2948463, upload-time = "2025-11-05T19:06:48.17Z" }, + { url = "https://files.pythonhosted.org/packages/fa/4c/b553c9651662d6ce102ca7f3629d268b23df1abe5841e24bed81e8a8e949/openai_harmony-0.0.8-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5cfcfd963b50a41fc656c84d3440ca6eecdccd6c552158ce790b8f2e33dfb5a9", size = 2704083, upload-time = "2025-11-05T19:06:50.205Z" }, + { url = "https://files.pythonhosted.org/packages/9b/af/4eec8f9ab9c27bcdb444460c72cf43011d176fc44c79d6e113094ca1e152/openai_harmony-0.0.8-cp38-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a3a16972aa1cee38ea958470cd04ac9a2d5ac38fdcf77ab686611246220c158", size = 2959765, upload-time = "2025-11-05T19:06:53.62Z" }, + { url = "https://files.pythonhosted.org/packages/11/3c/33f3374e4624e0e776f6b13b73c45a7ead7f9c4529f8369ed5bfcaa30cac/openai_harmony-0.0.8-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4d5cfa168e74d08f8ba6d58a7e49bc7daef4d58951ec69b66b0d56f4927a68d", size = 3427031, upload-time = "2025-11-05T19:06:51.829Z" }, + { url = "https://files.pythonhosted.org/packages/25/3f/1a192b93bb47c6b44cd98ba8cc1d3d2a9308f1bb700c3017e6352da11bda/openai_harmony-0.0.8-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c007d277218a50db8839e599ed78e0fffe5130f614c3f6d93ae257f282071a29", size = 2953260, upload-time = "2025-11-05T19:06:55.406Z" }, + { url = "https://files.pythonhosted.org/packages/5b/f8/93b582cad3531797c3db7c2db5400fd841538ccddfd9f5e3df61be99a630/openai_harmony-0.0.8-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:8565d4f5a0638da1bffde29832ed63c9e695c558611053add3b2dc0b56c92dbc", size = 3127044, upload-time = "2025-11-05T19:06:59.553Z" }, + { url = "https://files.pythonhosted.org/packages/1d/10/4327dbf87f75ae813405fd9a9b4a5cde63d506ffed0a096a440a4cabd89c/openai_harmony-0.0.8-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:cbaa3bda75ef0d8836e1f8cc84af62f971b1d756d740efc95c38c3e04c0bfde2", size = 2932931, upload-time = "2025-11-05T19:07:01.437Z" }, + { url = "https://files.pythonhosted.org/packages/8a/c8/1774eec4f6f360ef57618fb8f52e3d3af245b2491bd0297513aa09eec04b/openai_harmony-0.0.8-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:772922a9bd24e133950fad71eb1550836f415a88e8c77870e12d0c3bd688ddc2", size = 2996140, upload-time = "2025-11-05T19:07:03.438Z" }, + { url = "https://files.pythonhosted.org/packages/60/c3/3d1e01e2dba517a91760e4a03e4f20ffc75039a6fe584d0e6f9b5c78fd15/openai_harmony-0.0.8-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:007b0476a1f331f8130783f901f1da6f5a7057af1a4891f1b6a31dec364189b5", size = 3205080, upload-time = "2025-11-05T19:07:05.078Z" }, + { url = "https://files.pythonhosted.org/packages/14/63/119de431572d7c70a7bf1037034a9be6ed0a7502a7498ba7302bca5b3242/openai_harmony-0.0.8-cp38-abi3-win32.whl", hash = "sha256:a9b5f893326b28d9e935ade14b4f655f5a840942473bc89b201c25f7a15af9cf", size = 2082457, upload-time = "2025-11-05T19:07:09.631Z" }, + { url = "https://files.pythonhosted.org/packages/40/1f/c83cf5a206c263ee70448a5ae4264682555f4d0b5bed0d2cc6ca1108103d/openai_harmony-0.0.8-cp38-abi3-win_amd64.whl", hash = "sha256:39d44f0d8f466bd56698e7ead708bead3141e27b9b87e3ab7d5a6d0e4a869ee5", size = 2438369, upload-time = "2025-11-05T19:07:08.1Z" }, +] + +[[package]] +name = "opentelemetry-api" +version = "1.44.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ee/8b/aa9e2d8b8dfa7c946f7dec5d1f8f6ba8eca062f43509a06bdb5ce93d26c0/opentelemetry_api-1.44.0.tar.gz", hash = "sha256:67647e5e9566edcf421166fdf022b3537f818635daa852b289e34604dc6fb33a", size = 72406, upload-time = "2026-07-16T15:25:32.678Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl", hash = "sha256:94b98c893a91b88657eaac1e3ba89618cdb85be6918196705354f34728b2cdef", size = 60018, upload-time = "2026-07-16T15:25:11.657Z" }, +] + +[[package]] +name = "packaging" +version = "26.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, +] + +[[package]] +name = "pandas" +version = "3.0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "python-dateutil" }, + { name = "tzdata", marker = "sys_platform == 'emscripten' or sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/be/4f/5f3422a2afec5ffc46308b79e53291365a93748b498ac2e58bead0197916/pandas-3.0.5.tar.gz", hash = "sha256:dca3734d6ab7c906e6730f0788b0a1dbb9f2467731f9711f77995c8e9d62d712", size = 4658219, upload-time = "2026-07-22T22:19:28.819Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1c/54/1dc810ea558d1320b597aa140a514f2fdf1d2ea09c38cf556f13ea712ec9/pandas-3.0.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fa290c16964d4963fbfbc358928239cf3bd755b20e988ce944877def2f44471d", size = 10411717, upload-time = "2026-07-22T22:18:08.307Z" }, + { url = "https://files.pythonhosted.org/packages/68/56/fbe81c09195924d8b7b8d4461a20458fe80a6a5ed6b24f0314da684277e1/pandas-3.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c2e26bb46934b8a2ca0c3de1d3d606fc5f6746584791b2db264d58cf370e08dc", size = 9957095, upload-time = "2026-07-22T22:18:10.6Z" }, + { url = "https://files.pythonhosted.org/packages/e0/51/fac252f4a913ed5eabf3c11b880a9e8d5a6c10f0b2129d0462212d238b4d/pandas-3.0.5-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:73fa87b08a7ef706f8aafda39ddaccf2a99047bea62d8c88a0361bcafb2237bc", size = 10485458, upload-time = "2026-07-22T22:18:12.834Z" }, + { url = "https://files.pythonhosted.org/packages/12/98/e976540c1addf70442be7842a18cf70884a964abbf69442504f4d2939989/pandas-3.0.5-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d373ce03ffd84010ed9839fa73672a9c8256990532e158440c0085db7d914b34", size = 10998091, upload-time = "2026-07-22T22:18:15.209Z" }, + { url = "https://files.pythonhosted.org/packages/a4/8c/1f29b5be8d3fc47dd7567eb167fabba2085879b31e0287ce7cba6d3d2ff4/pandas-3.0.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2a29c53d85ea98c5e792c59ef82ee9fbe6ca902c0d0adb6b23f45ef894cd7bf6", size = 11499501, upload-time = "2026-07-22T22:18:17.689Z" }, + { url = "https://files.pythonhosted.org/packages/9d/e2/bd9c98ad2df7b38bde002adde4cdf353519da51881634323b126c55997f9/pandas-3.0.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a5ad3b02ed6bc7d7ae9b70804b2c6aa31827489d150f8e623ce82491b82085d7", size = 12060559, upload-time = "2026-07-22T22:18:20.147Z" }, + { url = "https://files.pythonhosted.org/packages/f3/9a/ffbd852d58bd74a617fe2f8ee6a58a96982271ce41cf981eab22190b4a4b/pandas-3.0.5-cp312-cp312-pyemscripten_2024_0_wasm32.whl", hash = "sha256:b2acb4650527eec6822c3dadb2b771277b65e7dae7a267d4bccf65fd1bb3fbce", size = 7197652, upload-time = "2026-07-22T22:18:22.502Z" }, + { url = "https://files.pythonhosted.org/packages/70/b5/d2d3e9ae73362ba4229651b0ee1455cf78073a1ce585f6ff693782ce263e/pandas-3.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:80a611068e8a3ac23f7398c6c14eb46dc974e5cc9997f653e2dcfd1da74edd41", size = 9831691, upload-time = "2026-07-22T22:18:24.534Z" }, + { url = "https://files.pythonhosted.org/packages/52/51/dea1e89d6a6796b9c43f85a09b484ee03edb8a4c4842e73e200a8c11301c/pandas-3.0.5-cp312-cp312-win_arm64.whl", hash = "sha256:25ff585b972a18ef1fe9ffa3ac6544d9950508aa76832e5147640b6022821e49", size = 9105796, upload-time = "2026-07-22T22:18:27.064Z" }, +] + +[[package]] +name = "prime-pydantic-config" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3c/37/e240dd598e687af74523f4497acb122b6d484975dac35e38932b58733753/prime_pydantic_config-0.4.2.tar.gz", hash = "sha256:7e85ac624c63edc1995ef512398fa5cd4610724b48a65c595f7742b7514153a4", size = 75997, upload-time = "2026-07-20T19:39:54.631Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/f7/12d3b54d0db5812d4fb9e8b9df987f805e687df2f0d11359c2d066df513c/prime_pydantic_config-0.4.2-py3-none-any.whl", hash = "sha256:092f7da638f625747a136983b579f5c929ead1b243df22f69fad6cf16b044ab0", size = 27414, upload-time = "2026-07-20T19:39:53.716Z" }, +] + +[package.optional-dependencies] +toml = [ + { name = "tomli" }, +] + +[[package]] +name = "prime-sandboxes" +version = "0.2.34" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiofiles" }, + { name = "connect-python" }, + { name = "httpx" }, + { name = "protobuf" }, + { name = "pydantic" }, + { name = "tenacity" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d8/85/3bf9aaba1485058ea30821bc26296a0869cd8416f633b10483c8fe897dd5/prime_sandboxes-0.2.34.tar.gz", hash = "sha256:d95e0b320e372f557785d216a572a2af3287136c0e355d6a9728b242897331e7", size = 81225, upload-time = "2026-07-28T20:08:44.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/1e/79149754046add7070dbdc53242a836f6539fbc1da8bbca0c086c2998703/prime_sandboxes-0.2.34-py3-none-any.whl", hash = "sha256:75e0dccd0d310aca759d5de64ccbd732634ca267cf47a12ae0bfc01bc46bfec8", size = 42773, upload-time = "2026-07-28T20:08:42.74Z" }, +] + +[[package]] +name = "prime-tunnel" +version = "0.1.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httpx" }, + { name = "pydantic" }, + { name = "tenacity" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bf/26/7324b5b9ec117c21fc9320214bf04ecbe9144ee87ef48c7d6d6c3e3d3f7f/prime_tunnel-0.1.10.tar.gz", hash = "sha256:8bf575af659bcc107a98b0b5ec1ba3e958ea72ead535ced03c443134a1ad07ea", size = 15305, upload-time = "2026-06-17T00:01:02.392Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/b9/d767b4f6c7ce72b54aaba834b97f97c3c494f1865a37f8b5b9acfb1b2a68/prime_tunnel-0.1.10-py3-none-any.whl", hash = "sha256:6a1cb49a14cfc9622db5cae90665ebe7e7e8cd5d84e963e8c3572bce85288400", size = 16319, upload-time = "2026-06-17T00:01:01.095Z" }, +] + +[[package]] +name = "propcache" +version = "0.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/44/c87281c333769159c50594f22610f77398a47ccbfbbf23074e744e86f87c/propcache-0.5.2.tar.gz", hash = "sha256:01c4fc7480cd0598bb4b57022df55b9ca296da7fc5a8760bd8451a7e63a7d427", size = 50208, upload-time = "2026-05-08T21:02:12.199Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4a/cb/e27bc2b2737a0bb49962b275efa051e8f1c35a936df7d5139b6b658b7dc9/propcache-0.5.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:806719138ecd720339a12410fb9614ac9b2b2d3a5fdf8235d56981c36f4039ba", size = 95887, upload-time = "2026-05-08T21:00:11.277Z" }, + { url = "https://files.pythonhosted.org/packages/e6/13/b8ae04c59392f8d11c6cd9fb4011d1dc7c86b81225c770280300e259ffe1/propcache-0.5.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:db2b80ea58eab4f86b2beec3cc8b39e8ff9276ac20e96b7cce43c8ae84cd6b5a", size = 54654, upload-time = "2026-05-08T21:00:12.604Z" }, + { url = "https://files.pythonhosted.org/packages/2c/7d/49777a3e20b55863d4794384a38acd460c04157b0a00f8602b0d508b8431/propcache-0.5.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e5cbfac9f61484f7e9f3597775500cd3ebe8274e9b050c38f9525c77c97520bf", size = 55190, upload-time = "2026-05-08T21:00:13.935Z" }, + { url = "https://files.pythonhosted.org/packages/44/c7/085d0cd63062e84044e3f05797749c3f8e3938ff3aeb0eb2f69d43fafc91/propcache-0.5.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5dbc581d2814337da56222fab8dc5f161cd798a434e49bac27930aaef798e144", size = 59995, upload-time = "2026-05-08T21:00:15.526Z" }, + { url = "https://files.pythonhosted.org/packages/9c/42/32cf8e3009e92b2645cf1e944f701e8ea4e924dffde1ee26db860bcbf7e4/propcache-0.5.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:857187f381f88c8e2fa2fe56ab94879d011b883d5a2ee5a1b60a8cd2a06846d9", size = 63422, upload-time = "2026-05-08T21:00:16.824Z" }, + { url = "https://files.pythonhosted.org/packages/9e/1b/f112433f99fc979431b87a39ef169e3f8df070d99a72792c56d6937ac48b/propcache-0.5.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:178b4a2cdaac1818e2bf1c5a99b94383fa73ea5382e032a48dec07dc5668dc42", size = 64342, upload-time = "2026-05-08T21:00:18.362Z" }, + { url = "https://files.pythonhosted.org/packages/14/15/5574111ae50dd6e879456888c0eadd4c5a869959775854e18e18a6b345f3/propcache-0.5.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f328175a2cde1f0ff2c4ed8ce968b9dcfb55f3a7153f39e2957ed994da13476", size = 61639, upload-time = "2026-05-08T21:00:19.692Z" }, + { url = "https://files.pythonhosted.org/packages/cc/da/4d775080b1490c0ae604acda868bd71aabe3a89ed16f2aa4339eb8a283e7/propcache-0.5.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5671d09a36b06d0fd4a3da0fccbcae360e9b1570924171a15e9e0997f0249fba", size = 61588, upload-time = "2026-05-08T21:00:21.155Z" }, + { url = "https://files.pythonhosted.org/packages/04/ac/f076982cbe2195ee9cf32de5a1e46951d9fb399fc207f390562dd0fd8fb2/propcache-0.5.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:80168e2ebe4d3ec6599d10ad8f520304ae1cad9b6c5a95372aef1b66b7bfb53a", size = 60029, upload-time = "2026-05-08T21:00:22.713Z" }, + { url = "https://files.pythonhosted.org/packages/70/60/189be62e0dd898dce3b331e1b8c7a543cd3a405ac0c81fe8ee8a9d5d77e1/propcache-0.5.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:45f11346f884bc47444f6e6647131055844134c3175b629f84952e2b5cd62b64", size = 56774, upload-time = "2026-05-08T21:00:24.001Z" }, + { url = "https://files.pythonhosted.org/packages/ea/9e/93377b9c7939c1ffae98f878dee955efadfd638078bc86dbc21f9d52f651/propcache-0.5.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8e778ebd44ef4f66ed60a0416b06b489687db264a9c0b3620362f26489492913", size = 63532, upload-time = "2026-05-08T21:00:25.545Z" }, + { url = "https://files.pythonhosted.org/packages/14/f9/590ef6cfb9b8028d516d287812ece32bb0bc5f11fbb9c8bf6b2e6313fec8/propcache-0.5.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:c0cb9ed24c8964e172768d455a38254c2dd8a552905729ce006cad3d3dda59b1", size = 61592, upload-time = "2026-05-08T21:00:27.186Z" }, + { url = "https://files.pythonhosted.org/packages/b4/5e/70958b3034c297a630bba2f17ca7abc2d5f39a803ad7e370ab79d1ecd022/propcache-0.5.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1d1ad32d9d4355e2be65574fd0bfd3677e7066b009cd5b9b2dee8aa6a6393b33", size = 64788, upload-time = "2026-05-08T21:00:28.8Z" }, + { url = "https://files.pythonhosted.org/packages/12/fd/77fe5936d8c3086ca9048f7f415f122ed82e53884a9ec193646b42deef06/propcache-0.5.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c80f4ba3e8f00189165999a742ee526ebeccedf6c3f7beb0c7df821e9772435a", size = 62514, upload-time = "2026-05-08T21:00:30.098Z" }, + { url = "https://files.pythonhosted.org/packages/cf/74/66bd798b5b3be70aa1b391f5cc9d6a0a5532d7fd3b19ec0b213e72e6ad9d/propcache-0.5.2-cp312-cp312-win32.whl", hash = "sha256:8c7972d8f193740d9175f0998ab38717e6cd322d5935c5b0fef8c0d323fd9031", size = 39018, upload-time = "2026-05-08T21:00:31.622Z" }, + { url = "https://files.pythonhosted.org/packages/61/7c/5c0d34aa3024694d6dcb9271cdbdd08c4e47c1c0ad95ec7e7bc74cdea145/propcache-0.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:d9ee8826a7d47863a08ac44e1a5f611a462eefc3a194b492da242128bec75b42", size = 42322, upload-time = "2026-05-08T21:00:32.918Z" }, + { url = "https://files.pythonhosted.org/packages/4d/91/875812f1a3feb20ceba818ef39fbe4d92f1081e04ac815c822496d0d038b/propcache-0.5.2-cp312-cp312-win_arm64.whl", hash = "sha256:2800a4a8ead6b28cccd1ec54b59346f0def7922ee1c7598e8499c733cfbb7c84", size = 38172, upload-time = "2026-05-08T21:00:35.124Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ed/1cdcab6ba3d6ab7feca11fc14f0eeea80755bb53ef4e892079f31b10a25f/propcache-0.5.2-py3-none-any.whl", hash = "sha256:be1ddfcbb376e3de5d2e2db1d58d6d67463e6b4f9f040c000de8e300295465fe", size = 14036, upload-time = "2026-05-08T21:02:10.673Z" }, +] + +[[package]] +name = "protobuf" +version = "7.35.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/da/01/9ef0afd7999eb9badb3a768b4aedd78c86d4c65cfaf1958ab276199e76b4/protobuf-7.35.1.tar.gz", hash = "sha256:ce115a26fe0c39a2c29973d914d327e516a6455464489fe3cd1e51a1b354f81a", size = 458717, upload-time = "2026-06-11T21:55:40.257Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/03/8aeeb7458d22546bf64b5250ca1daeb5ff757d900e8e4a7476c6f0db843e/protobuf-7.35.1-cp310-abi3-macosx_10_9_universal2.whl", hash = "sha256:24f857477359a85c0c235261b8ba905fd51b2562f4a64ca1df5473f29850cbf6", size = 433226, upload-time = "2026-06-11T21:55:31.719Z" }, + { url = "https://files.pythonhosted.org/packages/37/4b/dfb89eb0e652a1ff073c39a59fb5e3a83cfe9b57a2c83fa6d78270101767/protobuf-7.35.1-cp310-abi3-manylinux2014_aarch64.whl", hash = "sha256:11d6b0ec246892d85215b0a13ca6e0233cf5284b68f0ac02646427f4ff88a799", size = 328847, upload-time = "2026-06-11T21:55:34.035Z" }, + { url = "https://files.pythonhosted.org/packages/0f/58/dc12f2cd484951524af6e3382c785869b9b3fb5e52ee95ae23add53ee8f9/protobuf-7.35.1-cp310-abi3-manylinux2014_s390x.whl", hash = "sha256:b73f9489a4b8b1c9cb1f8ed951c736392592edb24b9d6819f36d2e10b171d5b4", size = 344030, upload-time = "2026-06-11T21:55:34.941Z" }, + { url = "https://files.pythonhosted.org/packages/e4/be/5b3cfe508bfab6761414ff944e3366eb13be4fd71efcd69450f89ba39f43/protobuf-7.35.1-cp310-abi3-manylinux2014_x86_64.whl", hash = "sha256:74758715c53d7158fb76caf4f0cfdacc5329a4b1bb994f865d6cf302d413a1c4", size = 327130, upload-time = "2026-06-11T21:55:35.921Z" }, + { url = "https://files.pythonhosted.org/packages/d8/bc/6d6c7ba8709c85f8f2c390b2b118d6fb08a783676a572271851bf45a7d22/protobuf-7.35.1-cp310-abi3-win32.whl", hash = "sha256:353652e4efd0bca5b5fc2656abf8307ef351f0cf938c9eba09f0e09c20a25c30", size = 428945, upload-time = "2026-06-11T21:55:37.034Z" }, + { url = "https://files.pythonhosted.org/packages/0a/19/8d0cb6f20a1ef7b18f1c8986ad5783f22f84cce39c6ce9a6e645ea55192e/protobuf-7.35.1-cp310-abi3-win_amd64.whl", hash = "sha256:230a75ddfc2de4806e56696ce9640c1cdfdb6543b7cfce98d42a4c0a0e7bdb87", size = 439996, upload-time = "2026-06-11T21:55:38.123Z" }, + { url = "https://files.pythonhosted.org/packages/19/c7/5f7c636ec43e0c545e28d1f1db71990108306f7bdcb89f069ba97e428e7f/protobuf-7.35.1-py3-none-any.whl", hash = "sha256:4bc97768d8fe4ad6743c8a19403e314511ed9f6d13205b687e52421c023ac1b9", size = 171659, upload-time = "2026-06-11T21:55:39.155Z" }, +] + +[[package]] +name = "pyarrow" +version = "25.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/27/f3/95428098d1fa7d04432fb750eed06b41304c2f6a5d3319985e64db2d9d41/pyarrow-25.0.0.tar.gz", hash = "sha256:d2d697008b5ec06d75952ef260c2e9a8a0f6ccfce24266c04c9c8ade927cb3b4", size = 1199181, upload-time = "2026-07-10T08:29:50.116Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/44/fdd3a4377807b7dcabe2d4b5aa99dbbc98e2e5df3f1ca4e7f0aec492d987/pyarrow-25.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:149730a3d1f0fb59d663a0b8aa210adfd9c17c27cd94a0d143e60daea8320d4e", size = 35850884, upload-time = "2026-07-10T08:26:47.357Z" }, + { url = "https://files.pythonhosted.org/packages/bf/71/9f053177a7709b8c90abb00a2375b916286f9f0d6cfb21a5cadd4ef811e8/pyarrow-25.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:0721332c30fdd453fdd1fc203b2ac1f4c9db5aea28fa38d41f2574c4b068b9ec", size = 37616197, upload-time = "2026-07-10T08:26:53.564Z" }, + { url = "https://files.pythonhosted.org/packages/95/1a/22bfb6597dcdc861fa83c39c06e1457cb56f698940eff42fbb25de30e8e5/pyarrow-25.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:fa1482b3da10cac2d4db6e26b81da543e237616af2ef6d466018b31ca586496f", size = 46841966, upload-time = "2026-07-10T08:27:07.685Z" }, + { url = "https://files.pythonhosted.org/packages/55/0e/cd705c042bc4fe7022478db577fcab4abdcfabb9bc37ab7a75556b3fcb2b/pyarrow-25.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:5d1dbf24e151042f2fa3c129563f65d66674128868496fb008c4272b16bdf778", size = 50088993, upload-time = "2026-07-10T08:27:14.268Z" }, + { url = "https://files.pythonhosted.org/packages/98/ee/d822e1ee31fe31ec5d057210e0605c950b975dcd8d9a332976cc859a9df8/pyarrow-25.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:20887a762dd61dcc530f93a140840ab1f6aa7836b33270e42d627ab3cf11e537", size = 49941005, upload-time = "2026-07-10T08:27:21.274Z" }, + { url = "https://files.pythonhosted.org/packages/33/1b/207a90cc64619a095eb75a263ae069735f2810056d43c667befd573ec083/pyarrow-25.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:58d1ab556b0cea1c93fdb799b24ad58adb2f2a2788dbce782a94f64ae1a5cc9b", size = 53112355, upload-time = "2026-07-10T08:27:27.911Z" }, + { url = "https://files.pythonhosted.org/packages/7e/fe/81d1e5f8beed15c01e98649d5c6e2167b67fd395884a2488f18bf1cf0dba/pyarrow-25.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:3f356afe61186395c861d5cd63dc21ff7d5fa335012a4668d979257df7fea0f5", size = 27945954, upload-time = "2026-07-10T08:27:32.903Z" }, +] + +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + +[[package]] +name = "pydantic" +version = "2.13.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/18/a5/b60d21ac674192f8ab0ba4e9fd860690f9b4a6e51ca5df118733b487d8d6/pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6", size = 844775, upload-time = "2026-05-06T13:43:05.343Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl", hash = "sha256:45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba", size = 472262, upload-time = "2026-05-06T13:43:02.641Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.46.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464, upload-time = "2026-05-06T13:37:06.98Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/8c/af022f0af448d7747c5154288d46b5f2bc5f17366eaa0e23e9aa04d59f3b/pydantic_core-2.46.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3245406455a5d98187ec35530fd772b1d799b26667980872c8d4614991e2c4a2", size = 2106158, upload-time = "2026-05-06T13:38:57.215Z" }, + { url = "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:962ccbab7b642487b1d8b7df90ef677e03134cf1fd8880bf698649b22a69371f", size = 1951724, upload-time = "2026-05-06T13:37:02.697Z" }, + { url = "https://files.pythonhosted.org/packages/8e/bc/f47d1ff9cbb1620e1b5b697eef06010035735f07820180e74178226b27b3/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8233f2947cf85404441fd7e0085f53b10c93e0ee78611099b5c7237e36aacbf7", size = 1975742, upload-time = "2026-05-06T13:37:09.448Z" }, + { url = "https://files.pythonhosted.org/packages/5b/11/9b9a5b0306345664a2da6410877af6e8082481b5884b3ddd78d47c6013ce/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a233125ac121aa3ffba9a2b59edfc4a985a76092dc8279586ab4b71390875e7", size = 2052418, upload-time = "2026-05-06T13:37:38.234Z" }, + { url = "https://files.pythonhosted.org/packages/f1/b7/a65fec226f5d78fc39f4a13c4cc0c768c22b113438f60c14adc9d2865038/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b712b53160b79a5850310b912a5ef8e57e56947c8ad690c227f5c9d7e561712", size = 2232274, upload-time = "2026-05-06T13:38:27.753Z" }, + { url = "https://files.pythonhosted.org/packages/68/f0/92039db98b907ef49269a8271f67db9cb78ae2fc68062ef7e4e77adb5f61/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9401557acd873c3a7f3eb9383edef8ac4968f9510e340f4808d427e75667e7b4", size = 2309940, upload-time = "2026-05-06T13:38:05.353Z" }, + { url = "https://files.pythonhosted.org/packages/5f/97/2aab507d3d00ca626e8e57c1eac6a79e4e5fbcc63eb99733ff55d1717f65/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:926c9541b14b12b1681dca8a0b75feb510b06c6341b70a8e500c2fdcff837cce", size = 2094516, upload-time = "2026-05-06T13:39:10.577Z" }, + { url = "https://files.pythonhosted.org/packages/22/37/a8aca44d40d737dde2bc05b3c6c07dff0de07ce6f82e9f3167aeaf4d5dea/pydantic_core-2.46.4-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:56cb4851bcaf3d117eddcef4fe66afd750a50274b0da8e22be256d10e5611987", size = 2136854, upload-time = "2026-05-06T13:40:22.59Z" }, + { url = "https://files.pythonhosted.org/packages/24/99/fcef1b79238c06a8cbec70819ac722ba76e02bc8ada9b0fd66eba40da01b/pydantic_core-2.46.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c68fcd102d71ea85c5b2dfac3f4f8476eff42a9e078fd5faefff6d145063536b", size = 2180306, upload-time = "2026-05-06T13:40:10.666Z" }, + { url = "https://files.pythonhosted.org/packages/ae/6c/fc44000918855b42779d007ae63b0532794739027b2f417321cddbc44f6a/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b2f69dec1725e79a012d920df1707de5caf7ed5e08f3be4435e25803efc47458", size = 2190044, upload-time = "2026-05-06T13:40:43.231Z" }, + { url = "https://files.pythonhosted.org/packages/6b/65/d9cadc9f1920d7a127ad2edba16c1db7916e59719285cd6c94600b0080ba/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:8d0820e8192167f80d88d64038e609c31452eeca865b4e1d9950a27a4609b00b", size = 2329133, upload-time = "2026-05-06T13:39:57.365Z" }, + { url = "https://files.pythonhosted.org/packages/d0/cf/c873d91679f3a30bcf5e7ac280ce5573483e72295307685120d0d5ad3416/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fbdb89b3e1c94a30cc5edfce477c6e6a5dc4d8f84665b455c27582f211a1c72c", size = 2374464, upload-time = "2026-05-06T13:38:06.976Z" }, + { url = "https://files.pythonhosted.org/packages/47/bd/6f2fc8188f31bf10590f1e98e7b306336161fac930a8c514cd7bd828c7dc/pydantic_core-2.46.4-cp312-cp312-win32.whl", hash = "sha256:9aa768456404a8bf48a4406685ac2bec8e72b62c69313734fa3b73cf33b3a894", size = 1974823, upload-time = "2026-05-06T13:40:47.985Z" }, + { url = "https://files.pythonhosted.org/packages/40/8c/985c1d41ea1107c2534abd9870e4ed5c8e7669b5c308297835c001e7a1c4/pydantic_core-2.46.4-cp312-cp312-win_amd64.whl", hash = "sha256:e9c26f834c65f5752f3f06cb08cb86a913ceb7274d0db6e267808a708b46bc89", size = 2072919, upload-time = "2026-05-06T13:39:21.153Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ba/f463d006e0c47373ca7ec5e1a261c59dc01ef4d62b2657af925fb0deee3a/pydantic_core-2.46.4-cp312-cp312-win_arm64.whl", hash = "sha256:4fc73cb559bdb54b1134a706a2802a4cddd27a0633f5abb7e53056268751ac6a", size = 2027604, upload-time = "2026-05-06T13:39:03.753Z" }, + { url = "https://files.pythonhosted.org/packages/9d/1d/8987ad40f65ae1432753072f214fb5c74fe47ffbd0698bb9cbbb585664f8/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:1d8ba486450b14f3b1d63bc521d410ec7565e52f887b9fb671791886436a42f7", size = 2095527, upload-time = "2026-05-06T13:39:52.283Z" }, + { url = "https://files.pythonhosted.org/packages/64/d3/84c282a7eee1d3ac4c0377546ef5a1ea436ce26840d9ac3b7ed54a377507/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:3009f12e4e90b7f88b4f9adb1b0c4a3d58fe7820f3238c190047209d148026df", size = 1936024, upload-time = "2026-05-06T13:40:15.671Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ca/eac61596cdeb4d7e174d3dc0bd8a6238f14f75f97a24e7b7db4c7e7340a0/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad785e92e6dc634c21555edc8bd6b64957ab844541bcb96a1366c202951ae526", size = 1990696, upload-time = "2026-05-06T13:38:34.717Z" }, + { url = "https://files.pythonhosted.org/packages/fa/c3/7c8b240552251faf6b3a957db200fcfbbcec36763c050428b601e0c9b83b/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00c603d540afdd6b80eb39f078f33ebd46211f02f33e34a32d9f053bba711de0", size = 2147590, upload-time = "2026-05-06T13:39:29.883Z" }, +] + +[[package]] +name = "pydantic-settings" +version = "2.14.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5c/b5/8f48e906c3e0205276e8bd8cb7512217a87b2685304d64be27cad5b3019f/pydantic_settings-2.14.2.tar.gz", hash = "sha256:c19dd64b19097f1de80184f0cc7b0272a13ae6e170cbf240a3e27e381ed14a5f", size = 237700, upload-time = "2026-06-19T13:44:56.324Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/c1/6e422f34e569cf8e18df68d1939c81c099d2b61e4f7d9621c8a77560799c/pydantic_settings-2.14.2-py3-none-any.whl", hash = "sha256:a20c97b37910b6550d5ea50fbcc2d4187defe58cd57070b73863d069419c9440", size = 61715, upload-time = "2026-06-19T13:44:55.02Z" }, +] + +[[package]] +name = "pygments" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, +] + +[[package]] +name = "pyjwt" +version = "2.13.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/81/58d0ac84e1ef3a3843791d6954d94c0b33d526c75eeb1efbce9d0a4c4077/pyjwt-2.13.0.tar.gz", hash = "sha256:41571c89ca91598c79e8ef18a2d07367d4810fbbd6f637794879baf1b7703423", size = 107515, upload-time = "2026-05-21T19:54:36.618Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl", hash = "sha256:66adcc2aff09b3f1bbd95fc1e1577df8ac8723c978552fd43304c8a290ac5728", size = 31274, upload-time = "2026-05-21T19:54:35.362Z" }, +] + +[package.optional-dependencies] +crypto = [ + { name = "cryptography" }, +] + +[[package]] +name = "pyqwest" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cd/25/305acffe35817ac5dd3659f06bf5c7522cf2d6b1cbfb6e71dfd4e7cf28b0/pyqwest-0.8.0.tar.gz", hash = "sha256:138a6a01f5e3bdd92abed412f35bf122b5a7c41cadaffe9c8b3ba0dc2dc5d822", size = 469648, upload-time = "2026-07-31T03:33:42.436Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/38/76280a079b0f84dcc05c14eba16b6cd39bef9e8aa0a51e916abf71fea637/pyqwest-0.8.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:2976d8fc93b7b4fdb9bfc7ad231e6584d81b9777ad88c8256e02cfa8b690364d", size = 5216354, upload-time = "2026-07-31T03:32:16.344Z" }, + { url = "https://files.pythonhosted.org/packages/fd/0c/afde50b6814e6c053237fb6182f3ffcbe6562fdbfd0c44b6b6589cb37ea7/pyqwest-0.8.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:afe8a86b28ef637b85d2239758f91ef3acdb01bd569fb8abcb4ec70b368fd2d7", size = 5095245, upload-time = "2026-07-31T03:32:18.994Z" }, + { url = "https://files.pythonhosted.org/packages/d9/18/0b0d177754b337afaf9b7d7b0de476ae250bab3bbf105568211fa83da2d6/pyqwest-0.8.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8d948f99dc80e1d4879bbfb4ff073e1d7566dc307d483f6857907b9b634631d", size = 5614817, upload-time = "2026-07-31T03:32:21.005Z" }, + { url = "https://files.pythonhosted.org/packages/dc/12/d5b2e201ca3c374174644fbf201329ff6635ebabef0fcc49701f8d168984/pyqwest-0.8.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bcd1edaa837e136af6982c31c17100a16b6e4918e7237a34229928754edae35", size = 5557336, upload-time = "2026-07-31T03:32:22.725Z" }, + { url = "https://files.pythonhosted.org/packages/d8/36/d5ba098c323d7f5eb9cb9ebf075060d14c3364bf176d9815655065462bc7/pyqwest-0.8.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1c25504a5fe4d72f43b17253c9e1dc4cda426e9fa0a72474c4555455f63706c1", size = 5775102, upload-time = "2026-07-31T03:32:24.766Z" }, + { url = "https://files.pythonhosted.org/packages/1c/e5/1b1bae527e4de93b9eddbf15a78f1ce5198aece5c169478e385364e0f1f1/pyqwest-0.8.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:513fe7649d727cccb5d6e04999e91fed5f61f5e20a8556a2f96d3d1aeea02001", size = 5963251, upload-time = "2026-07-31T03:32:26.792Z" }, + { url = "https://files.pythonhosted.org/packages/44/14/a9d883fc59df1f34fe42764277ca26de11d74dd3aa3d9f9f4a35d7414f37/pyqwest-0.8.0-cp310-abi3-win_amd64.whl", hash = "sha256:7896646bd426db0cbd7a5d4ebd0dacd59f1a2c3cdc12fb2667234e9504e33b03", size = 4834356, upload-time = "2026-07-31T03:32:28.921Z" }, + { url = "https://files.pythonhosted.org/packages/2e/49/c0640e19718c4533590bcaba647ad3145f793c66c125cb62c399e580b1a6/pyqwest-0.8.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c4970ad95d4d51aa07980687d07e1f4003b68bc1fa1e46c9202f1b008c95662e", size = 5232611, upload-time = "2026-07-31T03:32:30.778Z" }, + { url = "https://files.pythonhosted.org/packages/50/85/25c440e1dc31320afa9de8a3ab43b0bc6f5ef5090e43fac350b5de4db623/pyqwest-0.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:63f341cf695b9c8b9b184a0f1c67f6e578b833502f1f21a9359f031b5b77a627", size = 5089482, upload-time = "2026-07-31T03:32:32.817Z" }, + { url = "https://files.pythonhosted.org/packages/5b/7c/a5c49001dc0685043512c5497a7820fe091d765f93a730ace81708ed8f5e/pyqwest-0.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed43c61eebe85aa078ff922378aac9904c9d0be06c99da5826c865c28f8468dc", size = 5618803, upload-time = "2026-07-31T03:32:34.801Z" }, + { url = "https://files.pythonhosted.org/packages/39/af/6835aaeb451f629886bae0b924a864b73b906c84944be37fea43298c163a/pyqwest-0.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7988aeb1dce1ee0d3dbcf9d6c8d3a2a821d9c56402c95c057567363ed01116c0", size = 5556779, upload-time = "2026-07-31T03:32:37.044Z" }, + { url = "https://files.pythonhosted.org/packages/ea/66/2f130d7dc3341112f1a620984d4af17cacf2a17085a1eaa98dfaa35da028/pyqwest-0.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37ebb0bfeaa5a6b5c6ebd1cfdbb3e4d89ac343e46be07a993e8af6473ee82b1b", size = 5779456, upload-time = "2026-07-31T03:32:39.021Z" }, + { url = "https://files.pythonhosted.org/packages/45/4b/14a30458a69e6f1b8e007ff6bd6fdf867cc28de45d046374f45087d31fd8/pyqwest-0.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4471266ff506d02f21350921abd0adbaa08d6b7db6d24408c2ed9635e187e263", size = 5962595, upload-time = "2026-07-31T03:32:41.02Z" }, + { url = "https://files.pythonhosted.org/packages/05/22/db95030afe6c5adc90b2864e194d8074175675a90703282286e3370ecd53/pyqwest-0.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:5b605cb927b5bbd0b1247a5439d90068fee84802003bd6609c48e985aeb15570", size = 4824467, upload-time = "2026-07-31T03:32:42.733Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "python-dotenv" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, +] + +[[package]] +name = "python-multipart" +version = "0.0.32" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/42/55c32bb9b12693c092ad250a0e82edb5b31ddeda6eb772de5f308b3804ad/python_multipart-0.0.32.tar.gz", hash = "sha256:be54b7f3fa167bb83e4fcd936b887b708f4e57fe75911c02aebf53efaf8d938e", size = 46881, upload-time = "2026-06-04T16:18:58.647Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl", hash = "sha256:ff6d3f776f16878c894e52e107296ffc890e913c611b1a4ec6c44e2821fe2e23", size = 30042, upload-time = "2026-06-04T16:18:57.319Z" }, +] + +[[package]] +name = "pywin32" +version = "312" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/ff/32aa7d2ed0ab12b323aaa64f9b75e6ad4f8fd09f9ccfc28c79414d46838d/pywin32-312-cp312-cp312-win32.whl", hash = "sha256:dab4f65ac9c4e48400a2a0530c46c3c579cd5905ecd11b80692373915269208b", size = 6371877, upload-time = "2026-06-04T07:49:28.836Z" }, + { url = "https://files.pythonhosted.org/packages/03/d9/77040d3b43df3f3be32ea289433d660d2727f5ba327bc73be835127d9d60/pywin32-312-cp312-cp312-win_amd64.whl", hash = "sha256:b457f6d628a47e8a7346ce22acb7e1a46a4a78b52e1d17e1af56871bd19a93bc", size = 6914841, upload-time = "2026-06-04T07:49:31.85Z" }, + { url = "https://files.pythonhosted.org/packages/e3/cc/7b1ec671775756020a0ee7f4feeaf3c568f0ab86bd3900088cf986937a92/pywin32-312-cp312-cp312-win_arm64.whl", hash = "sha256:6017c58e12f6809fbb0555b75df144c2922a9ffd18e4b9b5afa863b6c1a9d950", size = 6727901, upload-time = "2026-06-04T07:49:34.244Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, +] + +[[package]] +name = "pyzmq" +version = "27.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "implementation_name == 'pypy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750, upload-time = "2025-09-08T23:10:18.157Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279, upload-time = "2025-09-08T23:08:03.807Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645, upload-time = "2025-09-08T23:08:05.301Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574, upload-time = "2025-09-08T23:08:06.828Z" }, + { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995, upload-time = "2025-09-08T23:08:08.396Z" }, + { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070, upload-time = "2025-09-08T23:08:09.989Z" }, + { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121, upload-time = "2025-09-08T23:08:11.907Z" }, + { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550, upload-time = "2025-09-08T23:08:13.513Z" }, + { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184, upload-time = "2025-09-08T23:08:15.163Z" }, + { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480, upload-time = "2025-09-08T23:08:17.192Z" }, + { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993, upload-time = "2025-09-08T23:08:18.926Z" }, +] + +[[package]] +name = "referencing" +version = "0.37.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, +] + +[[package]] +name = "regex" +version = "2026.7.19" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/98/04b13f1ddfb63158025291c02e03eb42fbb7acb51d091d541050eb4e35e8/regex-2026.7.19.tar.gz", hash = "sha256:7e77b324909c1617cbb4c668677e2c6ae13f44d7c1de0d4f15f2e3c10f3315b5", size = 416440, upload-time = "2026-07-19T00:19:48.923Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/b9/d11d7e501ac8fd7d617684423ebb9561e0b998481c1e4cbc0cb212c5d74a/regex-2026.7.19-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2cc3460cedf7579948486eab03bc9ad7089df4d7281c0f47f4afe03e8d13f02d", size = 496778, upload-time = "2026-07-19T00:17:05.677Z" }, + { url = "https://files.pythonhosted.org/packages/3f/a9/a5ab6f312f24318019170dc485d5421fe4f89e43a98640da50d95a8a7041/regex-2026.7.19-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0e9554c8785eac5cffe6300f69a91f58ba72bc88a5f8d661235ad7c6aa5b8ccd", size = 297122, upload-time = "2026-07-19T00:17:07.59Z" }, + { url = "https://files.pythonhosted.org/packages/b3/63/4cab4d7f2d384a144d420b763d97674cb70619c878ea6fcd7640d0e62143/regex-2026.7.19-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d7da47a0f248977f08e2cb659ff3c17ddc13a4d39b3a7baa0a81bf5b415430f6", size = 292009, upload-time = "2026-07-19T00:17:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/22/85/102a81b218298957d4ea7d2f084fae537a71add9d6ff93c8e67284c5f45e/regex-2026.7.19-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:93db40c8de0815baab96a06e08a984bac71f989d13bab789e382158c5d426797", size = 796708, upload-time = "2026-07-19T00:17:11.542Z" }, + { url = "https://files.pythonhosted.org/packages/78/b5/dc136af5629938a037cd2b304c12240e132ec92f38be8ff9cc89af2a1f2d/regex-2026.7.19-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:66bd62c59a5427746e8c44becae1d9b99d22fb13f30f492083dfb9ad7c45cc18", size = 865651, upload-time = "2026-07-19T00:17:13.312Z" }, + { url = "https://files.pythonhosted.org/packages/e0/75/67402ae3cd9c8c988a4c805d15ee3eef015e7ca4cb112cf3e640fc1f4153/regex-2026.7.19-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1649eb39fcc9ea80c4d2f110fde2b8ab2aef3877b98f02ab9b14e961f418c511", size = 911756, upload-time = "2026-07-19T00:17:15.015Z" }, + { url = "https://files.pythonhosted.org/packages/2a/8e/096d00c7c480ef2ff4265349b14e2261d4ab787ba1f74e2e80d1c58079c3/regex-2026.7.19-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9dce8ec9695f531a1b8a6f314fd4b393adcccf2ea861db480cdf97a301d01a68", size = 801798, upload-time = "2026-07-19T00:17:17.208Z" }, + { url = "https://files.pythonhosted.org/packages/f0/41/e7ecac6edb5722417f85cc67eaf386322fbe8acf6918ec2fdc37c20dd9d0/regex-2026.7.19-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3080a7fd38ef049bd489e01c970c97dd84ff446a885b0f1f6b26d9b1ad13ce11", size = 776933, upload-time = "2026-07-19T00:17:19.347Z" }, + { url = "https://files.pythonhosted.org/packages/6f/69/03c9b3f058d66403e0ca2c938696e81d51cd4c6d47ec5265f02f96948d9a/regex-2026.7.19-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1d793a7988e04fcb1e2e135567443d82173225d657419ec09414a9b5a145b986", size = 784338, upload-time = "2026-07-19T00:17:21.057Z" }, + { url = "https://files.pythonhosted.org/packages/f6/f7/b38ab3d43f284afbb618fcd15d0e77eb786ae461ce1f6bc7494619ddc0f2/regex-2026.7.19-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e8b0abe7d870f53ca5143895fef7d1041a0c831a140d3dc2c760dd7ba25d4a8b", size = 860452, upload-time = "2026-07-19T00:17:23.119Z" }, + { url = "https://files.pythonhosted.org/packages/15/5c/ff60ef0571121714f3cf9920bc183071e384a10b556d042e0fdb06cc07a5/regex-2026.7.19-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:4e5413bd5f13d3a4e3539ca98f70f75e7fca92518dd7f117f030ebedd10b60cb", size = 765958, upload-time = "2026-07-19T00:17:24.81Z" }, + { url = "https://files.pythonhosted.org/packages/aa/0f/bd34021162c0ab47f9a315bd56cd5642e920c8e5668a75ef6c6a6fca590d/regex-2026.7.19-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:73b133a9e6fb512858e7f065e96f1180aa46646bc74a83aea62f1d314f3dd035", size = 851765, upload-time = "2026-07-19T00:17:26.993Z" }, + { url = "https://files.pythonhosted.org/packages/2a/20/a2ca43edade0595cccfdc98636739f536d9e26898e7dbddc2b9e98898953/regex-2026.7.19-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dbe6493fbd27321b1d1f2dd4f5c7e5bd4d8b1d7cab7f32fd67db3d0b2ed8248a", size = 789714, upload-time = "2026-07-19T00:17:28.699Z" }, + { url = "https://files.pythonhosted.org/packages/5d/47/e02db4015d424fc83c00ea0ac8c5e5ec14397943de9abf909d5ce3a25931/regex-2026.7.19-cp312-cp312-win32.whl", hash = "sha256:ddd67571c10869f65a5d7dde536d1e066e306cc90de57d7de4d5f34802428bb5", size = 267157, upload-time = "2026-07-19T00:17:31.051Z" }, + { url = "https://files.pythonhosted.org/packages/08/8e/c780c131f79b42ed22d1bd7da4096c2c35f813e835acd02ef0f018bd892c/regex-2026.7.19-cp312-cp312-win_amd64.whl", hash = "sha256:e30d40268a28d54ce0437031750497004c22602b8e3ab891f759b795a003b312", size = 277777, upload-time = "2026-07-19T00:17:32.848Z" }, + { url = "https://files.pythonhosted.org/packages/3e/4c/e4d7e086449bdf379d89774bf1f89dc4a41943f3c5a6125a03905b34b5fb/regex-2026.7.19-cp312-cp312-win_arm64.whl", hash = "sha256:de9208bb427130c82a5dbfd104f92c8876fc9559278c880b3002755bbbe9c83d", size = 277136, upload-time = "2026-07-19T00:17:34.803Z" }, +] + +[[package]] +name = "renderers" +version = "0.1.9.dev10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "numpy" }, + { name = "openai" }, + { name = "openai-harmony" }, + { name = "prime-pydantic-config" }, + { name = "tiktoken" }, + { name = "transformers" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/20/9e916532c3f5133514fc6909ff1efd686c6c4bf0e99eab2dc5a10ea87eda/renderers-0.1.9.dev10.tar.gz", hash = "sha256:35c2dac8704661a0b1127cec34a6577b795579d4e8f060ce6563076c24fac18a", size = 349159, upload-time = "2026-07-30T19:49:07.731Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/67/b4ea55e275aae6cb01ef0ed343c9874511de0d8e0173366a0ad7d7f7039f/renderers-0.1.9.dev10-py3-none-any.whl", hash = "sha256:36c4ee952239a71c41fbb3059ee7b1f48e153627937a59d8cb01f6f21695e7ee", size = 192989, upload-time = "2026-07-30T19:49:06.013Z" }, +] + +[[package]] +name = "requests" +version = "2.34.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" }, +] + +[[package]] +name = "rich" +version = "15.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" }, +] + +[[package]] +name = "rpds-py" +version = "2026.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/2a/9618a122aeb2a169a28b03889a2995fe297588964333d4a7d67bdf46e147/rpds_py-2026.6.3.tar.gz", hash = "sha256:1cebd1337c242e4ec2293e541f712b2da849b29f48f0c293684b71c0632625d4", size = 64051, upload-time = "2026-06-30T07:17:53.009Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/be/2e8974163072e7bab7df1a5acd54c4498e75e35d6d18b864d3a9d5dadc92/rpds_py-2026.6.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a0811d33247c3d6128a3001d763f2aa056bb3425204335400ac54f89eec3a0d0", size = 343691, upload-time = "2026-06-30T07:15:14.96Z" }, + { url = "https://files.pythonhosted.org/packages/a4/73/319dfa745dd668efe89309141ded489126461fcecd2b8f3a3cda185129b6/rpds_py-2026.6.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:538949e262e46caa31ac01bdb3c1e8f642622922cacbabbae6a8445d9dc33eaf", size = 338542, upload-time = "2026-06-30T07:15:16.267Z" }, + { url = "https://files.pythonhosted.org/packages/21/63/4239893be1c4d09b709b1a8f6be4188f0870084ff547f46606b8a75f1b03/rpds_py-2026.6.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55927d532399c2c646100ff7feb48eaa940ad70f42cd68e1328f3ded9f81ca24", size = 368180, upload-time = "2026-06-30T07:15:17.62Z" }, + { url = "https://files.pythonhosted.org/packages/1c/ca/9c5de382225234ceb37b1844ebdb140db12b2a278bb9efe2fcd19f6c82ce/rpds_py-2026.6.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f56f1695bc5c0871cbc33dc0130fcf503aab0c57dcc5a6700a4f49eba4f2652e", size = 375067, upload-time = "2026-06-30T07:15:18.952Z" }, + { url = "https://files.pythonhosted.org/packages/87/dc/863f69d1bf04ade34b7fe0d59b9fdf6f0135fe2d7cbca74f1d665589559d/rpds_py-2026.6.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:270b293dae9058fc9fcedab50f13cebf46fb8ed1d1d54e0521a9da5d6b211975", size = 490509, upload-time = "2026-06-30T07:15:20.434Z" }, + { url = "https://files.pythonhosted.org/packages/ce/ef/eac16a12048b45ec7c7fa94f2be3438a5f26bf9cc8580b18a1cfd609b7f6/rpds_py-2026.6.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:127565fead0a10943b282957bd5447804ff3160ad79f2ad2635e6d249e380680", size = 382754, upload-time = "2026-06-30T07:15:21.831Z" }, + { url = "https://files.pythonhosted.org/packages/04/8f/d2f3f532616be4d06c316ef119683e832bd3d41e112bf3a88f4151c95b17/rpds_py-2026.6.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecabd69db66de867690f9797f2f8fa27ba501bbc24540cbdbdc649cd15888ba6", size = 366189, upload-time = "2026-06-30T07:15:23.371Z" }, + { url = "https://files.pythonhosted.org/packages/e3/29/41a7b0e98a4b44cd676ab7598419623373eb43b20be68c084935c1a8cf88/rpds_py-2026.6.3-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:58eadac9cd119677b60e1cf8ac4052f35949d71b8a9e5556efccbe82533cf22a", size = 377750, upload-time = "2026-06-30T07:15:24.659Z" }, + { url = "https://files.pythonhosted.org/packages/2e/05/ecda0bec46f9a1565090bcdc941d023f6a25aff85fda28f89f8d19878152/rpds_py-2026.6.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7491ee23305ac3eb59e492b6945881f5cd77a6f731061a3f25b77fd40f9e99a4", size = 395576, upload-time = "2026-06-30T07:15:25.987Z" }, + { url = "https://files.pythonhosted.org/packages/68/a8/6ed52f03ee6cb854ce78785cc9a9a672eb880e83fd7224d471f667d151f1/rpds_py-2026.6.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2c99f7e8ccb3dd6e3e4bfeac657a7b208c9bac8075f4b078c02d7404c34107fa", size = 543807, upload-time = "2026-06-30T07:15:27.356Z" }, + { url = "https://files.pythonhosted.org/packages/8f/d6/156c0d3eea27ba09b92562ba2364ba124c0a061b199e17eac637cd25a5e2/rpds_py-2026.6.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:62698275682bf121181861295c9181e789030a2d516071f5b8f3c23c170cd0fc", size = 611187, upload-time = "2026-06-30T07:15:28.931Z" }, + { url = "https://files.pythonhosted.org/packages/f1/31/774212ed989c62f7f310220089f9b0a3fb8f40f5443d1727abd5d9f52bc9/rpds_py-2026.6.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a214c993455f99a89aaeadc9b21241900037adc9d97203e374d75513c5911822", size = 573030, upload-time = "2026-06-30T07:15:30.553Z" }, + { url = "https://files.pythonhosted.org/packages/c9/50/22f73127a41f1ce4f87fe39aadfb9a126345801c274aa93ae88456249327/rpds_py-2026.6.3-cp312-cp312-win32.whl", hash = "sha256:501f9f04a588d6a09179368c57071301445191767c64e4b52a6aa9871f1ef5ed", size = 202185, upload-time = "2026-06-30T07:15:32.027Z" }, + { url = "https://files.pythonhosted.org/packages/04/3a/f0ee4d4dde9d3b69dedf1b5f74e7a40017046d55052d173e418c6a94f960/rpds_py-2026.6.3-cp312-cp312-win_amd64.whl", hash = "sha256:2c958bf94822e9290a40aaf2a822d4bc5c88099093e3948ad6c571eca9272e5f", size = 220394, upload-time = "2026-06-30T07:15:33.359Z" }, + { url = "https://files.pythonhosted.org/packages/f3/83/3382fe37f809b59f02aac04dbc4e765b480b46ee0227ed516e3bdc4d3dfc/rpds_py-2026.6.3-cp312-cp312-win_arm64.whl", hash = "sha256:22bffe6042b9bcb0822bcd1955ec00e245daf17b4344e4ed8e9551b976b63e96", size = 215753, upload-time = "2026-06-30T07:15:34.778Z" }, +] + +[[package]] +name = "safetensors" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/45/06/f955dbbb1859e3bd23c8ac6141af5106e7ad5fedec4a3a6e3d60f94b7001/safetensors-0.8.0.tar.gz", hash = "sha256:fabaf3e0f18a6618d9b36560682562157f77c2b71fcffc7b432be2baed9d753d", size = 325846, upload-time = "2026-06-09T07:52:25.563Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/a0/f718cda65b05407d228f97602cf60dca269c979867aa5beb25410de26cd3/safetensors-0.8.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c554f85858e05226d3c2828e32395e677434685d6d94594a41643361c5e837f0", size = 473568, upload-time = "2026-06-09T07:52:18.829Z" }, + { url = "https://files.pythonhosted.org/packages/f5/b1/fa7c600e7dceae12e9606c7578cbc9ff1e1ed55844883ee5c92205e86226/safetensors-0.8.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:c80201d22cbf405b80647a60ada77bba06c8fba2da2743ba1e89cdcc39a81f25", size = 484562, upload-time = "2026-06-09T07:52:17.518Z" }, + { url = "https://files.pythonhosted.org/packages/09/7d/65a7de0af421317bb36a067241e4235fff194eed60b961ed6d3f59a3fc60/safetensors-0.8.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a46e5ff292c356d6991e60942ba7f79817682d3a2cef0702136448cb9c4d235", size = 502844, upload-time = "2026-06-09T07:52:07.624Z" }, + { url = "https://files.pythonhosted.org/packages/91/4f/3175c9d75634e0e0dda0082794193521035edd7c70a6f212bf33ca06ddf4/safetensors-0.8.0-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4124502b78f03534117c848f87a39b8f31e577b15eff423bf8bfb95f2a8c30d0", size = 511823, upload-time = "2026-06-09T07:52:09.565Z" }, + { url = "https://files.pythonhosted.org/packages/20/87/846c289e7aa2299eff406335717cf43ce8777194ece8aad75772e0411615/safetensors-0.8.0-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7bc0a787ba8a35be368ee3574edfa2b1ad389eebd0a72e482ae275490e3f6c98", size = 633461, upload-time = "2026-06-09T07:52:11.128Z" }, + { url = "https://files.pythonhosted.org/packages/76/22/8d64d9df2c45d5ded401df889d0ad90882804ca172d79ec4f0df8f727fe0/safetensors-0.8.0-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040070828e36dc8e122178bbbd5830ff9e97920affb84cbe0f46442497bed358", size = 545148, upload-time = "2026-06-09T07:52:13.603Z" }, + { url = "https://files.pythonhosted.org/packages/28/50/f203ff3a3ddfe19308efc83c5a3a29ed02bf786732ec35e68bf9162f3365/safetensors-0.8.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd6f3f93c9a0a7cc2788ee63fb763353d4bd2e89b0751bc78fcf7dda00bea774", size = 516040, upload-time = "2026-06-09T07:52:16.29Z" }, + { url = "https://files.pythonhosted.org/packages/46/fb/cdaed17ceb2948784fd9c36b6fd3e951b608547cea81a48e8ee6f8cfdfcb/safetensors-0.8.0-cp310-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:fcdd41ec4628fee5799f807c73c353629130fbd942aa23d83c623dd6c9d52d78", size = 513832, upload-time = "2026-06-09T07:52:12.37Z" }, + { url = "https://files.pythonhosted.org/packages/0d/49/1e15de264dcc3b77943d2d0c56a95809956883b1c2d6d585c792523f180b/safetensors-0.8.0-cp310-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8e9f537aa183a38ace122d27303dcd986b26bd2a7591f9181d7f0c396f4677ca", size = 559930, upload-time = "2026-06-09T07:52:14.743Z" }, + { url = "https://files.pythonhosted.org/packages/2a/43/bf38443278eab4b1be1fce2931e2b012ad9cb7df52ada751d0aab8f7659a/safetensors-0.8.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:87eec7ffed2b809f05a398a8becb7d013f19f7837cd15d9748580d6cf30dbaf4", size = 678670, upload-time = "2026-06-09T07:52:20.032Z" }, + { url = "https://files.pythonhosted.org/packages/72/e3/68cd3fa5b48488e84add63e04cb12f3bc28ae4638c06d4508c6e88823d0e/safetensors-0.8.0-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:4a95ae2b05d7726d751da4ebf626a2ca782b706e101bd894c95bc2450b1cffcc", size = 786679, upload-time = "2026-06-09T07:52:21.322Z" }, + { url = "https://files.pythonhosted.org/packages/29/4b/1c19c509d56e01f4fbb3d0a2e597450f6cc04d1d56cf52defb0a62dfd715/safetensors-0.8.0-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:3ae091f16662658bdc019a4ff6cb4c085bb7d725eb5978b183ffd265863b6d2d", size = 765683, upload-time = "2026-06-09T07:52:22.594Z" }, + { url = "https://files.pythonhosted.org/packages/27/43/41c1621732edd934d868a00d1b891584c892a7b62a9aab82ea5a0a5623ee/safetensors-0.8.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8e080062fcde23be189565e1c3305d16751a218ecf9412c8601e64204eb6f846", size = 722361, upload-time = "2026-06-09T07:52:23.924Z" }, + { url = "https://files.pythonhosted.org/packages/8e/3f/73ccf82579412b4a71c4ca673f10b5f1f888d7cf5af7fe24f27d30307be4/safetensors-0.8.0-cp310-abi3-win32.whl", hash = "sha256:2ddf52eac562eda224f99acfa7889d02968c1fd59a5b011ae7d8137c37e9c02d", size = 342401, upload-time = "2026-06-09T07:52:28.895Z" }, + { url = "https://files.pythonhosted.org/packages/1b/6d/3fba214c1e5e0f69991677ec3bc17023f0421776975e1de0c682dca475e2/safetensors-0.8.0-cp310-abi3-win_amd64.whl", hash = "sha256:096ec1a98435df7beb08853bb5aa9081a84f23d0adc67ed1a0a10550f608373f", size = 355540, upload-time = "2026-06-09T07:52:27.832Z" }, + { url = "https://files.pythonhosted.org/packages/8d/fc/7eedc3510d97878876e32774eebbeb61c43f148a96e915c84229a3e967aa/safetensors-0.8.0-cp310-abi3-win_arm64.whl", hash = "sha256:f7838e5135a406ad3e02efdcb8cf2e5397d368b0154537c4fec682dbc544d452", size = 340500, upload-time = "2026-06-09T07:52:26.745Z" }, +] + +[[package]] +name = "setproctitle" +version = "1.3.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8d/48/49393a96a2eef1ab418b17475fb92b8fcfad83d099e678751b05472e69de/setproctitle-1.3.7.tar.gz", hash = "sha256:bc2bc917691c1537d5b9bca1468437176809c7e11e5694ca79a9ca12345dcb9e", size = 27002, upload-time = "2025-09-05T12:51:25.278Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/f0/2dc88e842077719d7384d86cc47403e5102810492b33680e7dadcee64cd8/setproctitle-1.3.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2dc99aec591ab6126e636b11035a70991bc1ab7a261da428491a40b84376654e", size = 18049, upload-time = "2025-09-05T12:49:36.241Z" }, + { url = "https://files.pythonhosted.org/packages/f0/b4/50940504466689cda65680c9e9a1e518e5750c10490639fa687489ac7013/setproctitle-1.3.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cdd8aa571b7aa39840fdbea620e308a19691ff595c3a10231e9ee830339dd798", size = 13079, upload-time = "2025-09-05T12:49:38.088Z" }, + { url = "https://files.pythonhosted.org/packages/d0/99/71630546b9395b095f4082be41165d1078204d1696c2d9baade3de3202d0/setproctitle-1.3.7-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2906b6c7959cdb75f46159bf0acd8cc9906cf1361c9e1ded0d065fe8f9039629", size = 32932, upload-time = "2025-09-05T12:49:39.271Z" }, + { url = "https://files.pythonhosted.org/packages/50/22/cee06af4ffcfb0e8aba047bd44f5262e644199ae7527ae2c1f672b86495c/setproctitle-1.3.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6915964a6dda07920a1159321dcd6d94fc7fc526f815ca08a8063aeca3c204f1", size = 33736, upload-time = "2025-09-05T12:49:40.565Z" }, + { url = "https://files.pythonhosted.org/packages/5c/00/a5949a8bb06ef5e7df214fc393bb2fb6aedf0479b17214e57750dfdd0f24/setproctitle-1.3.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cff72899861c765bd4021d1ff1c68d60edc129711a2fdba77f9cb69ef726a8b6", size = 35605, upload-time = "2025-09-05T12:49:42.362Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3a/50caca532a9343828e3bf5778c7a84d6c737a249b1796d50dd680290594d/setproctitle-1.3.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b7cb05bd446687ff816a3aaaf831047fc4c364feff7ada94a66024f1367b448c", size = 33143, upload-time = "2025-09-05T12:49:43.515Z" }, + { url = "https://files.pythonhosted.org/packages/ca/14/b843a251296ce55e2e17c017d6b9f11ce0d3d070e9265de4ecad948b913d/setproctitle-1.3.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3a57b9a00de8cae7e2a1f7b9f0c2ac7b69372159e16a7708aa2f38f9e5cc987a", size = 34434, upload-time = "2025-09-05T12:49:45.31Z" }, + { url = "https://files.pythonhosted.org/packages/c8/b7/06145c238c0a6d2c4bc881f8be230bb9f36d2bf51aff7bddcb796d5eed67/setproctitle-1.3.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d8828b356114f6b308b04afe398ed93803d7fca4a955dd3abe84430e28d33739", size = 32795, upload-time = "2025-09-05T12:49:46.419Z" }, + { url = "https://files.pythonhosted.org/packages/ef/dc/ef76a81fac9bf27b84ed23df19c1f67391a753eed6e3c2254ebcb5133f56/setproctitle-1.3.7-cp312-cp312-win32.whl", hash = "sha256:b0304f905efc845829ac2bc791ddebb976db2885f6171f4a3de678d7ee3f7c9f", size = 12552, upload-time = "2025-09-05T12:49:47.635Z" }, + { url = "https://files.pythonhosted.org/packages/e2/5b/a9fe517912cd6e28cf43a212b80cb679ff179a91b623138a99796d7d18a0/setproctitle-1.3.7-cp312-cp312-win_amd64.whl", hash = "sha256:9888ceb4faea3116cf02a920ff00bfbc8cc899743e4b4ac914b03625bdc3c300", size = 13247, upload-time = "2025-09-05T12:49:49.16Z" }, +] + +[[package]] +name = "shellingham" +version = "1.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "sse-starlette" +version = "3.4.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "starlette" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6c/10/a34c656829ffc1c4b22ef36d70d9ebb6b99c020e2aeb17cee5485099f028/sse_starlette-3.4.6.tar.gz", hash = "sha256:725f8a1bd6d26ae1b2c9610c0ef5065dfdd496f3988d28adcf8c4b49dc25c627", size = 32542, upload-time = "2026-07-20T14:16:32.201Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/36/e10c1d1b7ca881d2625db2ec28508578499187bb1c389952c398474e1834/sse_starlette-3.4.6-py3-none-any.whl", hash = "sha256:56217ab4c9a9f9c5db7b21e08732d3e7c2b807f45231ad23de0551a24c4a41f6", size = 16516, upload-time = "2026-07-20T14:16:30.978Z" }, +] + +[[package]] +name = "starlette" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/e3/7c1dc7381d9f8ab7d854328ebfa884e62cb3f3d8549ddfd37c7814f42afa/starlette-1.3.1.tar.gz", hash = "sha256:05d0213193f2fbaae60e2ecb593b4add4262ad4e46536b54abe36f11a71724e0", size = 2703240, upload-time = "2026-06-12T09:23:11.602Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl", hash = "sha256:c7372aae11c3c3f26a42df7bd626cec2f47d03483d261d369516a615a53714c6", size = 73632, upload-time = "2026-06-12T09:23:10.017Z" }, +] + +[[package]] +name = "sympy" +version = "1.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mpmath" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, +] + +[[package]] +name = "tenacity" +version = "9.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/47/c6/ee486fd809e357697ee8a44d3d69222b344920433d3b6666ccd9b374630c/tenacity-9.1.4.tar.gz", hash = "sha256:adb31d4c263f2bd041081ab33b498309a57c77f9acf2db65aadf0898179cf93a", size = 49413, upload-time = "2026-02-07T10:45:33.841Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl", hash = "sha256:6095a360c919085f28c6527de529e76a06ad89b23659fa881ae0649b867a9d55", size = 28926, upload-time = "2026-02-07T10:45:32.24Z" }, +] + +[[package]] +name = "tiktoken" +version = "0.13.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "regex" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e4/e5/5f3cb2159769d0f4324c0e9e87f9de3c4b1cd45848a96b2eb3566ad5ca77/tiktoken-0.13.0.tar.gz", hash = "sha256:c9435714c3a84c2319499de9a300c0e604449dd0799ff246458b3bb6a7f433c1", size = 38986, upload-time = "2026-05-15T04:51:27.153Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/8e/144bde4e01df66b34bb865557c7cd754ed08b036217ebd79c9db5e9048a9/tiktoken-0.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:32ac870a806cfb260a02d0cb70426aef02e038297f8ad50df5040bb5af360791", size = 1034888, upload-time = "2026-05-15T04:50:31.579Z" }, + { url = "https://files.pythonhosted.org/packages/36/18/d4ac9d20956cdebca04841316660ed584c2fecdc2b81722a28bc7ad3b1e4/tiktoken-0.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4d9980f11429ed2d737c463bb1fb78cf330caa026adf002f714aced7849a687b", size = 982970, upload-time = "2026-05-15T04:50:32.961Z" }, + { url = "https://files.pythonhosted.org/packages/74/ed/6bb8d05b9f731f749fee5c6f5ca63e981143c826a5985877330507bd13b7/tiktoken-0.13.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3f277ebea5edd7b8bf03c6f9431e1d67d517530115572b2dc1d465326e8f88c7", size = 1115741, upload-time = "2026-05-15T04:50:34.475Z" }, + { url = "https://files.pythonhosted.org/packages/34/de/2ca96b07a82d972b74fe4b46de055b79c904e45c7eab699354a0bfa697dc/tiktoken-0.13.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:a116178fa7e1b4065bff05214360373a65cac22f965be7b3f73d00a0dbfe7649", size = 1136523, upload-time = "2026-05-15T04:50:35.782Z" }, + { url = "https://files.pythonhosted.org/packages/ee/dc/9dafec002c2d4424378563cf4cf5c7fb93631d2a55013c8b87554ee4012c/tiktoken-0.13.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2c397ddda233208345b01bd30f2fca79ff730e55731d0108a603f9bc57f6af3b", size = 1181954, upload-time = "2026-05-15T04:50:36.99Z" }, + { url = "https://files.pythonhosted.org/packages/a1/d0/1f8578c45b2f24759b46f0b50d31878c63c73e6bf0f2227e10ec5c5408dc/tiktoken-0.13.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:95097e4f89b06403976e498abf61a0ee73a7497e73fb599cb211d8197a054d91", size = 1240069, upload-time = "2026-05-15T04:50:38.221Z" }, + { url = "https://files.pythonhosted.org/packages/aa/90/28d7f154888610aa9237e541986beb62b479df29d193a5a0617dbb1514d0/tiktoken-0.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:8f2d16e7a7c783ad81f36e457d046d1f1c8af70b22aec8a13238efe531977c41", size = 874748, upload-time = "2026-05-15T04:50:39.587Z" }, +] + +[[package]] +name = "tokenizers" +version = "0.22.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "huggingface-hub" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917", size = 372115, upload-time = "2026-01-05T10:45:15.988Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/97/5dbfabf04c7e348e655e907ed27913e03db0923abb5dfdd120d7b25630e1/tokenizers-0.22.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:544dd704ae7238755d790de45ba8da072e9af3eea688f698b137915ae959281c", size = 3100275, upload-time = "2026-01-05T10:41:02.158Z" }, + { url = "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1e418a55456beedca4621dbab65a318981467a2b188e982a23e117f115ce5001", size = 2981472, upload-time = "2026-01-05T10:41:00.276Z" }, + { url = "https://files.pythonhosted.org/packages/d6/84/7990e799f1309a8b87af6b948f31edaa12a3ed22d11b352eaf4f4b2e5753/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2249487018adec45d6e3554c71d46eb39fa8ea67156c640f7513eb26f318cec7", size = 3290736, upload-time = "2026-01-05T10:40:32.165Z" }, + { url = "https://files.pythonhosted.org/packages/78/59/09d0d9ba94dcd5f4f1368d4858d24546b4bdc0231c2354aa31d6199f0399/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25b85325d0815e86e0bac263506dd114578953b7b53d7de09a6485e4a160a7dd", size = 3168835, upload-time = "2026-01-05T10:40:38.847Z" }, + { url = "https://files.pythonhosted.org/packages/47/50/b3ebb4243e7160bda8d34b731e54dd8ab8b133e50775872e7a434e524c28/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfb88f22a209ff7b40a576d5324bf8286b519d7358663db21d6246fb17eea2d5", size = 3521673, upload-time = "2026-01-05T10:40:56.614Z" }, + { url = "https://files.pythonhosted.org/packages/e0/fa/89f4cb9e08df770b57adb96f8cbb7e22695a4cb6c2bd5f0c4f0ebcf33b66/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c774b1276f71e1ef716e5486f21e76333464f47bece56bbd554485982a9e03e", size = 3724818, upload-time = "2026-01-05T10:40:44.507Z" }, + { url = "https://files.pythonhosted.org/packages/64/04/ca2363f0bfbe3b3d36e95bf67e56a4c88c8e3362b658e616d1ac185d47f2/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df6c4265b289083bf710dff49bc51ef252f9d5be33a45ee2bed151114a56207b", size = 3379195, upload-time = "2026-01-05T10:40:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/2e/76/932be4b50ef6ccedf9d3c6639b056a967a86258c6d9200643f01269211ca/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:369cc9fc8cc10cb24143873a0d95438bb8ee257bb80c71989e3ee290e8d72c67", size = 3274982, upload-time = "2026-01-05T10:40:58.331Z" }, + { url = "https://files.pythonhosted.org/packages/1d/28/5f9f5a4cc211b69e89420980e483831bcc29dade307955cc9dc858a40f01/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:29c30b83d8dcd061078b05ae0cb94d3c710555fbb44861139f9f83dcca3dc3e4", size = 9478245, upload-time = "2026-01-05T10:41:04.053Z" }, + { url = "https://files.pythonhosted.org/packages/6c/fb/66e2da4704d6aadebf8cb39f1d6d1957df667ab24cff2326b77cda0dcb85/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:37ae80a28c1d3265bb1f22464c856bd23c02a05bb211e56d0c5301a435be6c1a", size = 9560069, upload-time = "2026-01-05T10:45:10.673Z" }, + { url = "https://files.pythonhosted.org/packages/16/04/fed398b05caa87ce9b1a1bb5166645e38196081b225059a6edaff6440fac/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:791135ee325f2336f498590eb2f11dc5c295232f288e75c99a36c5dbce63088a", size = 9899263, upload-time = "2026-01-05T10:45:12.559Z" }, + { url = "https://files.pythonhosted.org/packages/05/a1/d62dfe7376beaaf1394917e0f8e93ee5f67fea8fcf4107501db35996586b/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38337540fbbddff8e999d59970f3c6f35a82de10053206a7562f1ea02d046fa5", size = 10033429, upload-time = "2026-01-05T10:45:14.333Z" }, + { url = "https://files.pythonhosted.org/packages/fd/18/a545c4ea42af3df6effd7d13d250ba77a0a86fb20393143bbb9a92e434d4/tokenizers-0.22.2-cp39-abi3-win32.whl", hash = "sha256:a6bf3f88c554a2b653af81f3204491c818ae2ac6fbc09e76ef4773351292bc92", size = 2502363, upload-time = "2026-01-05T10:45:20.593Z" }, + { url = "https://files.pythonhosted.org/packages/65/71/0670843133a43d43070abeb1949abfdef12a86d490bea9cd9e18e37c5ff7/tokenizers-0.22.2-cp39-abi3-win_amd64.whl", hash = "sha256:c9ea31edff2968b44a88f97d784c2f16dc0729b8b143ed004699ebca91f05c48", size = 2747786, upload-time = "2026-01-05T10:45:18.411Z" }, + { url = "https://files.pythonhosted.org/packages/72/f4/0de46cfa12cdcbcd464cc59fde36912af405696f687e53a091fb432f694c/tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc", size = 2612133, upload-time = "2026-01-05T10:45:17.232Z" }, +] + +[[package]] +name = "tomli" +version = "2.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543, upload-time = "2026-03-25T20:22:03.828Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", size = 155924, upload-time = "2026-03-25T20:21:21.626Z" }, + { url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", size = 150018, upload-time = "2026-03-25T20:21:23.002Z" }, + { url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", size = 244948, upload-time = "2026-03-25T20:21:24.04Z" }, + { url = "https://files.pythonhosted.org/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", size = 253341, upload-time = "2026-03-25T20:21:25.177Z" }, + { url = "https://files.pythonhosted.org/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", size = 248159, upload-time = "2026-03-25T20:21:26.364Z" }, + { url = "https://files.pythonhosted.org/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", size = 253290, upload-time = "2026-03-25T20:21:27.46Z" }, + { url = "https://files.pythonhosted.org/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", size = 98141, upload-time = "2026-03-25T20:21:28.492Z" }, + { url = "https://files.pythonhosted.org/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", size = 108847, upload-time = "2026-03-25T20:21:29.386Z" }, + { url = "https://files.pythonhosted.org/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", size = 95088, upload-time = "2026-03-25T20:21:30.677Z" }, + { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" }, +] + +[[package]] +name = "tomli-w" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/19/75/241269d1da26b624c0d5e110e8149093c759b7a286138f4efd61a60e75fe/tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021", size = 7184, upload-time = "2025-01-15T12:07:24.262Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", size = 6675, upload-time = "2025-01-15T12:07:22.074Z" }, +] + +[[package]] +name = "tqdm" +version = "4.70.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/21/3b/6c24bec5be5e743ffd99576daa5cc077722fc7d5bbc00bd133fa0c698dc6/tqdm-4.70.0.tar.gz", hash = "sha256:55b0b0dbd97462d06ebee91e4dac24ed4d4702be82b24f07e6c1d27e08cea220", size = 795438, upload-time = "2026-07-27T11:33:15.271Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl", hash = "sha256:7f585706bfddbdebf89daac705b2dfcc16890130727d3197ca62c732b4310953", size = 80184, upload-time = "2026-07-27T11:33:13.167Z" }, +] + +[[package]] +name = "transformers" +version = "5.14.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "huggingface-hub" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "regex" }, + { name = "safetensors" }, + { name = "tokenizers" }, + { name = "tqdm" }, + { name = "typer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5a/fb/2a2ba88f325e68a921d8b69ff63b477830b2e73ade9a3c8c8cab2f06d741/transformers-5.14.1.tar.gz", hash = "sha256:60d196c27781eacf8637e2b533f517582907ad6f9ae142046d6b69431a5b2173", size = 9295927, upload-time = "2026-07-16T09:41:57.773Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/67/8d85ca2323233ae3c0365a659c4e52ee1f587b440e4bc577e7d8e4416d0f/transformers-5.14.1-py3-none-any.whl", hash = "sha256:9db974c4079ede2d1a3ea7ca5a240df33f2cc26fc2b36ba64c5f2a4f43b6e725", size = 11625234, upload-time = "2026-07-16T09:41:54.143Z" }, +] + +[[package]] +name = "typer" +version = "0.27.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-doc" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "rich" }, + { name = "shellingham" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/40/4a3db7990d1f62a53182aa96eaef57aeb2886a27f90a195bc66713565d31/typer-0.27.1.tar.gz", hash = "sha256:a79bef8469a79c45498e7b814ecf8d603cc7644e9acbd9e19cac0334240b18df", size = 203994, upload-time = "2026-08-03T14:41:03.438Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/89/9518bc0c3929bee36b3a4a8e3daddd6e03f92f9961c66d4983b837160543/typer-0.27.1-py3-none-any.whl", hash = "sha256:53150287edd11baeb4e4722c8e394fcdf8181c0ae89485cba8d25c778d5edd56", size = 122874, upload-time = "2026-08-03T14:41:04.391Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, +] + +[[package]] +name = "tzdata" +version = "2026.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/92/ff/5a28bdfd8c3ebec42564ac7d0e54ca3db65044a9314a97f9564fa7a1e926/tzdata-2026.3.tar.gz", hash = "sha256:4a1518b8993086a7982523e071643f3c0e5f213e75b21318e78bcabfff9d1415", size = 198674, upload-time = "2026-07-10T08:50:37.887Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/6d/b53b99a9f2766d095985947a5782f1702cabb129a34f7a802d7197af832f/tzdata-2026.3-py2.py3-none-any.whl", hash = "sha256:dc096730c87af6cab1b171c9d532be840741ff5d459015e7f6947bd7d7e54931", size = 348168, upload-time = "2026-07-10T08:50:36.46Z" }, +] + +[[package]] +name = "understudy-campaign-admission-generic-smoke" +version = "0.0.0" +source = { virtual = "." } +dependencies = [ + { name = "verifiers" }, +] + +[package.metadata] +requires-dist = [{ name = "verifiers", git = "https://github.com/PrimeIntellect-ai/verifiers.git?rev=61e7394d45109d142deec768c3c459ab98111e91" }] + +[[package]] +name = "urllib3" +version = "2.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, +] + +[[package]] +name = "uvicorn" +version = "0.52.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/03/18/ccce41535dee1be77735592bd19965f3972c82e07ee703d324709496b716/uvicorn-0.52.1.tar.gz", hash = "sha256:112ec661814189acbccd3f7b86460147cc065fc92c0821afa78918780e4354dd", size = 100571, upload-time = "2026-08-01T18:19:30.732Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/d5/68e6e9bca63c0badf67002890a46d3784c958de45b65e1275ec583ca1f06/uvicorn-0.52.1-py3-none-any.whl", hash = "sha256:e4403f9d93188cf9d1088e9f40e3acd12630e2df8675316704379a7fc20fff6a", size = 79859, upload-time = "2026-08-01T18:19:29.294Z" }, +] + +[[package]] +name = "uvloop" +version = "0.22.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250, upload-time = "2025-10-16T22:17:19.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/ff/7f72e8170be527b4977b033239a83a68d5c881cc4775fca255c677f7ac5d/uvloop-0.22.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:fe94b4564e865d968414598eea1a6de60adba0c040ba4ed05ac1300de402cd42", size = 1359936, upload-time = "2025-10-16T22:16:29.436Z" }, + { url = "https://files.pythonhosted.org/packages/c3/c6/e5d433f88fd54d81ef4be58b2b7b0cea13c442454a1db703a1eea0db1a59/uvloop-0.22.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:51eb9bd88391483410daad430813d982010f9c9c89512321f5b60e2cddbdddd6", size = 752769, upload-time = "2025-10-16T22:16:30.493Z" }, + { url = "https://files.pythonhosted.org/packages/24/68/a6ac446820273e71aa762fa21cdcc09861edd3536ff47c5cd3b7afb10eeb/uvloop-0.22.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:700e674a166ca5778255e0e1dc4e9d79ab2acc57b9171b79e65feba7184b3370", size = 4317413, upload-time = "2025-10-16T22:16:31.644Z" }, + { url = "https://files.pythonhosted.org/packages/5f/6f/e62b4dfc7ad6518e7eff2516f680d02a0f6eb62c0c212e152ca708a0085e/uvloop-0.22.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b5b1ac819a3f946d3b2ee07f09149578ae76066d70b44df3fa990add49a82e4", size = 4426307, upload-time = "2025-10-16T22:16:32.917Z" }, + { url = "https://files.pythonhosted.org/packages/90/60/97362554ac21e20e81bcef1150cb2a7e4ffdaf8ea1e5b2e8bf7a053caa18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e047cc068570bac9866237739607d1313b9253c3051ad84738cbb095be0537b2", size = 4131970, upload-time = "2025-10-16T22:16:34.015Z" }, + { url = "https://files.pythonhosted.org/packages/99/39/6b3f7d234ba3964c428a6e40006340f53ba37993f46ed6e111c6e9141d18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:512fec6815e2dd45161054592441ef76c830eddaad55c8aa30952e6fe1ed07c0", size = 4296343, upload-time = "2025-10-16T22:16:35.149Z" }, +] + +[[package]] +name = "verifiers" +version = "0.2.2.dev77" +source = { git = "https://github.com/PrimeIntellect-ai/verifiers.git?rev=61e7394d45109d142deec768c3c459ab98111e91#61e7394d45109d142deec768c3c459ab98111e91" } +dependencies = [ + { name = "aiohttp" }, + { name = "aiolimiter" }, + { name = "anthropic" }, + { name = "datasets" }, + { name = "gepa" }, + { name = "httpx" }, + { name = "loguru" }, + { name = "math-verify" }, + { name = "mcp" }, + { name = "msgpack" }, + { name = "numpy" }, + { name = "openai" }, + { name = "openai-agents" }, + { name = "prime-pydantic-config", extra = ["toml"] }, + { name = "prime-sandboxes" }, + { name = "prime-tunnel" }, + { name = "pydantic" }, + { name = "pyzmq" }, + { name = "renderers" }, + { name = "requests" }, + { name = "rich" }, + { name = "setproctitle" }, + { name = "tenacity" }, + { name = "tomli-w" }, + { name = "typing-extensions" }, + { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, +] + +[[package]] +name = "websockets" +version = "16.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/21/f7/bc3a25c5ec26ce62ce487690becc2f3710bbc7b33338f005ad390db0b986/websockets-16.1.1.tar.gz", hash = "sha256:db234eda965dcce15df96bb9709f587cd87d4d52aaf0e80e2f34ec04c7670c57", size = 182204, upload-time = "2026-07-17T22:51:05.858Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/9d/681cda21c9eee743203a6cb79b9d3d05adad9aa60ec660c6c9bf4dd619ca/websockets-16.1.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:cc97814dfb786a83b6e2dc2e79351e1b83e6d715647d6887fcabd83026417a00", size = 179600, upload-time = "2026-07-17T22:49:13.92Z" }, + { url = "https://files.pythonhosted.org/packages/fb/8d/6195a88b45e8d2a8f745fc2046e36f885a3c9763e6767d2c46229bf9510c/websockets-16.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e047dc87ef7ca50f4d309bf775ad4a71711c58556d75d7bd0604b2317f43e94b", size = 177272, upload-time = "2026-07-17T22:49:15.453Z" }, + { url = "https://files.pythonhosted.org/packages/73/e3/fe2d498c64dea0095c9a9f9a351af4cd6eef31b618395582bc1f38ba45ff/websockets-16.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:01fbdcbac298efe19360b94bc0039c8f746f0220ba570f327577bfee81059175", size = 177542, upload-time = "2026-07-17T22:49:16.875Z" }, + { url = "https://files.pythonhosted.org/packages/fe/ed/f1831681fce0e3242346e5458486003c5f124ed69e5e0b847fd029db4973/websockets-16.1.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0f62863e8a00a6d33c3d6566ec0b89f23787b747ffe0c3bc71ec0e76b82c94b1", size = 187137, upload-time = "2026-07-17T22:49:18.323Z" }, + { url = "https://files.pythonhosted.org/packages/6f/79/4ff9dcc1bb46f6b4c536936dde1fd60f9b564f3304307274db97f4c9496d/websockets-16.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8087e82f842609734c9b5a1330464f8e94e346ba0e18c832c08bafa4b0d63c15", size = 188374, upload-time = "2026-07-17T22:49:19.65Z" }, + { url = "https://files.pythonhosted.org/packages/62/c3/5c49b6efb36cab733d23773f6de575e1dba65736ead17d5d2b2a1daef779/websockets-16.1.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2bb5d041a8307d2e18782e7ce777f6fdb1e8c2f5d09291484b18c294b789d9aa", size = 191155, upload-time = "2026-07-17T22:49:21.331Z" }, + { url = "https://files.pythonhosted.org/packages/6e/f6/56ccceda3a4838d18f1d40821480da4775397e8b1eecf4031e20c50e2e90/websockets-16.1.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1db4de4a0e95673f7545d393c49eeb0c2f18ac1ef93073218c79d5cdb2ee75ab", size = 189011, upload-time = "2026-07-17T22:49:22.889Z" }, + { url = "https://files.pythonhosted.org/packages/86/d6/ad5286241a2bce1107e2798d3bfbd62cf79aee167bdb654f8cb1e9dbf949/websockets-16.1.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f17dbe07eb3ea7f99e4df9b7e0efefe80fbf30d37a8cc4d561a0aed310bc8847", size = 187766, upload-time = "2026-07-17T22:49:24.339Z" }, + { url = "https://files.pythonhosted.org/packages/bc/67/d65c970b7e347fdca69479beb7811c2060529956730a7a4e3ae7c66b0e31/websockets-16.1.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4b57693728576d84ede0a77987ab16881b783d2cd9f1dc180a8fbbc3f79c4428", size = 185173, upload-time = "2026-07-17T22:49:25.743Z" }, + { url = "https://files.pythonhosted.org/packages/1d/5b/14af3cd4ee69d8ea9baca58f3dc3cfb1ba78332a347fd478cb096549d60e/websockets-16.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2a636ff1e7a5c4edf71ef0e79adae7f25dba93b4fcbe3dc958733477ffeb0eaf", size = 187809, upload-time = "2026-07-17T22:49:27.147Z" }, + { url = "https://files.pythonhosted.org/packages/7b/11/be301710d70de97e3e7b3586e6d492c9c06d6a61bf1c2202c36cf0c75607/websockets-16.1.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d6bec75c290fe484a8ba4cacdf838501e17c06ecfbbf31eede81a9e431bd7751", size = 186412, upload-time = "2026-07-17T22:49:28.611Z" }, + { url = "https://files.pythonhosted.org/packages/db/07/fe1435bf6fe738a3d3b54dbe0c18dabf12cba4d909ac8b58b539ce27c1f4/websockets-16.1.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:54509b8e92fee4453e152b7558ddef37ce9705a044922f2095a6105e3f80c96f", size = 188290, upload-time = "2026-07-17T22:49:29.965Z" }, + { url = "https://files.pythonhosted.org/packages/8a/0a/81f394aff8efcbb01208c1ced77df0a3c7fcce584a88c7273663697946c2/websockets-16.1.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:f0aa4aad3b1b69ad3fd85a0fd0952ec64331c762bd77ec51cc814170873890b2", size = 185844, upload-time = "2026-07-17T22:49:31.447Z" }, + { url = "https://files.pythonhosted.org/packages/39/5c/dd485b995473f415510251fe9bd708f2d24458f439fce958daf8d66dc7c6/websockets-16.1.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:42290eb6db4ccaca7012656738214f8514082fb6fa40cdeb61bb9a471b52e383", size = 186823, upload-time = "2026-07-17T22:49:33.104Z" }, + { url = "https://files.pythonhosted.org/packages/9d/0b/f78de76ff446f1e66af12b43c48a35f31744de93cfdec2f4ea67d5d7bbf1/websockets-16.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:53260c8930da5771cec89439bff99c20c8cb03ddb9588b980697355a83cd4bd3", size = 187102, upload-time = "2026-07-17T22:49:34.616Z" }, + { url = "https://files.pythonhosted.org/packages/37/a1/4cf892007778eaf84ad162bfc98046e0ed89b63ac55949e3236626b2a23f/websockets-16.1.1-cp312-cp312-win32.whl", hash = "sha256:1d27fa8462ad6a1cb36206a3d0640b2333340def181fae11ed7f9adeaa5c0747", size = 179943, upload-time = "2026-07-17T22:49:36.213Z" }, + { url = "https://files.pythonhosted.org/packages/d9/de/6abe251d28c3a3f217096575400b27750b18e0b1d2fff3a2a239960fea07/websockets-16.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:b436f6ec4fc3a6b4237c84d3f83170ed2b40bb584222f0ac47a0c8a5921980c7", size = 180243, upload-time = "2026-07-17T22:49:37.626Z" }, + { url = "https://files.pythonhosted.org/packages/be/4d/2d0d67834092e354d2b0498f014a41249a89556bc406cf86f3e1557bb463/websockets-16.1.1-py3-none-any.whl", hash = "sha256:6abbd3e82c731c8e531714466acd5d87b5e88ac3243465337ba71d68e23ae7e3", size = 173814, upload-time = "2026-07-17T22:51:04.184Z" }, +] + +[[package]] +name = "win32-setctime" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/8f/705086c9d734d3b663af0e9bb3d4de6578d08f46b1b101c2442fd9aecaa2/win32_setctime-1.2.0.tar.gz", hash = "sha256:ae1fdf948f5640aae05c511ade119313fb6a30d7eabe25fef9764dca5873c4c0", size = 4867, upload-time = "2024-12-07T15:28:28.314Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/07/c6fe3ad3e685340704d314d765b7912993bcb8dc198f0e7a89382d37974b/win32_setctime-1.2.0-py3-none-any.whl", hash = "sha256:95d644c4e708aba81dc3704a116d8cbc974d70b3bdb8be1d150e36be6e9d1390", size = 4083, upload-time = "2024-12-07T15:28:26.465Z" }, +] + +[[package]] +name = "xxhash" +version = "3.8.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/63/71aa56b151a1b28770037a61bd4e461c2619cfc8866a4fcaf1548605e325/xxhash-3.8.1.tar.gz", hash = "sha256:b0de4bf3aa66363552d52c6a89003c479911f12098cd48a53d44a0f7a25f7c46", size = 86223, upload-time = "2026-07-06T10:49:58.937Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/91/f65c34a7aa7b4e7cf4854f8e6ef3f7ee32ceac41d4f008da0780db0612f6/xxhash-3.8.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e6e49370822c1f4d8d90e678b06dbcb08b51a026a7c4b55479e7d467f2e813bc", size = 34680, upload-time = "2026-07-06T10:44:40.932Z" }, + { url = "https://files.pythonhosted.org/packages/57/04/b10a245a4c09a9cfa88f8e9ae755029413ad1ac17047f9a61906e5ae0799/xxhash-3.8.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:220d68130f83f7cc86d6edfdeab176adc73d7200bf3a8ec10c629e8cf605c215", size = 32397, upload-time = "2026-07-06T10:44:42.196Z" }, + { url = "https://files.pythonhosted.org/packages/3a/75/45ab795b5945b6388583bd75202106af505537935566c15a1577797a0e08/xxhash-3.8.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4d365ee1892c1fa803536f8c6ce21d24b29c9718ec75eb856095c07830f8c478", size = 220549, upload-time = "2026-07-06T10:44:43.603Z" }, + { url = "https://files.pythonhosted.org/packages/13/44/5ba2bd0a14ddf4193fc7d8ec29625f659f22c06d60b28f04bf46305d8330/xxhash-3.8.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:852bfe059720632e2f16a6a4745e41d20937b2bf2a42a401e2412046bb6971cc", size = 241186, upload-time = "2026-07-06T10:44:45.534Z" }, + { url = "https://files.pythonhosted.org/packages/23/32/c4147def4d1e4538b906f82731e0ba23424377fc50a7cddd03cd284c8f63/xxhash-3.8.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2f8c25a7061d952de589bd0ea0eaadee32378ff83dd6a677b267f9cd86f401f8", size = 264852, upload-time = "2026-07-06T10:44:47.199Z" }, + { url = "https://files.pythonhosted.org/packages/6c/bd/71ed14f4f0318bb7fd7b2ec51999413487fa8da8d41208e84d50d1ef0f98/xxhash-3.8.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:868a8dcaff1a84ba78038e1cef14fc88ccf84d9b4d12ea604696e0693296aa56", size = 242663, upload-time = "2026-07-06T10:44:48.846Z" }, + { url = "https://files.pythonhosted.org/packages/91/09/70af22c565a8473b3f2ae73f88e7721af281bc4a575236dbd1970c9f76f6/xxhash-3.8.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6536d8677d2fff7e64cd0b98b976df9de7aee0e69590044c2af5f51b76b7a170", size = 473510, upload-time = "2026-07-06T10:44:50.695Z" }, + { url = "https://files.pythonhosted.org/packages/18/96/34db781c8f0cf99c544ca1f2bc2e5bf55426e1eb4ca6de8ea5da56a9f352/xxhash-3.8.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:82c0cedd280eab2e8291270e6c04894dbc096f8159a39dcf1807429f026ca3cc", size = 220469, upload-time = "2026-07-06T10:44:52.422Z" }, + { url = "https://files.pythonhosted.org/packages/93/5f/9a184f615fa5a4dce30c01534f62946ce5a11ce40f73785cbd356ccabaa9/xxhash-3.8.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:daa86e4b68221d38e669bb236ba112d0335353829fb627c82e5909e4bbe8694c", size = 310290, upload-time = "2026-07-06T10:44:54.142Z" }, + { url = "https://files.pythonhosted.org/packages/a9/dc/9b9a9789011ee153723a5eb9e7dd7fcbae2ba9b3fe7a729249ca7c252056/xxhash-3.8.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2bc7113e6f2b6b3922dd61796ca9f36af09da3773898e7003038dc992fc83b8d", size = 238173, upload-time = "2026-07-06T10:44:55.693Z" }, + { url = "https://files.pythonhosted.org/packages/ec/4d/71c6005ada9dcb608a4e1902e8475ecadb5f3fbfa04e1e244d276a2d0c43/xxhash-3.8.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5eed32dad81d6ba8e62dc7b9ffa0500199385d7810a8dd9d4eafaceb8c6e20bb", size = 269026, upload-time = "2026-07-06T10:44:57.424Z" }, + { url = "https://files.pythonhosted.org/packages/2f/87/d6c036ba25dfbd9c8633be5aa86fc9474bbb9e2c68212a841d090abe7344/xxhash-3.8.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:83697b0ea1f10e7f5d8b26a4906fa851393c61546c63839643a2b7fe2d868061", size = 224970, upload-time = "2026-07-06T10:44:59.085Z" }, + { url = "https://files.pythonhosted.org/packages/48/62/4c1f035a41c5752aa05e195b6c904c07b94fe9061a16de61e72a6e6b135f/xxhash-3.8.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:36fc69160465ae75c6ec4ac9f781bb2aa16ae7ff869e73c26fee85fbb11b9887", size = 240820, upload-time = "2026-07-06T10:45:00.746Z" }, + { url = "https://files.pythonhosted.org/packages/da/14/d39d565069b87e86d21a2af2a31d04db79249d25aa8d5b62959056a89857/xxhash-3.8.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:445e0f5a31f2f3546ae0895d4811e159518cdc9d824c11419898d40cfadb677e", size = 300619, upload-time = "2026-07-06T10:45:02.716Z" }, + { url = "https://files.pythonhosted.org/packages/13/22/75467acc887edc8cf71c97ab1708feb3df7a88bda589b9f399765c6387d2/xxhash-3.8.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:dfe0580fbfd5e4af87d0cc52d2044f155d55ebd8c8a93568758a2ea7d8e15975", size = 443267, upload-time = "2026-07-06T10:45:04.653Z" }, + { url = "https://files.pythonhosted.org/packages/a4/b6/1da3baa5fa6ef705e3425fddd382be7dfc4dfba2686df90a20f16e9c7b1b/xxhash-3.8.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:095e1323fa108be1292c54c86da3ef3c7a7dc015b105a52133973bc07a6ad11a", size = 217338, upload-time = "2026-07-06T10:45:06.304Z" }, + { url = "https://files.pythonhosted.org/packages/78/dd/b5295a9f97484e7a1c2b283a742ca45e3104991c55a1ef670dde161829ba/xxhash-3.8.1-cp312-cp312-win32.whl", hash = "sha256:bf28f55e427e0483acb1f666bd0d869b6d5e5a716680c216ad7befe3d4cfba2e", size = 31970, upload-time = "2026-07-06T10:45:07.823Z" }, + { url = "https://files.pythonhosted.org/packages/ec/31/3fa0b807d7e21515cd975e7fe5c039d52ac3e9401a96d6ad68dae6305215/xxhash-3.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:2256e80e4960ee282f63428adb349cb7f8bd8efe4db770d88eb815f4b9860724", size = 32741, upload-time = "2026-07-06T10:45:09.42Z" }, + { url = "https://files.pythonhosted.org/packages/b8/05/86feada74e239600e6875aa507afb40482a89b92700aa74a92da83bdcb77/xxhash-3.8.1-cp312-cp312-win_arm64.whl", hash = "sha256:9df56e6df96a60590935e22373041cccc91fd55858763dcffb55bf63b3a2b396", size = 29234, upload-time = "2026-07-06T10:45:10.809Z" }, +] + +[[package]] +name = "yarl" +version = "1.24.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "multidict" }, + { name = "propcache" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/31/33/ebe9e3d1f86c7a0b51094c0a146392045ca1631d2664889539dec8088a33/yarl-1.24.5.tar.gz", hash = "sha256:e81b83143bee16329c23db3c1b2d82b29892fcbcb849186d2f6e98a5abe9a57f", size = 228679, upload-time = "2026-07-20T02:07:45.435Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/84/71d051c850b5af41d168c679d9eb67eb7c55283ac4ee131673edf134bc4e/yarl-1.24.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d693396e5aea78db03decd60aec9ece16c9b40ba00a587f089615ff4e718a81d", size = 136035, upload-time = "2026-07-20T02:05:25.489Z" }, + { url = "https://files.pythonhosted.org/packages/03/4d/8ad27f9a1b7e69313cca5d695b925b48efe51208d3490e0844bae97cabc0/yarl-1.24.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3363fcc96e665878946ad7a106b9a13eac0541766a690ef287c0232ac768b6ec", size = 97642, upload-time = "2026-07-20T02:05:27.429Z" }, + { url = "https://files.pythonhosted.org/packages/ea/b4/05b4131c407006cd1e410e9c6539f16a0945724677e5364447313c15ea3e/yarl-1.24.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9d399bdcfb4a0f659b9b3788bbc89babe63d9a6a65aacdf4d4e7065ff2e6316c", size = 97323, upload-time = "2026-07-20T02:05:29.441Z" }, + { url = "https://files.pythonhosted.org/packages/20/16/e618c875c73e0e39611f20a581b3d5e8d59b8857bf001bee3263044c6deb/yarl-1.24.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90333fd89b43c0d08ac85f3f1447593fc2c66de18c3d6378d7125ea118dc7a54", size = 107741, upload-time = "2026-07-20T02:05:31.367Z" }, + { url = "https://files.pythonhosted.org/packages/d9/9a/c4defeaf3ed33fcb346aacf9c6e971a8d4e2bde04a0310e79abb208e7965/yarl-1.24.5-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:665b0a2c463cc9423dd647e0bfd9f4ccc9b50f768c55304d5e9f80b177c1de12", size = 103570, upload-time = "2026-07-20T02:05:33.303Z" }, + { url = "https://files.pythonhosted.org/packages/5f/e7/0e0e0de5865ebd5914537ef486f36c727a59865c3ac0cf5ff1b32aececbf/yarl-1.24.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e006d3a974c4ee19512e5f058abedb6eef36a5e553c14812bdeba1758d812e6d", size = 115815, upload-time = "2026-07-20T02:05:35.292Z" }, + { url = "https://files.pythonhosted.org/packages/2b/27/ca56b700cb170aba25a3893b75355b213935657dc5714d2383354a270e62/yarl-1.24.5-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e7d42c531243450ef0d4d9c172e7ed6ef052640f195629065041b5add4e058d1", size = 116025, upload-time = "2026-07-20T02:05:37.503Z" }, + { url = "https://files.pythonhosted.org/packages/d6/d0/d56c859b8222116f5d68459199f48359e0bf121b6f65a69bf329b3602ba0/yarl-1.24.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f08c7513ecef5aad65687bfdf6bc601ae9fccd04a42904501f8f7141abad9eb9", size = 109835, upload-time = "2026-07-20T02:05:39.506Z" }, + { url = "https://files.pythonhosted.org/packages/70/a2/3a35557e4d1a79425040eba202ccaf08bdc8717680fc77e2498a1ad2e0a5/yarl-1.24.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6c95b17fe34ed802f17e205112e6e10db92275c34fee290aa9bdc55a9c724027", size = 108884, upload-time = "2026-07-20T02:05:41.584Z" }, + { url = "https://files.pythonhosted.org/packages/e4/35/ef4c26356b7913c68983bac2d72a4212b3347af551cb8d250b99b5ed7b7f/yarl-1.24.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:56b149b22de33b23b0c6077ab9518c6dcb538ad462e1830e68d06591ccf6e38b", size = 107308, upload-time = "2026-07-20T02:05:43.697Z" }, + { url = "https://files.pythonhosted.org/packages/d5/91/ff0dc66c2ccf3e0153ab97ff61eabab4400e6a5264af427ab30cd69f1857/yarl-1.24.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a8fe66b8f300da93798025a785a5b90b42f3810dc2b72283ff84a41aaaebc293", size = 103646, upload-time = "2026-07-20T02:05:45.895Z" }, + { url = "https://files.pythonhosted.org/packages/74/f0/33b9271c7f881766359d58266fa0811d2e5210ed860e28da7dc6d7786344/yarl-1.24.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:377fe3732edbaf78ee74efdf2c9f49f6e99f20e7f9d2649fda3eb4badd77d76e", size = 115305, upload-time = "2026-07-20T02:05:47.832Z" }, + { url = "https://files.pythonhosted.org/packages/ef/65/fd79fb1868c4a80db8661091de525bf430f63c3bea1b20e8b6a84fc7d359/yarl-1.24.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e8ffa78582120024f476a611d7befc123cee59e47e8309d470cf667d806e613b", size = 108404, upload-time = "2026-07-20T02:05:49.604Z" }, + { url = "https://files.pythonhosted.org/packages/ff/ba/dbabe6b262f17a816c70cfc09558dbf03ece3ec76684d02f911a3d3a189c/yarl-1.24.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:daba5e594f06114e37db186efd2dd916609071e59daca901a0a2e71f02b142ce", size = 115940, upload-time = "2026-07-20T02:05:51.741Z" }, + { url = "https://files.pythonhosted.org/packages/a5/43/fab2d1dad9d340a268cdde63756a123d069723efff6a372d123fa74a9517/yarl-1.24.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:65be18ec59496c13908f02a2472751d9ef840b4f3fb5726f129306bf6a2a7bba", size = 110006, upload-time = "2026-07-20T02:05:53.554Z" }, + { url = "https://files.pythonhosted.org/packages/c4/27/41eb51bbd1b8d89546b83897cfb0164f1e109304fd408dbb151b639eec0f/yarl-1.24.5-cp312-cp312-win_amd64.whl", hash = "sha256:a929d878fec099030c292803b31e5d5540a7b6a31e6a3cc76cb4685fc2a2f51b", size = 97618, upload-time = "2026-07-20T02:05:55.57Z" }, + { url = "https://files.pythonhosted.org/packages/3c/25/b2553764b3d65db711d8f45416351ec4f420847558eb669edcbcaadf5780/yarl-1.24.5-cp312-cp312-win_arm64.whl", hash = "sha256:7ce27823052e2013b597e0c738b13e7e36b8ccb9400df8959417b052ab0fd92c", size = 93018, upload-time = "2026-07-20T02:05:57.554Z" }, + { url = "https://files.pythonhosted.org/packages/61/02/962c1cbfc401a30c1d034dc67ff395f64b52302c6d62de556c1fca99acc0/yarl-1.24.5-py3-none-any.whl", hash = "sha256:a33700d13d9b7d84fd10947b09ff69fb9a792e519c8cb9764a3ca70baa6c23a7", size = 58612, upload-time = "2026-07-20T02:07:43.461Z" }, +] diff --git a/tests/fixtures/campaign-admission/uv-project/generate_smoke.py b/tests/fixtures/campaign-admission/uv-project/generate_smoke.py index d2398446..fe7487d5 100755 --- a/tests/fixtures/campaign-admission/uv-project/generate_smoke.py +++ b/tests/fixtures/campaign-admission/uv-project/generate_smoke.py @@ -9,11 +9,14 @@ import os import platform import sys -import time +import subprocess +import tomllib from pathlib import Path import verifiers as vf from datasets import Dataset +from packaging.markers import default_environment +from packaging.requirements import Requirement from verifiers.clients import Client from verifiers.types import AssistantMessage, Response, ResponseMessage, ToolCall @@ -27,6 +30,14 @@ SAMPLING = {"max_tokens": 256, "temperature": 0} ARGUMENTS = '{"id":"alpha","status":"ready"}' CALL_ID = "call-public-1" +CAMPAIGN_ID = "public-synthetic-campaign" +WORKLOAD_ID = "cedar-public-synthetic" +REQUEST_ID = "request-public-1" +EXECUTION_ID = "execution-public-1" + + +def identity(): + return {"campaign_id": CAMPAIGN_ID, "workload_id": WORKLOAD_ID, "request_id": REQUEST_ID, "execution_id": EXECUTION_ID} def canonical(value): @@ -92,20 +103,30 @@ def set_record(id: str, status: str) -> str: return canonical({"ok": True, "applied": before != status, "before": before, "after": status}) set_record.__name__ = "set-record" + async def assertion_fraction(state): + if records["alpha"]["status"] != "ready": + return 0.0 + tool_messages = [message for step in state["trajectory"] for message in step["prompt"] if getattr(message, "role", None) == "tool"] + return 1.0 if any(json.loads(message.content).get("after") == "ready" for message in tool_messages) else 0.0 + dataset = Dataset.from_list([{"prompt": MESSAGES, "answer": "ready"}]) env = vf.ToolEnv(tools=[set_record], dataset=dataset, max_turns=2, sampling_args=SAMPLING) + assertion_rubric = vf.Rubric(funcs=[assertion_fraction]) + env.add_rubric(assertion_rubric) client = SyntheticClient() before = {"records": json.loads(json.dumps(records))} state = await env.rollout({"prompt": MESSAGES, "example_id": 0, "answer": "ready"}, client, "synthetic-local", SAMPLING) + await assertion_rubric.score_rollout(state) + assertion = state["metrics"].get("assertion_fraction") after = {"records": json.loads(json.dumps(records))} - if tool_calls != 1 or before["records"]["alpha"]["status"] != "pending" or after["records"]["alpha"]["status"] != "ready": + if tool_calls != 1 or assertion != 1.0 or before["records"]["alpha"]["status"] != "pending" or after["records"]["alpha"]["status"] != "ready": raise RuntimeError("Verifiers ToolEnv did not execute the required state delta exactly once") completion = state["trajectory"][0]["completion"][0] result = state["trajectory"][1]["prompt"][-1] - return before, after, state, completion, result, tool_calls + return before, after, state, completion, result, tool_calls, assertion -async def execute_overflow_probe(): +async def execute_overflow_probe(executable_bundle_sha256): tool_calls = 0 def set_record(id: str, status: str) -> str: @@ -122,6 +143,8 @@ def set_record(id: str, status: str) -> str: if failure != "OverlongPromptError" or client.sample_calls != 0 or tool_calls != 0 or state["trajectory"]: raise RuntimeError(f"oversized Verifiers probe did not fail before sampling/tool execution: failure={failure} samples={client.sample_calls} tools={tool_calls} trajectory={len(state['trajectory'])} error={state.get('error')!r}") return { + **identity(), + "executable_bundle_sha256": executable_bundle_sha256, "schema_version": "understudy.synthetic_overflow_probe.v1", "failure": failure, "failed_before_sampling": True, @@ -135,18 +158,35 @@ def set_record(id: str, status: str) -> str: async def generate(output): - before, after, state, completion, result, tool_calls = await execute_mutation() - overflow = await execute_overflow_probe() + before, after, state, completion, result, tool_calls, assertion = await execute_mutation() output.mkdir(parents=True, exist_ok=True) before_path, after_path, trace_path = output / "before-state.json", output / "after-state.json", output / "trace.json" write_json(before_path, before) write_json(after_path, after) + optimizer_input = {**identity(), "kind": "optimizer-input", "component": "actor", "source": "public-synthetic"} + model_attestation = {**identity(), "model": "synthetic-local", "provider": "provider-free"} + checkpoint = {**identity(), "checkpoint": "synthetic-checkpoint-v1"} + environment_sha256 = sha_bytes(Path("uv.lock").read_bytes()) + model_sha256, checkpoint_sha256 = sha_bytes(canonical(model_attestation).encode()), sha_bytes(canonical(checkpoint).encode()) + executable_bundle = {**identity(), "kind": "policy", "schema_version": "understudy.policy.v1", "policy": CANDIDATE, "frozen": True, "environment_sha256": environment_sha256, "model_attestation_sha256": model_sha256, "checkpoint_sha256": checkpoint_sha256} + executable_sha256 = sha_bytes(canonical(executable_bundle).encode()) + health_receipt = {**identity(), "status": "healthy", "route": "synthetic-local", "executable_bundle_sha256": executable_sha256, "environment_sha256": environment_sha256, "model_attestation_sha256": model_sha256} + lineage = {**identity(), "parent_candidate_sha256": sha_bytes(SEED.encode()), "prompt_sha256": sha_bytes(canonical(MESSAGES).encode()), "model_attestation_sha256": model_sha256, "checkpoint_sha256": checkpoint_sha256, "executable_bundle_sha256": executable_sha256, "health_receipt_sha256": sha_bytes(canonical(health_receipt).encode())} + evidence = { + "schema_version": "understudy.synthetic_campaign_evidence.v1", **identity(), + "optimizer_input": optimizer_input, "executable_bundle": executable_bundle, "health_receipt": health_receipt, + "model_attestation": model_attestation, "checkpoint": checkpoint, "lineage": lineage, + "source_context": {**identity(), "kind": "source", "context": "public synthetic source evidence"}, + "reflection_context": {**identity(), "kind": "reflection", "context": "public synthetic reflection evidence"}, + } + write_json(output / "campaign-evidence.json", evidence) + overflow = await execute_overflow_probe(sha_bytes(canonical(executable_bundle).encode())) write_json(output / "overflow-receipt.json", overflow) tools = [{"type": "function", "function": {"name": "set-record", "description": "Mutate a public synthetic record.", "parameters": env_tool_schema()}}] trace = { - "runtime": "standard-verifiers", "verifiers_version": vf.__version__, + "runtime": "standard-verifiers", "verifiers_version": vf.__version__, **identity(), "task": {"data": {"task_id": "public-synthetic-mutation-1", "split": "train"}}, - "rewards": {"assertion_fraction": 1.0}, "metrics": {"assertion_fraction": 1.0}, "errors": [], "ok": True, + "rewards": {"assertion_fraction": assertion}, "metrics": {"assertion_fraction": assertion}, "errors": [], "ok": True, "calls": [{"node": 2, "model": "synthetic-local", "endpoint": "/chat/completions", "finish_reason": "tool_calls", "messages_sha256": sha_bytes(canonical(MESSAGES).encode()), "tools_sha256": sha_bytes(canonical(tools).encode()), "sampling_sha256": sha_bytes(canonical(SAMPLING).encode()), "max_tokens": 256, "context_overflow_behavior": "fail"}], "nodes": [ {"message": MESSAGES[0], "sampled": False}, {"parent": 0, "message": MESSAGES[1], "sampled": False}, @@ -157,6 +197,25 @@ async def generate(output): } write_json(trace_path, trace) installed = sorted(({"name": d.metadata["Name"].lower().replace("_", "-"), "version": d.version} for d in importlib.metadata.distributions()), key=lambda x: (x["name"], x["version"])) + installed_by_name = {item["name"]: item["version"] for item in installed} + exported = subprocess.run(["uv", "export", "--project", ".", "--locked", "--format", "requirements-txt", "--no-hashes", "--no-emit-project", "--no-annotate", "--no-header"], check=True, capture_output=True, text=True).stdout + applicable = [] + for line in exported.splitlines(): + if not line.strip() or line.startswith((" ", "-")): + continue + requirement = Requirement(line.rstrip(" \\")) + if requirement.marker is not None and not requirement.marker.evaluate(default_environment()): + continue + name = requirement.name.lower().replace("_", "-") + version = installed_by_name.get(name) + if version is None: + raise RuntimeError(f"applicable locked distribution {name} is not installed") + applicable.append({"name": name, "version": version}) + applicable.sort(key=lambda x: (x["name"], x["version"])) + if installed != applicable: + raise RuntimeError("installed distributions do not equal uv-exported applicable lock inventory") + applicable_path = output / "applicable-lock.json" + write_json(applicable_path, applicable) executable = str(Path(sys.executable).absolute()) project_root = str(Path.cwd().resolve()) if not executable.startswith(str(Path(project_root, ".venv").absolute()) + os.sep): @@ -166,14 +225,19 @@ async def generate(output): verifiers_commit = direct_url.get("vcs_info", {}).get("commit_id") if not isinstance(verifiers_commit, str) or len(verifiers_commit) != 40: raise RuntimeError("installed Verifiers distribution lacks an exact git commit") + root_name = tomllib.loads(Path("pyproject.toml").read_text(encoding="utf-8"))["project"]["name"] receipt = { - "schema_version": "understudy.synthetic_verifiers_execution.v1", "argv": ARGV, + "schema_version": "understudy.synthetic_verifiers_execution.v1", **identity(), "argv": ARGV, "interpreter": {"implementation": platform.python_implementation(), "version": platform.python_version(), "path": str(Path(executable).relative_to(project_root)), "path_kind": "project_relative", "executable_sha256": sha_bytes(Path(executable).read_bytes())}, "installed_distributions": installed, "installed_distributions_sha256": sha_bytes(canonical(installed).encode()), + "applicable_locked_distributions": applicable, "applicable_locked_distributions_sha256": sha_bytes(canonical(applicable).encode()), + "applicable_lock_artifact_sha256": sha_bytes(applicable_path.read_bytes()), + "root_package_name": root_name, + "lock_exclusions": [{"name": root_name, "reason": "root-non-installable-no-emit-project"}, {"reason": "platform-marker-not-applicable"}], "verifiers": {"version": vf.__version__, "module": "verifiers", "git_revision": verifiers_commit}, "seed_candidate_sha256": sha_bytes(SEED.encode()), "mutated_candidate_sha256": sha_bytes(CANDIDATE.encode()), "before_state_sha256": sha_bytes(before_path.read_bytes()), "after_state_sha256": sha_bytes(after_path.read_bytes()), "trace_sha256": sha_bytes(trace_path.read_bytes()), - "verified_state_delta": {"path": "/records/alpha/status", "before": "pending", "after": "ready", "independently_asserted": True}, + "assertion_fraction": assertion, "assertion_rubric": "verifiers.Rubric", "verified_state_delta": {"path": "/records/alpha/status", "before": "pending", "after": "ready", "independently_asserted": True}, } write_json(output / "execution-receipt.json", receipt) diff --git a/tests/fixtures/campaign-admission/uv-project/generated/applicable-lock.json b/tests/fixtures/campaign-admission/uv-project/generated/applicable-lock.json new file mode 100644 index 00000000..683f424f --- /dev/null +++ b/tests/fixtures/campaign-admission/uv-project/generated/applicable-lock.json @@ -0,0 +1,418 @@ +[ + { + "name": "aiofiles", + "version": "25.1.0" + }, + { + "name": "aiohappyeyeballs", + "version": "2.7.1" + }, + { + "name": "aiohttp", + "version": "3.14.3" + }, + { + "name": "aiolimiter", + "version": "1.2.1" + }, + { + "name": "aiosignal", + "version": "1.4.0" + }, + { + "name": "annotated-doc", + "version": "0.0.5" + }, + { + "name": "annotated-types", + "version": "0.8.0" + }, + { + "name": "anthropic", + "version": "0.120.2" + }, + { + "name": "antlr4-python3-runtime", + "version": "4.13.2" + }, + { + "name": "anyio", + "version": "4.14.2" + }, + { + "name": "attrs", + "version": "26.1.0" + }, + { + "name": "certifi", + "version": "2026.7.22" + }, + { + "name": "cffi", + "version": "2.1.1" + }, + { + "name": "charset-normalizer", + "version": "3.4.9" + }, + { + "name": "click", + "version": "8.4.2" + }, + { + "name": "connect-python", + "version": "0.9.0" + }, + { + "name": "cryptography", + "version": "50.0.0" + }, + { + "name": "datasets", + "version": "5.0.1" + }, + { + "name": "dill", + "version": "0.4.1" + }, + { + "name": "distro", + "version": "1.9.0" + }, + { + "name": "docstring-parser", + "version": "0.18.0" + }, + { + "name": "filelock", + "version": "3.32.2" + }, + { + "name": "frozenlist", + "version": "1.8.0" + }, + { + "name": "fsspec", + "version": "2026.6.0" + }, + { + "name": "gepa", + "version": "0.1.4" + }, + { + "name": "griffelib", + "version": "2.1.0" + }, + { + "name": "h11", + "version": "0.16.0" + }, + { + "name": "hf-xet", + "version": "1.6.0" + }, + { + "name": "httpcore", + "version": "1.0.9" + }, + { + "name": "httpx", + "version": "0.28.1" + }, + { + "name": "httpx-sse", + "version": "0.4.3" + }, + { + "name": "huggingface-hub", + "version": "1.26.0" + }, + { + "name": "idna", + "version": "3.18" + }, + { + "name": "jinja2", + "version": "3.1.6" + }, + { + "name": "jiter", + "version": "0.16.0" + }, + { + "name": "jsonschema", + "version": "4.26.0" + }, + { + "name": "jsonschema-specifications", + "version": "2025.9.1" + }, + { + "name": "latex2sympy2-extended", + "version": "1.11.0" + }, + { + "name": "loguru", + "version": "0.7.3" + }, + { + "name": "markdown-it-py", + "version": "4.2.0" + }, + { + "name": "markupsafe", + "version": "3.0.3" + }, + { + "name": "math-verify", + "version": "0.9.0" + }, + { + "name": "mcp", + "version": "1.29.0" + }, + { + "name": "mdurl", + "version": "0.1.2" + }, + { + "name": "mpmath", + "version": "1.3.0" + }, + { + "name": "msgpack", + "version": "1.2.1" + }, + { + "name": "multidict", + "version": "6.7.1" + }, + { + "name": "multiprocess", + "version": "0.70.19" + }, + { + "name": "numpy", + "version": "2.5.1" + }, + { + "name": "openai", + "version": "2.53.0" + }, + { + "name": "openai-agents", + "version": "0.19.3" + }, + { + "name": "openai-harmony", + "version": "0.0.8" + }, + { + "name": "opentelemetry-api", + "version": "1.44.0" + }, + { + "name": "packaging", + "version": "26.2" + }, + { + "name": "pandas", + "version": "3.0.5" + }, + { + "name": "prime-pydantic-config", + "version": "0.4.2" + }, + { + "name": "prime-sandboxes", + "version": "0.2.34" + }, + { + "name": "prime-tunnel", + "version": "0.1.10" + }, + { + "name": "propcache", + "version": "0.5.2" + }, + { + "name": "protobuf", + "version": "7.35.1" + }, + { + "name": "pyarrow", + "version": "25.0.0" + }, + { + "name": "pycparser", + "version": "3.0" + }, + { + "name": "pydantic", + "version": "2.13.4" + }, + { + "name": "pydantic-core", + "version": "2.46.4" + }, + { + "name": "pydantic-settings", + "version": "2.14.2" + }, + { + "name": "pygments", + "version": "2.20.0" + }, + { + "name": "pyjwt", + "version": "2.13.0" + }, + { + "name": "pyqwest", + "version": "0.8.0" + }, + { + "name": "python-dateutil", + "version": "2.9.0.post0" + }, + { + "name": "python-dotenv", + "version": "1.2.2" + }, + { + "name": "python-multipart", + "version": "0.0.32" + }, + { + "name": "pyyaml", + "version": "6.0.3" + }, + { + "name": "pyzmq", + "version": "27.1.0" + }, + { + "name": "referencing", + "version": "0.37.0" + }, + { + "name": "regex", + "version": "2026.7.19" + }, + { + "name": "renderers", + "version": "0.1.8" + }, + { + "name": "requests", + "version": "2.34.2" + }, + { + "name": "rich", + "version": "15.0.0" + }, + { + "name": "rpds-py", + "version": "2026.6.3" + }, + { + "name": "safetensors", + "version": "0.8.0" + }, + { + "name": "setproctitle", + "version": "1.3.7" + }, + { + "name": "shellingham", + "version": "1.5.4" + }, + { + "name": "six", + "version": "1.17.0" + }, + { + "name": "sniffio", + "version": "1.3.1" + }, + { + "name": "sse-starlette", + "version": "3.4.6" + }, + { + "name": "starlette", + "version": "1.3.1" + }, + { + "name": "sympy", + "version": "1.14.0" + }, + { + "name": "tenacity", + "version": "9.1.4" + }, + { + "name": "tiktoken", + "version": "0.13.0" + }, + { + "name": "tokenizers", + "version": "0.22.2" + }, + { + "name": "tomli", + "version": "2.4.1" + }, + { + "name": "tomli-w", + "version": "1.2.0" + }, + { + "name": "tqdm", + "version": "4.70.0" + }, + { + "name": "transformers", + "version": "5.14.1" + }, + { + "name": "typer", + "version": "0.27.1" + }, + { + "name": "typing-extensions", + "version": "4.16.0" + }, + { + "name": "typing-inspection", + "version": "0.4.2" + }, + { + "name": "urllib3", + "version": "2.7.0" + }, + { + "name": "uvicorn", + "version": "0.52.1" + }, + { + "name": "uvloop", + "version": "0.22.1" + }, + { + "name": "verifiers", + "version": "0.2.1" + }, + { + "name": "websockets", + "version": "16.1.1" + }, + { + "name": "xxhash", + "version": "3.8.1" + }, + { + "name": "yarl", + "version": "1.24.5" + } +] diff --git a/tests/fixtures/campaign-admission/uv-project/generated/campaign-evidence.json b/tests/fixtures/campaign-admission/uv-project/generated/campaign-evidence.json new file mode 100644 index 00000000..1a0f1705 --- /dev/null +++ b/tests/fixtures/campaign-admission/uv-project/generated/campaign-evidence.json @@ -0,0 +1,83 @@ +{ + "campaign_id": "public-synthetic-campaign", + "checkpoint": { + "campaign_id": "public-synthetic-campaign", + "checkpoint": "synthetic-checkpoint-v1", + "execution_id": "execution-public-1", + "request_id": "request-public-1", + "workload_id": "cedar-public-synthetic" + }, + "executable_bundle": { + "campaign_id": "public-synthetic-campaign", + "checkpoint_sha256": "267de74365c7b4321821fb7924ff0598c6c7a69abc38fa11bb889755ac5c09af", + "environment_sha256": "be34de4d14a135dac01c2649f6447b4abebde8242ff51cbf6d8bba2835d7c8dd", + "execution_id": "execution-public-1", + "frozen": true, + "kind": "policy", + "model_attestation_sha256": "c889573d7bc391c0df3d5d3d4cfec9d7a4ec006b34e934eb6f19bf55ef3e6c87", + "policy": "Set record alpha to ready with set-record, then report success.", + "request_id": "request-public-1", + "schema_version": "understudy.policy.v1", + "workload_id": "cedar-public-synthetic" + }, + "execution_id": "execution-public-1", + "health_receipt": { + "campaign_id": "public-synthetic-campaign", + "environment_sha256": "be34de4d14a135dac01c2649f6447b4abebde8242ff51cbf6d8bba2835d7c8dd", + "executable_bundle_sha256": "f6f7c7c57a2d5613bc2be3bfe23115bd97350c3839df87abcf266387bbdf3860", + "execution_id": "execution-public-1", + "model_attestation_sha256": "c889573d7bc391c0df3d5d3d4cfec9d7a4ec006b34e934eb6f19bf55ef3e6c87", + "request_id": "request-public-1", + "route": "synthetic-local", + "status": "healthy", + "workload_id": "cedar-public-synthetic" + }, + "lineage": { + "campaign_id": "public-synthetic-campaign", + "checkpoint_sha256": "267de74365c7b4321821fb7924ff0598c6c7a69abc38fa11bb889755ac5c09af", + "executable_bundle_sha256": "f6f7c7c57a2d5613bc2be3bfe23115bd97350c3839df87abcf266387bbdf3860", + "execution_id": "execution-public-1", + "health_receipt_sha256": "88fe5da7984fde75c1c8444e9fe525e991ceeeb2a387e4a006b2a560fa4eb85f", + "model_attestation_sha256": "c889573d7bc391c0df3d5d3d4cfec9d7a4ec006b34e934eb6f19bf55ef3e6c87", + "parent_candidate_sha256": "4dbee206fc073f8db3e50fad210ca48772e481ad31ee37f33e638bca91db1914", + "prompt_sha256": "6f71099eedf6d5b161ceea52fa0663b0c104b5729a77d3a5f4264967b5853808", + "request_id": "request-public-1", + "workload_id": "cedar-public-synthetic" + }, + "model_attestation": { + "campaign_id": "public-synthetic-campaign", + "execution_id": "execution-public-1", + "model": "synthetic-local", + "provider": "provider-free", + "request_id": "request-public-1", + "workload_id": "cedar-public-synthetic" + }, + "optimizer_input": { + "campaign_id": "public-synthetic-campaign", + "component": "actor", + "execution_id": "execution-public-1", + "kind": "optimizer-input", + "request_id": "request-public-1", + "source": "public-synthetic", + "workload_id": "cedar-public-synthetic" + }, + "reflection_context": { + "campaign_id": "public-synthetic-campaign", + "context": "public synthetic reflection evidence", + "execution_id": "execution-public-1", + "kind": "reflection", + "request_id": "request-public-1", + "workload_id": "cedar-public-synthetic" + }, + "request_id": "request-public-1", + "schema_version": "understudy.synthetic_campaign_evidence.v1", + "source_context": { + "campaign_id": "public-synthetic-campaign", + "context": "public synthetic source evidence", + "execution_id": "execution-public-1", + "kind": "source", + "request_id": "request-public-1", + "workload_id": "cedar-public-synthetic" + }, + "workload_id": "cedar-public-synthetic" +} diff --git a/tests/fixtures/campaign-admission/uv-project/generated/execution-receipt.json b/tests/fixtures/campaign-admission/uv-project/generated/execution-receipt.json index de8e86ae..561e3220 100644 --- a/tests/fixtures/campaign-admission/uv-project/generated/execution-receipt.json +++ b/tests/fixtures/campaign-admission/uv-project/generated/execution-receipt.json @@ -1,5 +1,425 @@ { "after_state_sha256": "578c4dc9e95cf9ef87e1ccd5f2236a61cc2faf0a120d16f52f871643f3675a34", + "applicable_lock_artifact_sha256": "3db856f8e925ea98bf9f61c4b550bf8b2cb2159495426505145da69460e4d1ec", + "applicable_locked_distributions": [ + { + "name": "aiofiles", + "version": "25.1.0" + }, + { + "name": "aiohappyeyeballs", + "version": "2.7.1" + }, + { + "name": "aiohttp", + "version": "3.14.3" + }, + { + "name": "aiolimiter", + "version": "1.2.1" + }, + { + "name": "aiosignal", + "version": "1.4.0" + }, + { + "name": "annotated-doc", + "version": "0.0.5" + }, + { + "name": "annotated-types", + "version": "0.8.0" + }, + { + "name": "anthropic", + "version": "0.120.2" + }, + { + "name": "antlr4-python3-runtime", + "version": "4.13.2" + }, + { + "name": "anyio", + "version": "4.14.2" + }, + { + "name": "attrs", + "version": "26.1.0" + }, + { + "name": "certifi", + "version": "2026.7.22" + }, + { + "name": "cffi", + "version": "2.1.1" + }, + { + "name": "charset-normalizer", + "version": "3.4.9" + }, + { + "name": "click", + "version": "8.4.2" + }, + { + "name": "connect-python", + "version": "0.9.0" + }, + { + "name": "cryptography", + "version": "50.0.0" + }, + { + "name": "datasets", + "version": "5.0.1" + }, + { + "name": "dill", + "version": "0.4.1" + }, + { + "name": "distro", + "version": "1.9.0" + }, + { + "name": "docstring-parser", + "version": "0.18.0" + }, + { + "name": "filelock", + "version": "3.32.2" + }, + { + "name": "frozenlist", + "version": "1.8.0" + }, + { + "name": "fsspec", + "version": "2026.6.0" + }, + { + "name": "gepa", + "version": "0.1.4" + }, + { + "name": "griffelib", + "version": "2.1.0" + }, + { + "name": "h11", + "version": "0.16.0" + }, + { + "name": "hf-xet", + "version": "1.6.0" + }, + { + "name": "httpcore", + "version": "1.0.9" + }, + { + "name": "httpx", + "version": "0.28.1" + }, + { + "name": "httpx-sse", + "version": "0.4.3" + }, + { + "name": "huggingface-hub", + "version": "1.26.0" + }, + { + "name": "idna", + "version": "3.18" + }, + { + "name": "jinja2", + "version": "3.1.6" + }, + { + "name": "jiter", + "version": "0.16.0" + }, + { + "name": "jsonschema", + "version": "4.26.0" + }, + { + "name": "jsonschema-specifications", + "version": "2025.9.1" + }, + { + "name": "latex2sympy2-extended", + "version": "1.11.0" + }, + { + "name": "loguru", + "version": "0.7.3" + }, + { + "name": "markdown-it-py", + "version": "4.2.0" + }, + { + "name": "markupsafe", + "version": "3.0.3" + }, + { + "name": "math-verify", + "version": "0.9.0" + }, + { + "name": "mcp", + "version": "1.29.0" + }, + { + "name": "mdurl", + "version": "0.1.2" + }, + { + "name": "mpmath", + "version": "1.3.0" + }, + { + "name": "msgpack", + "version": "1.2.1" + }, + { + "name": "multidict", + "version": "6.7.1" + }, + { + "name": "multiprocess", + "version": "0.70.19" + }, + { + "name": "numpy", + "version": "2.5.1" + }, + { + "name": "openai", + "version": "2.53.0" + }, + { + "name": "openai-agents", + "version": "0.19.3" + }, + { + "name": "openai-harmony", + "version": "0.0.8" + }, + { + "name": "opentelemetry-api", + "version": "1.44.0" + }, + { + "name": "packaging", + "version": "26.2" + }, + { + "name": "pandas", + "version": "3.0.5" + }, + { + "name": "prime-pydantic-config", + "version": "0.4.2" + }, + { + "name": "prime-sandboxes", + "version": "0.2.34" + }, + { + "name": "prime-tunnel", + "version": "0.1.10" + }, + { + "name": "propcache", + "version": "0.5.2" + }, + { + "name": "protobuf", + "version": "7.35.1" + }, + { + "name": "pyarrow", + "version": "25.0.0" + }, + { + "name": "pycparser", + "version": "3.0" + }, + { + "name": "pydantic", + "version": "2.13.4" + }, + { + "name": "pydantic-core", + "version": "2.46.4" + }, + { + "name": "pydantic-settings", + "version": "2.14.2" + }, + { + "name": "pygments", + "version": "2.20.0" + }, + { + "name": "pyjwt", + "version": "2.13.0" + }, + { + "name": "pyqwest", + "version": "0.8.0" + }, + { + "name": "python-dateutil", + "version": "2.9.0.post0" + }, + { + "name": "python-dotenv", + "version": "1.2.2" + }, + { + "name": "python-multipart", + "version": "0.0.32" + }, + { + "name": "pyyaml", + "version": "6.0.3" + }, + { + "name": "pyzmq", + "version": "27.1.0" + }, + { + "name": "referencing", + "version": "0.37.0" + }, + { + "name": "regex", + "version": "2026.7.19" + }, + { + "name": "renderers", + "version": "0.1.8" + }, + { + "name": "requests", + "version": "2.34.2" + }, + { + "name": "rich", + "version": "15.0.0" + }, + { + "name": "rpds-py", + "version": "2026.6.3" + }, + { + "name": "safetensors", + "version": "0.8.0" + }, + { + "name": "setproctitle", + "version": "1.3.7" + }, + { + "name": "shellingham", + "version": "1.5.4" + }, + { + "name": "six", + "version": "1.17.0" + }, + { + "name": "sniffio", + "version": "1.3.1" + }, + { + "name": "sse-starlette", + "version": "3.4.6" + }, + { + "name": "starlette", + "version": "1.3.1" + }, + { + "name": "sympy", + "version": "1.14.0" + }, + { + "name": "tenacity", + "version": "9.1.4" + }, + { + "name": "tiktoken", + "version": "0.13.0" + }, + { + "name": "tokenizers", + "version": "0.22.2" + }, + { + "name": "tomli", + "version": "2.4.1" + }, + { + "name": "tomli-w", + "version": "1.2.0" + }, + { + "name": "tqdm", + "version": "4.70.0" + }, + { + "name": "transformers", + "version": "5.14.1" + }, + { + "name": "typer", + "version": "0.27.1" + }, + { + "name": "typing-extensions", + "version": "4.16.0" + }, + { + "name": "typing-inspection", + "version": "0.4.2" + }, + { + "name": "urllib3", + "version": "2.7.0" + }, + { + "name": "uvicorn", + "version": "0.52.1" + }, + { + "name": "uvloop", + "version": "0.22.1" + }, + { + "name": "verifiers", + "version": "0.2.1" + }, + { + "name": "websockets", + "version": "16.1.1" + }, + { + "name": "xxhash", + "version": "3.8.1" + }, + { + "name": "yarl", + "version": "1.24.5" + } + ], + "applicable_locked_distributions_sha256": "d1693d46acb2bd255e700e847358bdabc19b35879a8ff187ed038e6dee6b5d01", "argv": [ "uv", "run", @@ -11,7 +431,11 @@ "--output", "generated" ], + "assertion_fraction": 1.0, + "assertion_rubric": "verifiers.Rubric", "before_state_sha256": "9e4f76c756726a6c01f052f18b08db9fa2e073cd5e074f7693d55159d5f99612", + "campaign_id": "public-synthetic-campaign", + "execution_id": "execution-public-1", "installed_distributions": [ { "name": "aiofiles", @@ -438,10 +862,21 @@ "path_kind": "project_relative", "version": "3.12.13" }, + "lock_exclusions": [ + { + "name": "understudy-campaign-admission-smoke", + "reason": "root-non-installable-no-emit-project" + }, + { + "reason": "platform-marker-not-applicable" + } + ], "mutated_candidate_sha256": "0ba2e4298634b3771db51d77ffca15af1c7e731fc15c290b60ab5c44097c1f6c", + "request_id": "request-public-1", + "root_package_name": "understudy-campaign-admission-smoke", "schema_version": "understudy.synthetic_verifiers_execution.v1", "seed_candidate_sha256": "4dbee206fc073f8db3e50fad210ca48772e481ad31ee37f33e638bca91db1914", - "trace_sha256": "cd9ffc6c1bb68e006481e0789a4a63bdbbc8b4ee066a8083228106595591d25b", + "trace_sha256": "fce8b5fcb3c4e6ee75d154342aa679f1a15d842e1ecfb47fd532014100cd3353", "verified_state_delta": { "after": "ready", "before": "pending", @@ -452,5 +887,6 @@ "git_revision": "ab65b6e8d34b03d162408d4bcb854430a86809e6", "module": "verifiers", "version": "0.2.1" - } + }, + "workload_id": "cedar-public-synthetic" } diff --git a/tests/fixtures/campaign-admission/uv-project/generated/overflow-receipt.json b/tests/fixtures/campaign-admission/uv-project/generated/overflow-receipt.json index 9aa3e053..28f5ddbb 100644 --- a/tests/fixtures/campaign-admission/uv-project/generated/overflow-receipt.json +++ b/tests/fixtures/campaign-admission/uv-project/generated/overflow-receipt.json @@ -1,11 +1,16 @@ { + "campaign_id": "public-synthetic-campaign", "effective_max_tokens": 256, + "executable_bundle_sha256": "f6f7c7c57a2d5613bc2be3bfe23115bd97350c3839df87abcf266387bbdf3860", + "execution_id": "execution-public-1", "failed_before_sampling": true, "failure": "OverlongPromptError", "oversized_request_sha256": "a47b86e783052357b1268c9ce2b1d1943d197a330f7863a2c2c21664da05008a", + "request_id": "request-public-1", "requested_max_tokens": 256, "sample_calls": 0, "schema_version": "understudy.synthetic_overflow_probe.v1", "tool_calls": 0, - "trajectory_steps": 0 + "trajectory_steps": 0, + "workload_id": "cedar-public-synthetic" } diff --git a/tests/fixtures/campaign-admission/uv-project/generated/trace.json b/tests/fixtures/campaign-admission/uv-project/generated/trace.json index 584d8d22..a60f3c21 100644 --- a/tests/fixtures/campaign-admission/uv-project/generated/trace.json +++ b/tests/fixtures/campaign-admission/uv-project/generated/trace.json @@ -12,11 +12,13 @@ "tools_sha256": "ad4cc5e9dc6e0a8481d7b6b890033bd33fc457c49a875d458d27e4299b761b64" } ], + "campaign_id": "public-synthetic-campaign", "errors": [], "execution": { "tool_calls": 1, "verifiers_trajectory_steps": 2 }, + "execution_id": "execution-public-1", "metrics": { "assertion_fraction": 1.0 }, @@ -62,6 +64,7 @@ } ], "ok": true, + "request_id": "request-public-1", "rewards": { "assertion_fraction": 1.0 }, @@ -72,5 +75,6 @@ "task_id": "public-synthetic-mutation-1" } }, - "verifiers_version": "0.2.1" + "verifiers_version": "0.2.1", + "workload_id": "cedar-public-synthetic" } diff --git a/tests/helpers/campaign-admission-fixture.mjs b/tests/helpers/campaign-admission-fixture.mjs index 28ff64c9..ccc906f1 100644 --- a/tests/helpers/campaign-admission-fixture.mjs +++ b/tests/helpers/campaign-admission-fixture.mjs @@ -6,25 +6,26 @@ const fixture = resolve("tests/fixtures/campaign-admission"); const bytes = (name) => readFileSync(join(fixture, name)); const sha = (value) => createHash("sha256").update(value).digest("hex"); -export function baseManifest(mod) { - const generated = "uv-project/generated"; - const artifacts = { request: bytes("request.json"), response: bytes("response.json"), tools: bytes("tools.json"), trace: bytes(`${generated}/trace.json`), executionReceipt: bytes(`${generated}/execution-receipt.json`), beforeState: bytes(`${generated}/before-state.json`), afterState: bytes(`${generated}/after-state.json`), overflowReceipt: bytes(`${generated}/overflow-receipt.json`) }; +export function baseManifest(mod, projectDir = "uv-project") { + const generated = `${projectDir}/generated`; + const artifacts = { request: bytes("request.json"), response: bytes("response.json"), tools: bytes("tools.json"), trace: bytes(`${generated}/trace.json`), executionReceipt: bytes(`${generated}/execution-receipt.json`), beforeState: bytes(`${generated}/before-state.json`), afterState: bytes(`${generated}/after-state.json`), overflowReceipt: bytes(`${generated}/overflow-receipt.json`), campaignEvidence: bytes(`${generated}/campaign-evidence.json`), applicableLock: bytes(`${generated}/applicable-lock.json`) }; const trace = JSON.parse(artifacts.trace); const receipt = JSON.parse(artifacts.executionReceipt); const request = JSON.parse(artifacts.request); + const evidence = JSON.parse(artifacts.campaignEvidence); const semantic = (value) => mod.semanticJsonSha256(Buffer.from(JSON.stringify(value)), "fixture"); const fixedMessages = request.messages.map((message) => ({ ...message, content: message.content.replace(/[\s\S]*?<\/candidate_policy>/g, "") })); - const lockHash = sha(bytes("uv-project/uv.lock")); + const lockHash = sha(bytes(`${projectDir}/uv.lock`)); const manifest = { - schema_version: "understudy.campaign_admission.v1", campaign_id: "public-synthetic-campaign", - environment: { pyproject_sha256: sha(bytes("uv-project/pyproject.toml")), uv_lock_sha256: lockHash, uv_lock_check_command: "uv lock --check", uv_lock_check_exit_code: 0, uv_version: "0.12.1", python_version: receipt.interpreter.version, python_executable_sha256: receipt.interpreter.executable_sha256, installed_distributions_sha256: receipt.installed_distributions_sha256, container_image_digest: `sha256:${"2".repeat(64)}`, resolved_packages: mod.parseUvLockPins(bytes("uv-project/uv.lock").toString("utf8")) }, + schema_version: "understudy.campaign_admission.v1", campaign_id: request.campaign_id, workload_id: request.workload_id, request_id: request.request_id, execution_id: request.execution_id, + environment: { pyproject_sha256: sha(bytes(`${projectDir}/pyproject.toml`)), uv_lock_sha256: lockHash, uv_lock_check_command: "uv lock --check", uv_lock_check_exit_code: 0, uv_version: "0.12.1", python_version: receipt.interpreter.version, python_executable_sha256: receipt.interpreter.executable_sha256, installed_distributions_sha256: receipt.installed_distributions_sha256, applicable_lock_artifact_sha256: sha(artifacts.applicableLock), container_image_digest: `sha256:${"2".repeat(64)}`, resolved_packages: mod.parseUvLockPins(bytes(`${projectDir}/uv.lock`).toString("utf8")) }, transport_fingerprints: mod.fingerprintTransport(artifacts), tool_steps: mod.fingerprintToolSteps(artifacts), payload_parity: { messages_sha256: semantic(request.messages), tools_sha256: semantic(JSON.parse(artifacts.tools)), sampling_sha256: semantic(request.sampling), context_overflow_behavior: "fail", overflow_probe_receipt_sha256: sha(artifacts.overflowReceipt) }, - workload_contract: { benchmark_prompt_sha256: semantic(fixedMessages), candidate_source: "outer_system_transcript", candidate_tag_sha256: receipt.mutated_candidate_sha256, policy_injection_count: 1, verifiers_version: "0.2.1", verifiers_git_revision: "ab65b6e8d34b03d162408d4bcb854430a86809e6", mcp_version: "1.29.0", tool_schema_sha256: semantic(JSON.parse(artifacts.tools)), package_inventory_sha256: lockHash }, - optimizer_input: { input_bundle_sha256: "3".repeat(64) }, - endpoint_bundle: { bundle_kind: "policy", schema_version: "understudy.policy.v1", executable_bundle_sha256: "4".repeat(64), environment_sha256: lockHash, health_receipt_sha256: "5".repeat(64), model_attestation_sha256: "6".repeat(64), frozen: true, seed: false }, - candidate_lineage: { parent_candidate_sha256: "7".repeat(64), candidate_sha256: "0".repeat(64), prompt_sha256: semantic(fixedMessages), model_attestation_sha256: "6".repeat(64), checkpoint_sha256: "8".repeat(64) }, - context_gates: { source_context_sha256: "9".repeat(64), reflection_context_sha256: "a".repeat(64), source_context_present: true, reflection_context_present: true }, + workload_contract: { benchmark_prompt_sha256: semantic(fixedMessages), candidate_source: "outer_system_transcript", candidate_tag_sha256: receipt.mutated_candidate_sha256, policy_injection_count: 1, verifiers_version: receipt.verifiers.version, verifiers_git_revision: receipt.verifiers.git_revision, mcp_version: "1.29.0", tool_schema_sha256: semantic(JSON.parse(artifacts.tools)), package_inventory_sha256: lockHash }, + optimizer_input: { input_bundle_sha256: semantic(evidence.optimizer_input) }, + endpoint_bundle: { bundle_kind: evidence.executable_bundle.kind, schema_version: evidence.executable_bundle.schema_version, executable_bundle_sha256: semantic(evidence.executable_bundle), environment_sha256: lockHash, health_receipt_sha256: semantic(evidence.health_receipt), model_attestation_sha256: semantic(evidence.model_attestation), frozen: true, seed: false }, + candidate_lineage: { parent_candidate_sha256: evidence.lineage.parent_candidate_sha256, candidate_sha256: "0".repeat(64), prompt_sha256: evidence.lineage.prompt_sha256, model_attestation_sha256: evidence.lineage.model_attestation_sha256, checkpoint_sha256: evidence.lineage.checkpoint_sha256, lineage_artifact_sha256: semantic(evidence.lineage) }, + context_gates: { source_context_sha256: semantic(evidence.source_context), reflection_context_sha256: semantic(evidence.reflection_context), source_context_present: true, reflection_context_present: true }, mutation_smoke: { runtime: trace.runtime, verifiers_version: trace.verifiers_version, task_count: 1, calls: trace.calls.length, nodes: trace.nodes.length, assertion_fraction: trace.metrics.assertion_fraction, seed_candidate_sha256: receipt.seed_candidate_sha256, mutated_candidate_sha256: receipt.mutated_candidate_sha256, eval_exit_code: 0, trace_artifact_sha256: sha(artifacts.trace), execution_receipt_sha256: sha(artifacts.executionReceipt), mutating_effects: [{ tool: "set-record", applied: true }] }, spend: { campaign_total_usd: 100, prior_spend_usd: 10, allocations: { optimizer: { cap_usd: 20 }, endpoint: { cap_usd: 40 }, training: { cap_usd: 30 } }, transfers: [], charges: [{ charge_id: "optimizer-1", lane: "optimizer", amount_usd: 2, immutable_receipt_sha256: "b".repeat(64) }, { charge_id: "endpoint-1", lane: "endpoint", amount_usd: 3, immutable_receipt_sha256: "c".repeat(64) }, { charge_id: "training-1", lane: "training", amount_usd: 4, immutable_receipt_sha256: "d".repeat(64) }] }, }; From d348fe7031ba25d65056699dad71d51cd68a146d Mon Sep 17 00:00:00 2001 From: luis manrique <166242911+lluisinthedesert@users.noreply.github.com> Date: Tue, 4 Aug 2026 05:48:58 -0700 Subject: [PATCH 6/8] move campaign admission trust root into agent tools --- .../campaign-admission/trusted-generator.txt | 7 +- ...derstudy.campaign_admission.v1.schema.json | 3 +- scripts/package-smoke.mjs | 1 + src/campaign-admission/index.ts | 9 +- src/commands/campaigns.ts | 19 +- tests/campaign-admission-cli.test.mjs | 42 ++- tests/campaign-admission.test.mjs | 2 +- .../generated/execution-receipt.json | 8 +- .../uv-project/generate_smoke.py | 253 ------------------ .../generated/execution-receipt.json | 8 +- tests/helpers/campaign-admission-fixture.mjs | 4 +- 11 files changed, 78 insertions(+), 278 deletions(-) rename tests/fixtures/campaign-admission/uv-project-generic/generate_smoke.py => runtime-assets/campaign-admission/trusted-generator.txt (97%) delete mode 100755 tests/fixtures/campaign-admission/uv-project/generate_smoke.py diff --git a/tests/fixtures/campaign-admission/uv-project-generic/generate_smoke.py b/runtime-assets/campaign-admission/trusted-generator.txt similarity index 97% rename from tests/fixtures/campaign-admission/uv-project-generic/generate_smoke.py rename to runtime-assets/campaign-admission/trusted-generator.txt index fe7487d5..d7a63074 100755 --- a/tests/fixtures/campaign-admission/uv-project-generic/generate_smoke.py +++ b/runtime-assets/campaign-admission/trusted-generator.txt @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Generate provider-free evidence by executing pinned Verifiers 0.2.1.""" +"""Audited agent-tools trust root for provider-free campaign admission.""" import argparse import asyncio @@ -20,7 +20,8 @@ from verifiers.clients import Client from verifiers.types import AssistantMessage, Response, ResponseMessage, ToolCall -ARGV = ["uv", "run", "--project", ".", "--locked", "python", "generate_smoke.py", "--output", "generated"] +TRUSTED_GENERATOR_VERSION = "understudy.agent_tools.campaign_admission_generator.v1" +ARGV = ["uv", "run", "--project", "", "--locked", "python", "", "--output", ""] SEED = "Only inspect the synthetic record." CANDIDATE = "Set record alpha to ready with set-record, then report success." MESSAGES = [ @@ -228,6 +229,8 @@ async def generate(output): root_name = tomllib.loads(Path("pyproject.toml").read_text(encoding="utf-8"))["project"]["name"] receipt = { "schema_version": "understudy.synthetic_verifiers_execution.v1", **identity(), "argv": ARGV, + "trusted_generator_version": TRUSTED_GENERATOR_VERSION, + "trusted_generator_sha256": sha_bytes(Path(__file__).read_bytes()), "interpreter": {"implementation": platform.python_implementation(), "version": platform.python_version(), "path": str(Path(executable).relative_to(project_root)), "path_kind": "project_relative", "executable_sha256": sha_bytes(Path(executable).read_bytes())}, "installed_distributions": installed, "installed_distributions_sha256": sha_bytes(canonical(installed).encode()), "applicable_locked_distributions": applicable, "applicable_locked_distributions_sha256": sha_bytes(canonical(applicable).encode()), diff --git a/schemas/understudy.campaign_admission.v1.schema.json b/schemas/understudy.campaign_admission.v1.schema.json index 2f8f0110..e7772b3b 100644 --- a/schemas/understudy.campaign_admission.v1.schema.json +++ b/schemas/understudy.campaign_admission.v1.schema.json @@ -30,7 +30,7 @@ "exact_version": { "type": "string", "pattern": "^[0-9][0-9A-Za-z.!+_-]*$" }, "environment": { "type": "object", "additionalProperties": false, - "required": ["pyproject_sha256", "uv_lock_sha256", "uv_lock_check_command", "uv_lock_check_exit_code", "uv_version", "python_version", "python_executable_sha256", "installed_distributions_sha256", "applicable_lock_artifact_sha256", "resolved_packages", "container_image_digest"], + "required": ["pyproject_sha256", "uv_lock_sha256", "uv_lock_check_command", "uv_lock_check_exit_code", "uv_version", "python_version", "python_executable_sha256", "installed_distributions_sha256", "applicable_lock_artifact_sha256", "trusted_generator_sha256", "resolved_packages", "container_image_digest"], "properties": { "pyproject_sha256": { "$ref": "#/$defs/sha256" }, "uv_lock_sha256": { "$ref": "#/$defs/sha256" }, @@ -41,6 +41,7 @@ "python_executable_sha256": { "$ref": "#/$defs/sha256" }, "installed_distributions_sha256": { "$ref": "#/$defs/sha256" }, "applicable_lock_artifact_sha256": { "$ref": "#/$defs/sha256" }, + "trusted_generator_sha256": { "$ref": "#/$defs/sha256" }, "container_image_digest": { "$ref": "#/$defs/image_digest" }, "resolved_packages": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/package_pin" } } } diff --git a/scripts/package-smoke.mjs b/scripts/package-smoke.mjs index 1ddb4fcd..7c3e20be 100644 --- a/scripts/package-smoke.mjs +++ b/scripts/package-smoke.mjs @@ -47,6 +47,7 @@ const requiredPackageMembers = [ "skills/local-distillation-lab/references/pedagogical-arm.md", "skills/recursive-language-model/SKILL.md", "skills/recursive-language-model/references/pedagogical-training.md", + "runtime-assets/campaign-admission/trusted-generator.txt", ]; function npmPackFiles() { diff --git a/src/campaign-admission/index.ts b/src/campaign-admission/index.ts index 8ac11fab..cff56bd6 100644 --- a/src/campaign-admission/index.ts +++ b/src/campaign-admission/index.ts @@ -19,6 +19,7 @@ export type TransportArtifacts = { overflowReceipt: Buffer; campaignEvidence: Buffer; applicableLock: Buffer; + trustedGenerator: Buffer; }; export type TransportFingerprints = { @@ -227,9 +228,10 @@ function validateExecutionReceipt(manifest: JsonObject, artifacts: TransportArti const smoke = object(manifest.mutation_smoke); if (smoke.execution_receipt_sha256 !== sha256Bytes(artifacts.executionReceipt)) errors.push("mutation_smoke.execution_receipt_sha256 does not match supplied receipt"); if (receipt.schema_version !== "understudy.synthetic_verifiers_execution.v1") errors.push("synthetic execution receipt schema is invalid"); + if (receipt.trusted_generator_version !== "understudy.agent_tools.campaign_admission_generator.v1" || receipt.trusted_generator_sha256 !== sha256Bytes(artifacts.trustedGenerator) || receipt.trusted_generator_sha256 !== object(manifest.environment).trusted_generator_sha256) errors.push("execution evidence is not derived by the trusted agent-tools generator"); validateIdentity(manifest, receipt, "execution receipt", errors); const argv = receipt.argv; - if (canonicalize(argv) !== canonicalize(["uv", "run", "--project", ".", "--locked", "python", "generate_smoke.py", "--output", "generated"])) errors.push("synthetic smoke must use exact locked-project uv argv"); + if (canonicalize(argv) !== canonicalize(["uv", "run", "--project", "", "--locked", "python", "", "--output", ""])) errors.push("synthetic smoke must use the exact locked-project trusted-generator argv"); if (Array.isArray(argv) && argv.includes("--no-project")) errors.push("synthetic smoke cannot use --no-project"); const interpreter = object(receipt.interpreter); if (interpreter.implementation !== "CPython" || interpreter.version !== object(manifest.environment).python_version) errors.push("execution receipt interpreter does not match the admitted project"); @@ -388,6 +390,7 @@ function validateEnvironment(manifest: JsonObject, errors: string[]): void { requireSha(errors, environment.python_executable_sha256, "environment.python_executable_sha256"); requireSha(errors, environment.installed_distributions_sha256, "environment.installed_distributions_sha256"); requireSha(errors, environment.applicable_lock_artifact_sha256, "environment.applicable_lock_artifact_sha256"); + requireSha(errors, environment.trusted_generator_sha256, "environment.trusted_generator_sha256"); if (typeof environment.container_image_digest !== "string" || !IMAGE_DIGEST.test(environment.container_image_digest)) errors.push("environment.container_image_digest must be an immutable sha256 digest"); const pins = Array.isArray(environment.resolved_packages) ? environment.resolved_packages.map(object) : []; @@ -523,6 +526,6 @@ export function validateCampaignAdmission(manifest: unknown, artifacts: Transpor return { admission_only: true, compile_authorized: false, admitted: errors.length === 0, errors, fingerprints, tool_steps, effective_spend_caps_usd: spend.effective, cumulative_spend_usd: spend.cumulative }; } -export function readTransportArtifacts(paths: { request: string; response: string; tools: string; trace: string; executionReceipt: string; beforeState: string; afterState: string; overflowReceipt: string; campaignEvidence: string; applicableLock: string }): TransportArtifacts { - return { request: readFileSync(paths.request), response: readFileSync(paths.response), tools: readFileSync(paths.tools), trace: readFileSync(paths.trace), executionReceipt: readFileSync(paths.executionReceipt), beforeState: readFileSync(paths.beforeState), afterState: readFileSync(paths.afterState), overflowReceipt: readFileSync(paths.overflowReceipt), campaignEvidence: readFileSync(paths.campaignEvidence), applicableLock: readFileSync(paths.applicableLock) }; +export function readTransportArtifacts(paths: { request: string; response: string; tools: string; trace: string; executionReceipt: string; beforeState: string; afterState: string; overflowReceipt: string; campaignEvidence: string; applicableLock: string; trustedGenerator: string }): TransportArtifacts { + return { request: readFileSync(paths.request), response: readFileSync(paths.response), tools: readFileSync(paths.tools), trace: readFileSync(paths.trace), executionReceipt: readFileSync(paths.executionReceipt), beforeState: readFileSync(paths.beforeState), afterState: readFileSync(paths.afterState), overflowReceipt: readFileSync(paths.overflowReceipt), campaignEvidence: readFileSync(paths.campaignEvidence), applicableLock: readFileSync(paths.applicableLock), trustedGenerator: readFileSync(paths.trustedGenerator) }; } diff --git a/src/commands/campaigns.ts b/src/commands/campaigns.ts index 24c9f6cc..ba8b52bd 100644 --- a/src/commands/campaigns.ts +++ b/src/commands/campaigns.ts @@ -1,7 +1,9 @@ import { execFileSync } from "node:child_process"; import { createHash } from "node:crypto"; -import { readFileSync } from "node:fs"; +import { mkdtempSync, readFileSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; import { join, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; import type { Command } from "commander"; import { parseUvLockPins, readTransportArtifacts, validateCampaignAdmission } from "../campaign-admission/index.js"; @@ -26,8 +28,7 @@ export function registerCampaignsCommand(program: Command): void { .requiredOption("--overflow-receipt ", "Generated oversized-request failure receipt") .requiredOption("--campaign-evidence ", "Generated immutable campaign evidence bundle") .requiredOption("--applicable-lock ", "Generated platform-applicable uv lock inventory") - .requiredOption("--smoke-generator ", "Provider-free generator inside the locked project") - .action((options: { manifest: string; project: string; request: string; response: string; tools: string; trace: string; executionReceipt: string; beforeState: string; afterState: string; overflowReceipt: string; campaignEvidence: string; applicableLock: string; smokeGenerator: string }) => { + .action((options: { manifest: string; project: string; request: string; response: string; tools: string; trace: string; executionReceipt: string; beforeState: string; afterState: string; overflowReceipt: string; campaignEvidence: string; applicableLock: string }) => { try { const project = resolve(options.project); const manifest = JSON.parse(readFileSync(resolve(options.manifest), "utf8")) as Record; @@ -44,13 +45,15 @@ export function registerCampaignsCommand(program: Command): void { const declaredPins = JSON.stringify(environment.resolved_packages); const lockedPins = JSON.stringify(parseUvLockPins(readFileSync(lock, "utf8"))); if (declaredPins !== lockedPins) throw new Error("resolved package pins do not exactly match uv.lock"); - const generator = resolve(options.smokeGenerator); - if (generator !== join(project, "generate_smoke.py")) throw new Error("smoke generator must be generate_smoke.py inside the locked project"); + const generator = fileURLToPath(new URL("../../runtime-assets/campaign-admission/trusted-generator.txt", import.meta.url)); + if (environment.trusted_generator_sha256 !== fileSha256(generator)) throw new Error("trusted agent-tools generator hash does not match manifest"); const comparisons = [["trace.json", options.trace], ["execution-receipt.json", options.executionReceipt], ["before-state.json", options.beforeState], ["after-state.json", options.afterState], ["overflow-receipt.json", options.overflowReceipt], ["campaign-evidence.json", options.campaignEvidence], ["applicable-lock.json", options.applicableLock]] as const; const expected = new Map(comparisons.map(([generated, supplied]) => [generated, readFileSync(resolve(supplied))])); - execFileSync("uv", ["run", "--project", ".", "--locked", "python", "generate_smoke.py", "--output", "generated"], { cwd: project, stdio: "pipe" }); - for (const [generated] of comparisons) if (!readFileSync(join(project, "generated", generated)).equals(expected.get(generated)!)) throw new Error(`generated ${generated} differs from supplied fixture`); - const result = validateCampaignAdmission(manifest, readTransportArtifacts({ request: resolve(options.request), response: resolve(options.response), tools: resolve(options.tools), trace: resolve(options.trace), executionReceipt: resolve(options.executionReceipt), beforeState: resolve(options.beforeState), afterState: resolve(options.afterState), overflowReceipt: resolve(options.overflowReceipt), campaignEvidence: resolve(options.campaignEvidence), applicableLock: resolve(options.applicableLock) })); + const generatedDir = mkdtempSync(join(tmpdir(), "understudy-trusted-admission-")); + execFileSync("uv", ["run", "--project", project, "--locked", "python", generator, "--output", generatedDir], { cwd: project, stdio: "pipe" }); + for (const [generated] of comparisons) if (!readFileSync(join(generatedDir, generated)).equals(expected.get(generated)!)) throw new Error(`trusted agent-tools derivation rejects supplied ${generated}`); + const result = validateCampaignAdmission(manifest, readTransportArtifacts({ request: resolve(options.request), response: resolve(options.response), tools: resolve(options.tools), trace: resolve(options.trace), executionReceipt: resolve(options.executionReceipt), beforeState: resolve(options.beforeState), afterState: resolve(options.afterState), overflowReceipt: resolve(options.overflowReceipt), campaignEvidence: resolve(options.campaignEvidence), applicableLock: resolve(options.applicableLock), trustedGenerator: generator })); + rmSync(generatedDir, { recursive: true, force: true }); process.stdout.write(`${JSON.stringify(result, null, 2)}\n`); if (!result.admitted) process.exitCode = 1; } catch (error) { diff --git a/tests/campaign-admission-cli.test.mjs b/tests/campaign-admission-cli.test.mjs index fc1620ed..f23b9f2e 100644 --- a/tests/campaign-admission-cli.test.mjs +++ b/tests/campaign-admission-cli.test.mjs @@ -24,8 +24,7 @@ for (const projectName of ["uv-project", "uv-project-generic"]) it(`campaigns ad "--before-state", join(generated, "before-state.json"), "--after-state", join(generated, "after-state.json"), "--overflow-receipt", join(generated, "overflow-receipt.json"), "--campaign-evidence", join(generated, "campaign-evidence.json"), - "--applicable-lock", join(generated, "applicable-lock.json"), - "--smoke-generator", join(project, "generate_smoke.py")]; + "--applicable-lock", join(generated, "applicable-lock.json")]; const run = spawnSync("node", args, { encoding: "utf8", timeout: 30_000 }); assert.equal(run.status, 0, `${run.stderr}\n${run.stdout}`); const output = JSON.parse(run.stdout); @@ -35,3 +34,42 @@ for (const projectName of ["uv-project", "uv-project-generic"]) it(`campaigns ad assert.equal(output.tool_steps[0].semantic_arguments_equal, true); } finally { rmSync(temp, { recursive: true, force: true }); } }); + +it("rejects a coherently rehashed fabrication because trusted agent-tools derivation disagrees", async (t) => { + if (spawnSync("uv", ["--version"]).status !== 0) return t.skip("uv is unavailable"); + const mod = await import("../dist/campaign-admission/index.js"); + const { manifest, artifacts } = baseManifest(mod); + const project = join(fixture, "uv-project"); + manifest.environment.uv_version = execFileSync("uv", ["--version"], { encoding: "utf8" }).trim().match(/^uv\s+(\S+)/)[1]; + const trace = JSON.parse(artifacts.trace); + trace.metrics.assertion_fraction = 0.5; + trace.rewards.assertion_fraction = 0.5; + const fakeTrace = Buffer.from(`${JSON.stringify(trace)}\n`); + const receipt = JSON.parse(artifacts.executionReceipt); + receipt.assertion_fraction = 0.5; + receipt.trace_sha256 = mod.sha256Bytes(fakeTrace); + const fakeReceipt = Buffer.from(`${JSON.stringify(receipt)}\n`); + const fakeArtifacts = { ...artifacts, trace: fakeTrace, executionReceipt: fakeReceipt }; + manifest.mutation_smoke.assertion_fraction = 0.5; + manifest.mutation_smoke.trace_artifact_sha256 = mod.sha256Bytes(fakeTrace); + manifest.mutation_smoke.execution_receipt_sha256 = mod.sha256Bytes(fakeReceipt); + manifest.transport_fingerprints = mod.fingerprintTransport(fakeArtifacts); + const temp = mkdtempSync(join(tmpdir(), "campaign-admission-fabrication-")); + try { + const manifestPath = join(temp, "manifest.json"); + const tracePath = join(temp, "trace.json"); + const receiptPath = join(temp, "execution-receipt.json"); + writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`); + writeFileSync(tracePath, fakeTrace); + writeFileSync(receiptPath, fakeReceipt); + const generated = join(project, "generated"); + const args = [resolve("dist/bin.js"), "campaigns", "admit", "--manifest", manifestPath, "--project", project, + "--request", join(fixture, "request.json"), "--response", join(fixture, "response.json"), "--tools", join(fixture, "tools.json"), + "--trace", tracePath, "--execution-receipt", receiptPath, "--before-state", join(generated, "before-state.json"), + "--after-state", join(generated, "after-state.json"), "--overflow-receipt", join(generated, "overflow-receipt.json"), + "--campaign-evidence", join(generated, "campaign-evidence.json"), "--applicable-lock", join(generated, "applicable-lock.json")]; + const run = spawnSync("node", args, { encoding: "utf8", timeout: 30_000 }); + assert.equal(run.status, 1, run.stdout); + assert.match(run.stderr, /trusted agent-tools derivation rejects supplied trace\.json/); + } finally { rmSync(temp, { recursive: true, force: true }); } +}); diff --git a/tests/campaign-admission.test.mjs b/tests/campaign-admission.test.mjs index 9240238a..89904e84 100644 --- a/tests/campaign-admission.test.mjs +++ b/tests/campaign-admission.test.mjs @@ -126,7 +126,7 @@ describe("campaign admission", () => { manifest.mutation_smoke.execution_receipt_sha256 = mod.sha256Bytes(changed.executionReceipt); const result = mod.validateCampaignAdmission(manifest, changed); assert.equal(result.admitted, false); - assert.match(result.errors.join("\n"), /locked-project uv argv|cannot use --no-project|locked project Python|installed distributions/); + assert.match(result.errors.join("\n"), /locked-project trusted-generator argv|cannot use --no-project|locked project Python|installed distributions/); } }); diff --git a/tests/fixtures/campaign-admission/uv-project-generic/generated/execution-receipt.json b/tests/fixtures/campaign-admission/uv-project-generic/generated/execution-receipt.json index f6b9319b..391f5b6f 100644 --- a/tests/fixtures/campaign-admission/uv-project-generic/generated/execution-receipt.json +++ b/tests/fixtures/campaign-admission/uv-project-generic/generated/execution-receipt.json @@ -424,12 +424,12 @@ "uv", "run", "--project", - ".", + "", "--locked", "python", - "generate_smoke.py", + "", "--output", - "generated" + "" ], "assertion_fraction": 1.0, "assertion_rubric": "verifiers.Rubric", @@ -877,6 +877,8 @@ "schema_version": "understudy.synthetic_verifiers_execution.v1", "seed_candidate_sha256": "4dbee206fc073f8db3e50fad210ca48772e481ad31ee37f33e638bca91db1914", "trace_sha256": "4d47c8afd537dd8377d8b349ca7b67900f7b2d3fd2e406606c07bc57204b5938", + "trusted_generator_sha256": "e49c99e33cdaaa9b82198acf2d2b342000b3e1fbaf824add561bf0e9f8d7363e", + "trusted_generator_version": "understudy.agent_tools.campaign_admission_generator.v1", "verified_state_delta": { "after": "ready", "before": "pending", diff --git a/tests/fixtures/campaign-admission/uv-project/generate_smoke.py b/tests/fixtures/campaign-admission/uv-project/generate_smoke.py deleted file mode 100755 index fe7487d5..00000000 --- a/tests/fixtures/campaign-admission/uv-project/generate_smoke.py +++ /dev/null @@ -1,253 +0,0 @@ -#!/usr/bin/env python3 -"""Generate provider-free evidence by executing pinned Verifiers 0.2.1.""" - -import argparse -import asyncio -import hashlib -import importlib.metadata -import json -import os -import platform -import sys -import subprocess -import tomllib -from pathlib import Path - -import verifiers as vf -from datasets import Dataset -from packaging.markers import default_environment -from packaging.requirements import Requirement -from verifiers.clients import Client -from verifiers.types import AssistantMessage, Response, ResponseMessage, ToolCall - -ARGV = ["uv", "run", "--project", ".", "--locked", "python", "generate_smoke.py", "--output", "generated"] -SEED = "Only inspect the synthetic record." -CANDIDATE = "Set record alpha to ready with set-record, then report success." -MESSAGES = [ - {"role": "system", "content": f"{SEED}\n{CANDIDATE}"}, - {"role": "user", "content": "Set synthetic record alpha to ready."}, -] -SAMPLING = {"max_tokens": 256, "temperature": 0} -ARGUMENTS = '{"id":"alpha","status":"ready"}' -CALL_ID = "call-public-1" -CAMPAIGN_ID = "public-synthetic-campaign" -WORKLOAD_ID = "cedar-public-synthetic" -REQUEST_ID = "request-public-1" -EXECUTION_ID = "execution-public-1" - - -def identity(): - return {"campaign_id": CAMPAIGN_ID, "workload_id": WORKLOAD_ID, "request_id": REQUEST_ID, "execution_id": EXECUTION_ID} - - -def canonical(value): - return json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=False) - - -def sha_bytes(value): - return hashlib.sha256(value).hexdigest() - - -def write_json(path, value): - path.write_text(json.dumps(value, sort_keys=True, indent=2) + "\n", encoding="utf-8") - - -class SyntheticClient(Client): - def __init__(self, *, overflow_limit=None): - super().__init__(object()) - self.sample_calls = 0 - self.overflow_limit = overflow_limit - - def setup_client(self, config): - return object() - - async def to_native_tool(self, tool): - return tool - - async def to_native_prompt(self, messages): - return messages, {} - - async def get_native_response(self, prompt, model, sampling_args, tools=None, **kwargs): - raise AssertionError("the synthetic client overrides get_response") - - async def raise_from_native_response(self, response): - return None - - async def from_native_response(self, response): - return response - - async def close(self): - return None - - async def get_response(self, prompt, model, sampling_args, tools=None, **kwargs): - if self.overflow_limit is not None and len(canonical([m.model_dump() for m in prompt])) > self.overflow_limit: - raise vf.OverlongPromptError("synthetic context limit exceeded") - self.sample_calls += 1 - if self.sample_calls == 1: - message = ResponseMessage(role="assistant", content=None, finish_reason="tool_calls", is_truncated=False, tool_calls=[ToolCall(id=CALL_ID, name="set-record", arguments=ARGUMENTS)]) - else: - message = ResponseMessage(role="assistant", content="done", finish_reason="stop", is_truncated=False) - return Response(id=f"synthetic-{self.sample_calls}", created=0, model=model, usage=None, message=message) - - -async def execute_mutation(): - records = {"alpha": {"status": "pending"}} - tool_calls = 0 - - def set_record(id: str, status: str) -> str: - """Mutate a public synthetic record.""" - nonlocal tool_calls - tool_calls += 1 - before = records[id]["status"] - records[id]["status"] = status - return canonical({"ok": True, "applied": before != status, "before": before, "after": status}) - set_record.__name__ = "set-record" - - async def assertion_fraction(state): - if records["alpha"]["status"] != "ready": - return 0.0 - tool_messages = [message for step in state["trajectory"] for message in step["prompt"] if getattr(message, "role", None) == "tool"] - return 1.0 if any(json.loads(message.content).get("after") == "ready" for message in tool_messages) else 0.0 - - dataset = Dataset.from_list([{"prompt": MESSAGES, "answer": "ready"}]) - env = vf.ToolEnv(tools=[set_record], dataset=dataset, max_turns=2, sampling_args=SAMPLING) - assertion_rubric = vf.Rubric(funcs=[assertion_fraction]) - env.add_rubric(assertion_rubric) - client = SyntheticClient() - before = {"records": json.loads(json.dumps(records))} - state = await env.rollout({"prompt": MESSAGES, "example_id": 0, "answer": "ready"}, client, "synthetic-local", SAMPLING) - await assertion_rubric.score_rollout(state) - assertion = state["metrics"].get("assertion_fraction") - after = {"records": json.loads(json.dumps(records))} - if tool_calls != 1 or assertion != 1.0 or before["records"]["alpha"]["status"] != "pending" or after["records"]["alpha"]["status"] != "ready": - raise RuntimeError("Verifiers ToolEnv did not execute the required state delta exactly once") - completion = state["trajectory"][0]["completion"][0] - result = state["trajectory"][1]["prompt"][-1] - return before, after, state, completion, result, tool_calls, assertion - - -async def execute_overflow_probe(executable_bundle_sha256): - tool_calls = 0 - - def set_record(id: str, status: str) -> str: - nonlocal tool_calls - tool_calls += 1 - return canonical({"ok": True}) - set_record.__name__ = "set-record" - - oversized = [{"role": "user", "content": "x" * 4096}] - env = vf.ToolEnv(tools=[set_record], dataset=Dataset.from_list([{"prompt": oversized}]), max_turns=1, sampling_args=SAMPLING) - client = SyntheticClient(overflow_limit=128) - state = await env.rollout({"prompt": oversized, "example_id": 0}, client, "synthetic-local", SAMPLING) - failure = "OverlongPromptError" if state.get("prompt_too_long") else (type(state.get("error")).__name__ if state.get("error") else None) - if failure != "OverlongPromptError" or client.sample_calls != 0 or tool_calls != 0 or state["trajectory"]: - raise RuntimeError(f"oversized Verifiers probe did not fail before sampling/tool execution: failure={failure} samples={client.sample_calls} tools={tool_calls} trajectory={len(state['trajectory'])} error={state.get('error')!r}") - return { - **identity(), - "executable_bundle_sha256": executable_bundle_sha256, - "schema_version": "understudy.synthetic_overflow_probe.v1", - "failure": failure, - "failed_before_sampling": True, - "sample_calls": client.sample_calls, - "tool_calls": tool_calls, - "trajectory_steps": len(state["trajectory"]), - "oversized_request_sha256": sha_bytes(canonical(oversized).encode()), - "requested_max_tokens": SAMPLING["max_tokens"], - "effective_max_tokens": state["sampling_args"]["max_tokens"], - } - - -async def generate(output): - before, after, state, completion, result, tool_calls, assertion = await execute_mutation() - output.mkdir(parents=True, exist_ok=True) - before_path, after_path, trace_path = output / "before-state.json", output / "after-state.json", output / "trace.json" - write_json(before_path, before) - write_json(after_path, after) - optimizer_input = {**identity(), "kind": "optimizer-input", "component": "actor", "source": "public-synthetic"} - model_attestation = {**identity(), "model": "synthetic-local", "provider": "provider-free"} - checkpoint = {**identity(), "checkpoint": "synthetic-checkpoint-v1"} - environment_sha256 = sha_bytes(Path("uv.lock").read_bytes()) - model_sha256, checkpoint_sha256 = sha_bytes(canonical(model_attestation).encode()), sha_bytes(canonical(checkpoint).encode()) - executable_bundle = {**identity(), "kind": "policy", "schema_version": "understudy.policy.v1", "policy": CANDIDATE, "frozen": True, "environment_sha256": environment_sha256, "model_attestation_sha256": model_sha256, "checkpoint_sha256": checkpoint_sha256} - executable_sha256 = sha_bytes(canonical(executable_bundle).encode()) - health_receipt = {**identity(), "status": "healthy", "route": "synthetic-local", "executable_bundle_sha256": executable_sha256, "environment_sha256": environment_sha256, "model_attestation_sha256": model_sha256} - lineage = {**identity(), "parent_candidate_sha256": sha_bytes(SEED.encode()), "prompt_sha256": sha_bytes(canonical(MESSAGES).encode()), "model_attestation_sha256": model_sha256, "checkpoint_sha256": checkpoint_sha256, "executable_bundle_sha256": executable_sha256, "health_receipt_sha256": sha_bytes(canonical(health_receipt).encode())} - evidence = { - "schema_version": "understudy.synthetic_campaign_evidence.v1", **identity(), - "optimizer_input": optimizer_input, "executable_bundle": executable_bundle, "health_receipt": health_receipt, - "model_attestation": model_attestation, "checkpoint": checkpoint, "lineage": lineage, - "source_context": {**identity(), "kind": "source", "context": "public synthetic source evidence"}, - "reflection_context": {**identity(), "kind": "reflection", "context": "public synthetic reflection evidence"}, - } - write_json(output / "campaign-evidence.json", evidence) - overflow = await execute_overflow_probe(sha_bytes(canonical(executable_bundle).encode())) - write_json(output / "overflow-receipt.json", overflow) - tools = [{"type": "function", "function": {"name": "set-record", "description": "Mutate a public synthetic record.", "parameters": env_tool_schema()}}] - trace = { - "runtime": "standard-verifiers", "verifiers_version": vf.__version__, **identity(), - "task": {"data": {"task_id": "public-synthetic-mutation-1", "split": "train"}}, - "rewards": {"assertion_fraction": assertion}, "metrics": {"assertion_fraction": assertion}, "errors": [], "ok": True, - "calls": [{"node": 2, "model": "synthetic-local", "endpoint": "/chat/completions", "finish_reason": "tool_calls", "messages_sha256": sha_bytes(canonical(MESSAGES).encode()), "tools_sha256": sha_bytes(canonical(tools).encode()), "sampling_sha256": sha_bytes(canonical(SAMPLING).encode()), "max_tokens": 256, "context_overflow_behavior": "fail"}], - "nodes": [ - {"message": MESSAGES[0], "sampled": False}, {"parent": 0, "message": MESSAGES[1], "sampled": False}, - {"parent": 1, "message": completion.model_dump(exclude_none=True), "sampled": True}, - {"parent": 2, "message": {**result.model_dump(exclude_none=True), "name": "world_toolset_set-record"}, "sampled": False}, - ], - "execution": {"verifiers_trajectory_steps": len(state["trajectory"]), "tool_calls": tool_calls}, - } - write_json(trace_path, trace) - installed = sorted(({"name": d.metadata["Name"].lower().replace("_", "-"), "version": d.version} for d in importlib.metadata.distributions()), key=lambda x: (x["name"], x["version"])) - installed_by_name = {item["name"]: item["version"] for item in installed} - exported = subprocess.run(["uv", "export", "--project", ".", "--locked", "--format", "requirements-txt", "--no-hashes", "--no-emit-project", "--no-annotate", "--no-header"], check=True, capture_output=True, text=True).stdout - applicable = [] - for line in exported.splitlines(): - if not line.strip() or line.startswith((" ", "-")): - continue - requirement = Requirement(line.rstrip(" \\")) - if requirement.marker is not None and not requirement.marker.evaluate(default_environment()): - continue - name = requirement.name.lower().replace("_", "-") - version = installed_by_name.get(name) - if version is None: - raise RuntimeError(f"applicable locked distribution {name} is not installed") - applicable.append({"name": name, "version": version}) - applicable.sort(key=lambda x: (x["name"], x["version"])) - if installed != applicable: - raise RuntimeError("installed distributions do not equal uv-exported applicable lock inventory") - applicable_path = output / "applicable-lock.json" - write_json(applicable_path, applicable) - executable = str(Path(sys.executable).absolute()) - project_root = str(Path.cwd().resolve()) - if not executable.startswith(str(Path(project_root, ".venv").absolute()) + os.sep): - raise RuntimeError("generator is not running inside the exact project .venv") - verifiers_dist = importlib.metadata.distribution("verifiers") - direct_url = json.loads(verifiers_dist.read_text("direct_url.json") or "{}") - verifiers_commit = direct_url.get("vcs_info", {}).get("commit_id") - if not isinstance(verifiers_commit, str) or len(verifiers_commit) != 40: - raise RuntimeError("installed Verifiers distribution lacks an exact git commit") - root_name = tomllib.loads(Path("pyproject.toml").read_text(encoding="utf-8"))["project"]["name"] - receipt = { - "schema_version": "understudy.synthetic_verifiers_execution.v1", **identity(), "argv": ARGV, - "interpreter": {"implementation": platform.python_implementation(), "version": platform.python_version(), "path": str(Path(executable).relative_to(project_root)), "path_kind": "project_relative", "executable_sha256": sha_bytes(Path(executable).read_bytes())}, - "installed_distributions": installed, "installed_distributions_sha256": sha_bytes(canonical(installed).encode()), - "applicable_locked_distributions": applicable, "applicable_locked_distributions_sha256": sha_bytes(canonical(applicable).encode()), - "applicable_lock_artifact_sha256": sha_bytes(applicable_path.read_bytes()), - "root_package_name": root_name, - "lock_exclusions": [{"name": root_name, "reason": "root-non-installable-no-emit-project"}, {"reason": "platform-marker-not-applicable"}], - "verifiers": {"version": vf.__version__, "module": "verifiers", "git_revision": verifiers_commit}, - "seed_candidate_sha256": sha_bytes(SEED.encode()), "mutated_candidate_sha256": sha_bytes(CANDIDATE.encode()), - "before_state_sha256": sha_bytes(before_path.read_bytes()), "after_state_sha256": sha_bytes(after_path.read_bytes()), "trace_sha256": sha_bytes(trace_path.read_bytes()), - "assertion_fraction": assertion, "assertion_rubric": "verifiers.Rubric", "verified_state_delta": {"path": "/records/alpha/status", "before": "pending", "after": "ready", "independently_asserted": True}, - } - write_json(output / "execution-receipt.json", receipt) - - -def env_tool_schema(): - return {"type": "object", "additionalProperties": False, "required": ["id", "status"], "properties": {"id": {"type": "string"}, "status": {"enum": ["ready"]}}} - - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument("--output", default="generated") - args = parser.parse_args() - asyncio.run(generate(Path(args.output))) diff --git a/tests/fixtures/campaign-admission/uv-project/generated/execution-receipt.json b/tests/fixtures/campaign-admission/uv-project/generated/execution-receipt.json index 561e3220..ca754560 100644 --- a/tests/fixtures/campaign-admission/uv-project/generated/execution-receipt.json +++ b/tests/fixtures/campaign-admission/uv-project/generated/execution-receipt.json @@ -424,12 +424,12 @@ "uv", "run", "--project", - ".", + "", "--locked", "python", - "generate_smoke.py", + "", "--output", - "generated" + "" ], "assertion_fraction": 1.0, "assertion_rubric": "verifiers.Rubric", @@ -877,6 +877,8 @@ "schema_version": "understudy.synthetic_verifiers_execution.v1", "seed_candidate_sha256": "4dbee206fc073f8db3e50fad210ca48772e481ad31ee37f33e638bca91db1914", "trace_sha256": "fce8b5fcb3c4e6ee75d154342aa679f1a15d842e1ecfb47fd532014100cd3353", + "trusted_generator_sha256": "e49c99e33cdaaa9b82198acf2d2b342000b3e1fbaf824add561bf0e9f8d7363e", + "trusted_generator_version": "understudy.agent_tools.campaign_admission_generator.v1", "verified_state_delta": { "after": "ready", "before": "pending", diff --git a/tests/helpers/campaign-admission-fixture.mjs b/tests/helpers/campaign-admission-fixture.mjs index ccc906f1..3713eaa3 100644 --- a/tests/helpers/campaign-admission-fixture.mjs +++ b/tests/helpers/campaign-admission-fixture.mjs @@ -8,7 +8,7 @@ const sha = (value) => createHash("sha256").update(value).digest("hex"); export function baseManifest(mod, projectDir = "uv-project") { const generated = `${projectDir}/generated`; - const artifacts = { request: bytes("request.json"), response: bytes("response.json"), tools: bytes("tools.json"), trace: bytes(`${generated}/trace.json`), executionReceipt: bytes(`${generated}/execution-receipt.json`), beforeState: bytes(`${generated}/before-state.json`), afterState: bytes(`${generated}/after-state.json`), overflowReceipt: bytes(`${generated}/overflow-receipt.json`), campaignEvidence: bytes(`${generated}/campaign-evidence.json`), applicableLock: bytes(`${generated}/applicable-lock.json`) }; + const artifacts = { request: bytes("request.json"), response: bytes("response.json"), tools: bytes("tools.json"), trace: bytes(`${generated}/trace.json`), executionReceipt: bytes(`${generated}/execution-receipt.json`), beforeState: bytes(`${generated}/before-state.json`), afterState: bytes(`${generated}/after-state.json`), overflowReceipt: bytes(`${generated}/overflow-receipt.json`), campaignEvidence: bytes(`${generated}/campaign-evidence.json`), applicableLock: bytes(`${generated}/applicable-lock.json`), trustedGenerator: readFileSync(resolve("runtime-assets/campaign-admission/trusted-generator.txt")) }; const trace = JSON.parse(artifacts.trace); const receipt = JSON.parse(artifacts.executionReceipt); const request = JSON.parse(artifacts.request); @@ -18,7 +18,7 @@ export function baseManifest(mod, projectDir = "uv-project") { const lockHash = sha(bytes(`${projectDir}/uv.lock`)); const manifest = { schema_version: "understudy.campaign_admission.v1", campaign_id: request.campaign_id, workload_id: request.workload_id, request_id: request.request_id, execution_id: request.execution_id, - environment: { pyproject_sha256: sha(bytes(`${projectDir}/pyproject.toml`)), uv_lock_sha256: lockHash, uv_lock_check_command: "uv lock --check", uv_lock_check_exit_code: 0, uv_version: "0.12.1", python_version: receipt.interpreter.version, python_executable_sha256: receipt.interpreter.executable_sha256, installed_distributions_sha256: receipt.installed_distributions_sha256, applicable_lock_artifact_sha256: sha(artifacts.applicableLock), container_image_digest: `sha256:${"2".repeat(64)}`, resolved_packages: mod.parseUvLockPins(bytes(`${projectDir}/uv.lock`).toString("utf8")) }, + environment: { pyproject_sha256: sha(bytes(`${projectDir}/pyproject.toml`)), uv_lock_sha256: lockHash, uv_lock_check_command: "uv lock --check", uv_lock_check_exit_code: 0, uv_version: "0.12.1", python_version: receipt.interpreter.version, python_executable_sha256: receipt.interpreter.executable_sha256, installed_distributions_sha256: receipt.installed_distributions_sha256, applicable_lock_artifact_sha256: sha(artifacts.applicableLock), trusted_generator_sha256: sha(artifacts.trustedGenerator), container_image_digest: `sha256:${"2".repeat(64)}`, resolved_packages: mod.parseUvLockPins(bytes(`${projectDir}/uv.lock`).toString("utf8")) }, transport_fingerprints: mod.fingerprintTransport(artifacts), tool_steps: mod.fingerprintToolSteps(artifacts), payload_parity: { messages_sha256: semantic(request.messages), tools_sha256: semantic(JSON.parse(artifacts.tools)), sampling_sha256: semantic(request.sampling), context_overflow_behavior: "fail", overflow_probe_receipt_sha256: sha(artifacts.overflowReceipt) }, workload_contract: { benchmark_prompt_sha256: semantic(fixedMessages), candidate_source: "outer_system_transcript", candidate_tag_sha256: receipt.mutated_candidate_sha256, policy_injection_count: 1, verifiers_version: receipt.verifiers.version, verifiers_git_revision: receipt.verifiers.git_revision, mcp_version: "1.29.0", tool_schema_sha256: semantic(JSON.parse(artifacts.tools)), package_inventory_sha256: lockHash }, From f9bc9fe23771416f1abdfe645b8c14f8e050fba3 Mon Sep 17 00:00:00 2001 From: luis manrique <166242911+lluisinthedesert@users.noreply.github.com> Date: Tue, 4 Aug 2026 05:58:07 -0700 Subject: [PATCH 7/8] seal campaign admission public trust root --- src/campaign-admission/index.ts | 11 ++-- src/commands/campaigns.ts | 2 +- tests/campaign-admission.test.mjs | 67 ++++++++++++++++++++ tests/helpers/campaign-admission-fixture.mjs | 4 +- 4 files changed, 77 insertions(+), 7 deletions(-) diff --git a/src/campaign-admission/index.ts b/src/campaign-admission/index.ts index cff56bd6..7da012c7 100644 --- a/src/campaign-admission/index.ts +++ b/src/campaign-admission/index.ts @@ -1,6 +1,7 @@ import { createHash } from "node:crypto"; import { readFileSync } from "node:fs"; import { createRequire } from "node:module"; +import { fileURLToPath } from "node:url"; export const CAMPAIGN_ADMISSION_SCHEMA_VERSION = "understudy.campaign_admission.v1" as const; export const SPEND_LANES = ["optimizer", "endpoint", "training"] as const; @@ -19,7 +20,6 @@ export type TransportArtifacts = { overflowReceipt: Buffer; campaignEvidence: Buffer; applicableLock: Buffer; - trustedGenerator: Buffer; }; export type TransportFingerprints = { @@ -63,6 +63,8 @@ export type AdmissionResult = { export type ResolvedPackagePin = { name: string; version: string; git_revision?: string }; const SHA256 = /^[a-f0-9]{64}$/; +const TRUSTED_GENERATOR_PATH = fileURLToPath(new URL("../../runtime-assets/campaign-admission/trusted-generator.txt", import.meta.url)); +const trustedGeneratorBytes = (): Buffer => readFileSync(TRUSTED_GENERATOR_PATH); // Exact PEP 440-ish resolved versions may have one or two numeric segments, // epochs, post releases, or local suffixes; specifier operators/wildcards do // not belong in an attested resolved lock. @@ -228,7 +230,7 @@ function validateExecutionReceipt(manifest: JsonObject, artifacts: TransportArti const smoke = object(manifest.mutation_smoke); if (smoke.execution_receipt_sha256 !== sha256Bytes(artifacts.executionReceipt)) errors.push("mutation_smoke.execution_receipt_sha256 does not match supplied receipt"); if (receipt.schema_version !== "understudy.synthetic_verifiers_execution.v1") errors.push("synthetic execution receipt schema is invalid"); - if (receipt.trusted_generator_version !== "understudy.agent_tools.campaign_admission_generator.v1" || receipt.trusted_generator_sha256 !== sha256Bytes(artifacts.trustedGenerator) || receipt.trusted_generator_sha256 !== object(manifest.environment).trusted_generator_sha256) errors.push("execution evidence is not derived by the trusted agent-tools generator"); + if (receipt.trusted_generator_version !== "understudy.agent_tools.campaign_admission_generator.v1" || receipt.trusted_generator_sha256 !== sha256Bytes(trustedGeneratorBytes()) || receipt.trusted_generator_sha256 !== object(manifest.environment).trusted_generator_sha256) errors.push("execution evidence is not derived by the packaged trusted agent-tools generator"); validateIdentity(manifest, receipt, "execution receipt", errors); const argv = receipt.argv; if (canonicalize(argv) !== canonicalize(["uv", "run", "--project", "", "--locked", "python", "", "--output", ""])) errors.push("synthetic smoke must use the exact locked-project trusted-generator argv"); @@ -257,6 +259,7 @@ function validateExecutionReceipt(manifest: JsonObject, artifacts: TransportArti if (receipt.before_state_sha256 !== sha256Bytes(artifacts.beforeState) || receipt.after_state_sha256 !== sha256Bytes(artifacts.afterState)) errors.push("execution receipt does not bind before/after state"); if (receipt.seed_candidate_sha256 !== smoke.seed_candidate_sha256 || receipt.mutated_candidate_sha256 !== smoke.mutated_candidate_sha256) errors.push("candidate hashes are not bound to generated inputs"); if (receipt.assertion_rubric !== "verifiers.Rubric" || receipt.assertion_fraction !== smoke.assertion_fraction) errors.push("assertion_fraction is not bound to the executed standard-Verifiers Rubric receipt"); + if (receipt.schema_version === "understudy.synthetic_verifiers_execution.v1" && receipt.assertion_fraction !== 1) errors.push("trusted synthetic admission rubric must independently pass at 1.0"); const delta = object(receipt.verified_state_delta); if (delta.path !== "/records/alpha/status" || delta.before !== "pending" || delta.after !== "ready") errors.push("execution receipt does not verify the required state delta"); if (object(object(before.records).alpha).status !== "pending" || object(object(after.records).alpha).status !== "ready") errors.push("before/after state artifacts do not contain the verified mutation"); @@ -526,6 +529,6 @@ export function validateCampaignAdmission(manifest: unknown, artifacts: Transpor return { admission_only: true, compile_authorized: false, admitted: errors.length === 0, errors, fingerprints, tool_steps, effective_spend_caps_usd: spend.effective, cumulative_spend_usd: spend.cumulative }; } -export function readTransportArtifacts(paths: { request: string; response: string; tools: string; trace: string; executionReceipt: string; beforeState: string; afterState: string; overflowReceipt: string; campaignEvidence: string; applicableLock: string; trustedGenerator: string }): TransportArtifacts { - return { request: readFileSync(paths.request), response: readFileSync(paths.response), tools: readFileSync(paths.tools), trace: readFileSync(paths.trace), executionReceipt: readFileSync(paths.executionReceipt), beforeState: readFileSync(paths.beforeState), afterState: readFileSync(paths.afterState), overflowReceipt: readFileSync(paths.overflowReceipt), campaignEvidence: readFileSync(paths.campaignEvidence), applicableLock: readFileSync(paths.applicableLock), trustedGenerator: readFileSync(paths.trustedGenerator) }; +export function readTransportArtifacts(paths: { request: string; response: string; tools: string; trace: string; executionReceipt: string; beforeState: string; afterState: string; overflowReceipt: string; campaignEvidence: string; applicableLock: string }): TransportArtifacts { + return { request: readFileSync(paths.request), response: readFileSync(paths.response), tools: readFileSync(paths.tools), trace: readFileSync(paths.trace), executionReceipt: readFileSync(paths.executionReceipt), beforeState: readFileSync(paths.beforeState), afterState: readFileSync(paths.afterState), overflowReceipt: readFileSync(paths.overflowReceipt), campaignEvidence: readFileSync(paths.campaignEvidence), applicableLock: readFileSync(paths.applicableLock) }; } diff --git a/src/commands/campaigns.ts b/src/commands/campaigns.ts index ba8b52bd..54208bee 100644 --- a/src/commands/campaigns.ts +++ b/src/commands/campaigns.ts @@ -52,7 +52,7 @@ export function registerCampaignsCommand(program: Command): void { const generatedDir = mkdtempSync(join(tmpdir(), "understudy-trusted-admission-")); execFileSync("uv", ["run", "--project", project, "--locked", "python", generator, "--output", generatedDir], { cwd: project, stdio: "pipe" }); for (const [generated] of comparisons) if (!readFileSync(join(generatedDir, generated)).equals(expected.get(generated)!)) throw new Error(`trusted agent-tools derivation rejects supplied ${generated}`); - const result = validateCampaignAdmission(manifest, readTransportArtifacts({ request: resolve(options.request), response: resolve(options.response), tools: resolve(options.tools), trace: resolve(options.trace), executionReceipt: resolve(options.executionReceipt), beforeState: resolve(options.beforeState), afterState: resolve(options.afterState), overflowReceipt: resolve(options.overflowReceipt), campaignEvidence: resolve(options.campaignEvidence), applicableLock: resolve(options.applicableLock), trustedGenerator: generator })); + const result = validateCampaignAdmission(manifest, readTransportArtifacts({ request: resolve(options.request), response: resolve(options.response), tools: resolve(options.tools), trace: resolve(options.trace), executionReceipt: resolve(options.executionReceipt), beforeState: resolve(options.beforeState), afterState: resolve(options.afterState), overflowReceipt: resolve(options.overflowReceipt), campaignEvidence: resolve(options.campaignEvidence), applicableLock: resolve(options.applicableLock) })); rmSync(generatedDir, { recursive: true, force: true }); process.stdout.write(`${JSON.stringify(result, null, 2)}\n`); if (!result.admitted) process.exitCode = 1; diff --git a/tests/campaign-admission.test.mjs b/tests/campaign-admission.test.mjs index 89904e84..21141cf3 100644 --- a/tests/campaign-admission.test.mjs +++ b/tests/campaign-admission.test.mjs @@ -1,4 +1,7 @@ import assert from "node:assert/strict"; +import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join, resolve } from "node:path"; import { describe, it } from "node:test"; import { baseManifest } from "./helpers/campaign-admission-fixture.mjs"; @@ -16,6 +19,70 @@ describe("campaign admission", () => { assert.equal(result.tool_steps[0].mutation, true); }); + it("rejects direct-library trusted-generator byte and path substitution", async () => { + const mod = await import("../dist/campaign-admission/index.js"); + const fake = Buffer.from("coherent but untrusted generator\n"); + const fakeHash = mod.sha256Bytes(fake); + { + const { manifest, artifacts } = baseManifest(mod); + const receipt = JSON.parse(artifacts.executionReceipt); + receipt.trusted_generator_sha256 = fakeHash; + const changed = { ...artifacts, trustedGenerator: fake, executionReceipt: Buffer.from(`${JSON.stringify(receipt)}\n`) }; + manifest.environment.trusted_generator_sha256 = fakeHash; + manifest.mutation_smoke.execution_receipt_sha256 = mod.sha256Bytes(changed.executionReceipt); + const result = mod.validateCampaignAdmission(manifest, changed); + assert.equal(result.admitted, false); + assert.match(result.errors.join("\n"), /packaged trusted agent-tools generator/); + } + const temporary = mkdtempSync(join(tmpdir(), "campaign-admission-substitution-")); + try { + const fakePath = join(temporary, "generator.txt"); + writeFileSync(fakePath, fake); + const fixture = resolve("tests/fixtures/campaign-admission"); + const paths = { + request: join(fixture, "request.json"), response: join(fixture, "response.json"), tools: join(fixture, "tools.json"), + trace: join(fixture, "uv-project/generated/trace.json"), executionReceipt: join(fixture, "uv-project/generated/execution-receipt.json"), + beforeState: join(fixture, "uv-project/generated/before-state.json"), afterState: join(fixture, "uv-project/generated/after-state.json"), + overflowReceipt: join(fixture, "uv-project/generated/overflow-receipt.json"), campaignEvidence: join(fixture, "uv-project/generated/campaign-evidence.json"), + applicableLock: join(fixture, "uv-project/generated/applicable-lock.json"), trustedGenerator: fakePath, + }; + const artifacts = mod.readTransportArtifacts(paths); + assert.equal(Object.hasOwn(artifacts, "trustedGenerator"), false); + const { manifest } = baseManifest(mod); + const receipt = JSON.parse(artifacts.executionReceipt); + receipt.trusted_generator_sha256 = fakeHash; + artifacts.executionReceipt = Buffer.from(`${JSON.stringify(receipt)}\n`); + manifest.environment.trusted_generator_sha256 = fakeHash; + manifest.mutation_smoke.execution_receipt_sha256 = mod.sha256Bytes(artifacts.executionReceipt); + const result = mod.validateCampaignAdmission(manifest, artifacts); + assert.equal(result.admitted, false); + assert.match(result.errors.join("\n"), /packaged trusted agent-tools generator/); + } finally { + rmSync(temporary, { recursive: true, force: true }); + } + }); + + it("rejects coherent direct-library fabrication of metric, manifest, and receipt", async () => { + const mod = await import("../dist/campaign-admission/index.js"); + const { manifest, artifacts } = baseManifest(mod); + const trace = JSON.parse(artifacts.trace); + trace.metrics.assertion_fraction = 0.5; + trace.rewards.assertion_fraction = 0.5; + const changed = { ...artifacts, trace: Buffer.from(`${JSON.stringify(trace)}\n`) }; + const receipt = JSON.parse(artifacts.executionReceipt); + receipt.assertion_fraction = 0.5; + receipt.trace_sha256 = mod.sha256Bytes(changed.trace); + changed.executionReceipt = Buffer.from(`${JSON.stringify(receipt)}\n`); + manifest.transport_fingerprints = mod.fingerprintTransport(changed); + manifest.tool_steps = mod.fingerprintToolSteps(changed); + manifest.mutation_smoke.assertion_fraction = 0.5; + manifest.mutation_smoke.trace_artifact_sha256 = mod.sha256Bytes(changed.trace); + manifest.mutation_smoke.execution_receipt_sha256 = mod.sha256Bytes(changed.executionReceipt); + const result = mod.validateCampaignAdmission(manifest, changed); + assert.equal(result.admitted, false); + assert.match(result.errors.join("\n"), /trusted synthetic admission rubric must independently pass at 1\.0/); + }); + it("rejects whitespace-only raw argument drift even when semantics match", async () => { const mod = await import("../dist/campaign-admission/index.js"); const { manifest, artifacts } = baseManifest(mod); diff --git a/tests/helpers/campaign-admission-fixture.mjs b/tests/helpers/campaign-admission-fixture.mjs index 3713eaa3..704c36f4 100644 --- a/tests/helpers/campaign-admission-fixture.mjs +++ b/tests/helpers/campaign-admission-fixture.mjs @@ -8,7 +8,7 @@ const sha = (value) => createHash("sha256").update(value).digest("hex"); export function baseManifest(mod, projectDir = "uv-project") { const generated = `${projectDir}/generated`; - const artifacts = { request: bytes("request.json"), response: bytes("response.json"), tools: bytes("tools.json"), trace: bytes(`${generated}/trace.json`), executionReceipt: bytes(`${generated}/execution-receipt.json`), beforeState: bytes(`${generated}/before-state.json`), afterState: bytes(`${generated}/after-state.json`), overflowReceipt: bytes(`${generated}/overflow-receipt.json`), campaignEvidence: bytes(`${generated}/campaign-evidence.json`), applicableLock: bytes(`${generated}/applicable-lock.json`), trustedGenerator: readFileSync(resolve("runtime-assets/campaign-admission/trusted-generator.txt")) }; + const artifacts = { request: bytes("request.json"), response: bytes("response.json"), tools: bytes("tools.json"), trace: bytes(`${generated}/trace.json`), executionReceipt: bytes(`${generated}/execution-receipt.json`), beforeState: bytes(`${generated}/before-state.json`), afterState: bytes(`${generated}/after-state.json`), overflowReceipt: bytes(`${generated}/overflow-receipt.json`), campaignEvidence: bytes(`${generated}/campaign-evidence.json`), applicableLock: bytes(`${generated}/applicable-lock.json`) }; const trace = JSON.parse(artifacts.trace); const receipt = JSON.parse(artifacts.executionReceipt); const request = JSON.parse(artifacts.request); @@ -18,7 +18,7 @@ export function baseManifest(mod, projectDir = "uv-project") { const lockHash = sha(bytes(`${projectDir}/uv.lock`)); const manifest = { schema_version: "understudy.campaign_admission.v1", campaign_id: request.campaign_id, workload_id: request.workload_id, request_id: request.request_id, execution_id: request.execution_id, - environment: { pyproject_sha256: sha(bytes(`${projectDir}/pyproject.toml`)), uv_lock_sha256: lockHash, uv_lock_check_command: "uv lock --check", uv_lock_check_exit_code: 0, uv_version: "0.12.1", python_version: receipt.interpreter.version, python_executable_sha256: receipt.interpreter.executable_sha256, installed_distributions_sha256: receipt.installed_distributions_sha256, applicable_lock_artifact_sha256: sha(artifacts.applicableLock), trusted_generator_sha256: sha(artifacts.trustedGenerator), container_image_digest: `sha256:${"2".repeat(64)}`, resolved_packages: mod.parseUvLockPins(bytes(`${projectDir}/uv.lock`).toString("utf8")) }, + environment: { pyproject_sha256: sha(bytes(`${projectDir}/pyproject.toml`)), uv_lock_sha256: lockHash, uv_lock_check_command: "uv lock --check", uv_lock_check_exit_code: 0, uv_version: "0.12.1", python_version: receipt.interpreter.version, python_executable_sha256: receipt.interpreter.executable_sha256, installed_distributions_sha256: receipt.installed_distributions_sha256, applicable_lock_artifact_sha256: sha(artifacts.applicableLock), trusted_generator_sha256: receipt.trusted_generator_sha256, container_image_digest: `sha256:${"2".repeat(64)}`, resolved_packages: mod.parseUvLockPins(bytes(`${projectDir}/uv.lock`).toString("utf8")) }, transport_fingerprints: mod.fingerprintTransport(artifacts), tool_steps: mod.fingerprintToolSteps(artifacts), payload_parity: { messages_sha256: semantic(request.messages), tools_sha256: semantic(JSON.parse(artifacts.tools)), sampling_sha256: semantic(request.sampling), context_overflow_behavior: "fail", overflow_probe_receipt_sha256: sha(artifacts.overflowReceipt) }, workload_contract: { benchmark_prompt_sha256: semantic(fixedMessages), candidate_source: "outer_system_transcript", candidate_tag_sha256: receipt.mutated_candidate_sha256, policy_injection_count: 1, verifiers_version: receipt.verifiers.version, verifiers_git_revision: receipt.verifiers.git_revision, mcp_version: "1.29.0", tool_schema_sha256: semantic(JSON.parse(artifacts.tools)), package_inventory_sha256: lockHash }, From a1da9822a0ff9ffa276c893be03a347c854d6212 Mon Sep 17 00:00:00 2001 From: luis manrique <166242911+lluisinthedesert@users.noreply.github.com> Date: Tue, 4 Aug 2026 06:26:29 -0700 Subject: [PATCH 8/8] add strict exact promotion gate --- ...understudy.strict_promotion.v1.schema.json | 50 +++++++++++ scripts/package-smoke.mjs | 1 + src/campaign-admission/index.ts | 2 + src/campaign-admission/strict-promotion.ts | 83 +++++++++++++++++ src/index.ts | 3 + tests/campaign-strict-promotion.test.mjs | 88 +++++++++++++++++++ 6 files changed, 227 insertions(+) create mode 100644 schemas/understudy.strict_promotion.v1.schema.json create mode 100644 src/campaign-admission/strict-promotion.ts create mode 100644 tests/campaign-strict-promotion.test.mjs diff --git a/schemas/understudy.strict_promotion.v1.schema.json b/schemas/understudy.strict_promotion.v1.schema.json new file mode 100644 index 00000000..48756199 --- /dev/null +++ b/schemas/understudy.strict_promotion.v1.schema.json @@ -0,0 +1,50 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://understudylabs.com/schemas/understudy.strict_promotion.v1.schema.json", + "title": "understudy.strict_promotion.v1", + "type": "object", + "additionalProperties": false, + "required": ["schema_version", "campaign_id", "workload_id", "candidate_id", "parent_ids", "trusted_scorer_contract_sha256", "named_preimages", "scorer_exception_count", "rows", "prompt_bearing_artifacts"], + "properties": { + "schema_version": { "const": "understudy.strict_promotion.v1" }, + "campaign_id": { "type": "string", "minLength": 1 }, + "workload_id": { "type": "string", "minLength": 1 }, + "candidate_id": { "type": "string", "minLength": 1 }, + "parent_ids": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string", "minLength": 1 } }, + "trusted_scorer_contract_sha256": { "$ref": "#/$defs/sha" }, + "named_preimages": { + "type": "object", "additionalProperties": false, + "required": ["taskset", "harness", "scorer", "terminal", "export", "promotion", "model", "checkpoint", "dspy"], + "properties": { + "taskset": { "$ref": "#/$defs/sha" }, "harness": { "$ref": "#/$defs/sha" }, "scorer": { "$ref": "#/$defs/sha" }, + "terminal": { "$ref": "#/$defs/sha" }, "export": { "$ref": "#/$defs/sha" }, "promotion": { "$ref": "#/$defs/sha" }, + "model": { "$ref": "#/$defs/sha" }, "checkpoint": { "$ref": "#/$defs/sha" }, "dspy": { "$ref": "#/$defs/sha" } + } + }, + "scorer_exception_count": { "type": "integer", "minimum": 0 }, + "rows": { "type": "array", "minItems": 2, "items": { "$ref": "#/$defs/row" } }, + "prompt_bearing_artifacts": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/private_artifact" } } + }, + "$defs": { + "sha": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, + "row": { + "type": "object", "additionalProperties": false, + "required": ["candidate_id", "task_id", "candidate_prompt_sha256", "evaluated_prompt_sha256", "strict_exact", "dense_score", "canonical_row_sha256", "physical_row_sha256", "external_receipt"], + "properties": { + "candidate_id": { "type": "string", "minLength": 1 }, "task_id": { "type": "string", "minLength": 1 }, + "candidate_prompt_sha256": { "$ref": "#/$defs/sha" }, "evaluated_prompt_sha256": { "$ref": "#/$defs/sha" }, + "strict_exact": { "type": "boolean" }, "dense_score": { "type": "number" }, + "canonical_row_sha256": { "$ref": "#/$defs/sha" }, "physical_row_sha256": { "$ref": "#/$defs/sha" }, + "external_receipt": { "type": "object", "additionalProperties": false, "required": ["redacted", "contains_prompt"], "properties": { "redacted": { "const": true }, "contains_prompt": { "const": false } } } + } + }, + "private_artifact": { + "type": "object", "additionalProperties": false, + "required": ["name", "sha256", "classification", "contains_prompt", "externalized"], + "properties": { + "name": { "type": "string", "minLength": 1 }, "sha256": { "$ref": "#/$defs/sha" }, + "classification": { "const": "private_cas" }, "contains_prompt": { "const": true }, "externalized": { "const": false } + } + } + } +} diff --git a/scripts/package-smoke.mjs b/scripts/package-smoke.mjs index 7c3e20be..1a2a93b0 100644 --- a/scripts/package-smoke.mjs +++ b/scripts/package-smoke.mjs @@ -48,6 +48,7 @@ const requiredPackageMembers = [ "skills/recursive-language-model/SKILL.md", "skills/recursive-language-model/references/pedagogical-training.md", "runtime-assets/campaign-admission/trusted-generator.txt", + "schemas/understudy.strict_promotion.v1.schema.json", ]; function npmPackFiles() { diff --git a/src/campaign-admission/index.ts b/src/campaign-admission/index.ts index 7da012c7..ad6258c0 100644 --- a/src/campaign-admission/index.ts +++ b/src/campaign-admission/index.ts @@ -3,6 +3,8 @@ import { readFileSync } from "node:fs"; import { createRequire } from "node:module"; import { fileURLToPath } from "node:url"; +export { validateStrictPromotion, type StrictPromotionArtifacts, type StrictPromotionResult } from "./strict-promotion.js"; + export const CAMPAIGN_ADMISSION_SCHEMA_VERSION = "understudy.campaign_admission.v1" as const; export const SPEND_LANES = ["optimizer", "endpoint", "training"] as const; diff --git a/src/campaign-admission/strict-promotion.ts b/src/campaign-admission/strict-promotion.ts new file mode 100644 index 00000000..9ccb49ba --- /dev/null +++ b/src/campaign-admission/strict-promotion.ts @@ -0,0 +1,83 @@ +import { createHash } from "node:crypto"; +import { readFileSync } from "node:fs"; +import { createRequire } from "node:module"; + +type JsonObject = Record; +export type StrictPromotionResult = { decision: "PROMOTE" | "HOLD"; errors: string[]; candidate_strict_exact: number; parent_strict_exact: Record; paired: Record }; +export type StrictPromotionArtifacts = { + trustedScorerContract: Buffer; + expectedTrustedScorerContractSha256: string; + namedPreimages: Record<"taskset" | "harness" | "scorer" | "terminal" | "export" | "promotion" | "model" | "checkpoint" | "dspy", Buffer>; + expectedNamedPreimageSha256: Record<"taskset" | "harness" | "scorer" | "terminal" | "export" | "promotion" | "model" | "checkpoint" | "dspy", string>; + rowPreimages: Record; +}; + +const require = createRequire(import.meta.url); +const Ajv2020 = require("ajv/dist/2020").default as new (options: Record) => { compile: (schema: unknown) => ((value: unknown) => boolean) & { errors?: { instancePath: string; message?: string; keyword: string }[] | null } }; +const schema = JSON.parse(readFileSync(new URL("../../schemas/understudy.strict_promotion.v1.schema.json", import.meta.url), "utf8")); +const validateSchema = new Ajv2020({ allErrors: true, strict: true }).compile(schema); +const sha = (value: Uint8Array): string => createHash("sha256").update(value).digest("hex"); +const object = (value: unknown): JsonObject => value !== null && typeof value === "object" && !Array.isArray(value) ? value as JsonObject : {}; + +export function validateStrictPromotion(evidence: unknown, artifacts: StrictPromotionArtifacts): StrictPromotionResult { + const value = object(evidence); + const errors = validateSchema(value) ? [] : (validateSchema.errors ?? []).map((error) => `schema${error.instancePath || "/"}: ${error.message ?? error.keyword}`); + const scorerHash = sha(artifacts.trustedScorerContract); + if (value.trusted_scorer_contract_sha256 !== scorerHash || scorerHash !== artifacts.expectedTrustedScorerContractSha256) errors.push("trusted scorer contract hash does not match independently expected scorer-contract preimage"); + const declared = object(value.named_preimages); + for (const [name, bytes] of Object.entries(artifacts.namedPreimages)) if (declared[name] !== sha(bytes) || sha(bytes) !== artifacts.expectedNamedPreimageSha256[name as keyof typeof artifacts.expectedNamedPreimageSha256]) errors.push(`named preimage ${name} hash mismatch`); + let expectedTasks: string[] = []; + try { + const taskset = object(JSON.parse(artifacts.namedPreimages.taskset.toString("utf8"))); + expectedTasks = Array.isArray(taskset.dev_task_ids) ? taskset.dev_task_ids.filter((item): item is string => typeof item === "string").sort() : []; + } catch { errors.push("taskset preimage must be valid JSON with dev_task_ids"); } + if (expectedTasks.length === 0 || new Set(expectedTasks).size !== expectedTasks.length) errors.push("taskset preimage must name a unique non-empty complete dev task set"); + for (const name of ["model", "checkpoint", "dspy"] as const) { + try { + const identity = object(JSON.parse(artifacts.namedPreimages[name].toString("utf8"))); + if (identity.kind !== name || typeof identity.id !== "string" || identity.id.length === 0 || typeof identity.revision !== "string" || identity.revision.length === 0) errors.push(`${name} preimage lacks exact kind/id/revision identity`); + } catch { errors.push(`${name} preimage must be valid identity JSON`); } + } + if (value.scorer_exception_count !== 0) errors.push("scorer_exception_count must equal zero"); + + const candidate = typeof value.candidate_id === "string" ? value.candidate_id : ""; + const parents = Array.isArray(value.parent_ids) ? value.parent_ids.filter((item): item is string => typeof item === "string") : []; + const rows = Array.isArray(value.rows) ? value.rows.map(object) : []; + const byCandidate = new Map>(); + for (const row of rows) { + const id = typeof row.candidate_id === "string" ? row.candidate_id : ""; + const task = typeof row.task_id === "string" ? row.task_id : ""; + const tasks = byCandidate.get(id) ?? new Map(); + if (tasks.has(task)) errors.push(`duplicate task ${task} for candidate ${id}`); + tasks.set(task, row); byCandidate.set(id, tasks); + if (row.candidate_prompt_sha256 !== row.evaluated_prompt_sha256) errors.push(`prompt hash mismatch for ${id}/${task}`); + const rowPreimage = artifacts.rowPreimages[`${id}/${task}`]; + if (!rowPreimage || row.canonical_row_sha256 !== sha(rowPreimage.canonical) || row.physical_row_sha256 !== sha(rowPreimage.physical)) errors.push(`canonical/physical row hashes do not match supplied preimages for ${id}/${task}`); + } + const candidateTasks = byCandidate.get(candidate) ?? new Map(); + if (candidateTasks.size === 0) errors.push("candidate has no complete dev rows"); + const candidateTaskIds = [...candidateTasks.keys()].sort(); + if (JSON.stringify(candidateTaskIds) !== JSON.stringify(expectedTasks)) errors.push("candidate does not contain the exact complete dev taskset from the trusted taskset preimage"); + const strictCount = [...candidateTasks.values()].filter((row) => row.strict_exact === true).length; + const parentCounts: Record = {}; + const paired: StrictPromotionResult["paired"] = {}; + for (const parent of parents) { + const parentTasks = byCandidate.get(parent) ?? new Map(); + if (JSON.stringify([...parentTasks.keys()].sort()) !== JSON.stringify(candidateTaskIds)) errors.push(`parent ${parent} does not have the same complete dev task IDs exactly once`); + let wins = 0, losses = 0, ties = 0; + for (const task of candidateTaskIds) { + const left = candidateTasks.get(task)?.strict_exact === true ? 1 : 0; + const right = parentTasks.get(task)?.strict_exact === true ? 1 : 0; + if (left > right) wins++; else if (left < right) losses++; else ties++; + } + parentCounts[parent] = [...parentTasks.values()].filter((row) => row.strict_exact === true).length; + paired[parent] = { wins, losses, ties }; + if (strictCount <= parentCounts[parent]) errors.push(`candidate strict-exact count must exceed parent ${parent}`); + } + for (const id of byCandidate.keys()) if (id !== candidate && !parents.includes(id)) errors.push(`unexpected candidate rows for ${id}`); + const privateArtifacts = Array.isArray(value.prompt_bearing_artifacts) ? value.prompt_bearing_artifacts.map(object) : []; + if (!privateArtifacts.some((item) => item.name === "evaluation_evidence")) errors.push("evaluation_evidence must be classified as prompt-bearing private CAS"); + if (!privateArtifacts.some((item) => item.name === "candidate_persistence_payload")) errors.push("candidate_persistence_payload must be classified as prompt-bearing private CAS"); + for (const item of privateArtifacts) if (item.classification !== "private_cas" || item.contains_prompt !== true || item.externalized !== false) errors.push(`prompt-bearing artifact ${String(item.name)} must remain private CAS and not externalize`); + return { decision: errors.length === 0 ? "PROMOTE" : "HOLD", errors, candidate_strict_exact: strictCount, parent_strict_exact: parentCounts, paired }; +} diff --git a/src/index.ts b/src/index.ts index 6e746ae7..3b38b520 100644 --- a/src/index.ts +++ b/src/index.ts @@ -127,12 +127,15 @@ export { semanticJsonSha256, sha256Bytes as sha256CampaignAdmissionBytes, validateCampaignAdmission, + validateStrictPromotion, type AdmissionResult, type SpendLane, type TransportArtifacts, type TransportFingerprints, type ToolStepFingerprint, type ResolvedPackagePin, + type StrictPromotionArtifacts, + type StrictPromotionResult, } from "./campaign-admission/index.js"; export const repoRoot = installedPackageRoot(); diff --git a/tests/campaign-strict-promotion.test.mjs b/tests/campaign-strict-promotion.test.mjs new file mode 100644 index 00000000..4533e111 --- /dev/null +++ b/tests/campaign-strict-promotion.test.mjs @@ -0,0 +1,88 @@ +import assert from "node:assert/strict"; +import { createHash } from "node:crypto"; +import { describe, it } from "node:test"; + +const sha = (value) => createHash("sha256").update(value).digest("hex"); +const bytes = (name) => Buffer.from(`public synthetic ${name} preimage\n`); + +function fixture() { + const names = ["taskset", "harness", "scorer", "terminal", "export", "promotion", "model", "checkpoint", "dspy"]; + const namedPreimages = Object.fromEntries(names.map((name) => [name, bytes(name)])); + namedPreimages.taskset = Buffer.from(JSON.stringify({ split: "dev", dev_task_ids: ["dev-1", "dev-2"] })); + for (const name of ["model", "checkpoint", "dspy"]) namedPreimages[name] = Buffer.from(JSON.stringify({ kind: name, id: `public-${name}`, revision: "v1" })); + const trustedScorerContract = Buffer.from(JSON.stringify({ schema_version: "public.generic_strict_scorer.v1", semantics: "workload-supplied exact terminal outcome", strict_field: "strict_exact" })); + const rowPreimages = {}; + const row = (candidate_id, task_id, strict_exact, dense_score) => { + const prompt = sha(Buffer.from(`${candidate_id}:${task_id}:prompt`)); + const key = `${candidate_id}/${task_id}`; + rowPreimages[key] = { canonical: Buffer.from(`${candidate_id}:${task_id}:canonical`), physical: Buffer.from(`${candidate_id}:${task_id}:physical`) }; + return { candidate_id, task_id, candidate_prompt_sha256: prompt, evaluated_prompt_sha256: prompt, strict_exact, dense_score, canonical_row_sha256: sha(rowPreimages[key].canonical), physical_row_sha256: sha(rowPreimages[key].physical), external_receipt: { redacted: true, contains_prompt: false } }; + }; + const evidence = { + schema_version: "understudy.strict_promotion.v1", campaign_id: "campaign-public", workload_id: "workload-public", candidate_id: "candidate", parent_ids: ["parent-a", "parent-b"], + trusted_scorer_contract_sha256: sha(trustedScorerContract), named_preimages: Object.fromEntries(names.map((name) => [name, sha(namedPreimages[name])])), scorer_exception_count: 0, + rows: [row("candidate", "dev-1", true, 0.9), row("candidate", "dev-2", true, 0.8), row("parent-a", "dev-1", true, 0.4), row("parent-a", "dev-2", false, 0.7), row("parent-b", "dev-1", false, 0.8), row("parent-b", "dev-2", true, 0.5)], + prompt_bearing_artifacts: [{ name: "evaluation_evidence", sha256: sha(bytes("evaluation")), classification: "private_cas", contains_prompt: true, externalized: false }, { name: "candidate_persistence_payload", sha256: sha(bytes("policy")), classification: "private_cas", contains_prompt: true, externalized: false }], + }; + return { evidence, artifacts: { trustedScorerContract, expectedTrustedScorerContractSha256: sha(trustedScorerContract), namedPreimages, expectedNamedPreimageSha256: Object.fromEntries(names.map((name) => [name, sha(namedPreimages[name])])), rowPreimages } }; +} + +describe("strict promotion contract", () => { + it("promotes only a strict-exact winner over every parent with paired receipts", async () => { + const { validateStrictPromotion } = await import("../dist/campaign-admission/index.js"); + const { evidence, artifacts } = fixture(); + const result = validateStrictPromotion(evidence, artifacts); + assert.equal(result.decision, "PROMOTE", result.errors.join("\n")); + assert.deepEqual(result.paired["parent-a"], { wins: 1, losses: 0, ties: 1 }); + }); + + it("holds dense-only gain without strict gain", async () => { + const { validateStrictPromotion } = await import("../dist/campaign-admission/index.js"); + const { evidence, artifacts } = fixture(); + evidence.rows.find((row) => row.candidate_id === "candidate" && row.task_id === "dev-2").strict_exact = false; + evidence.rows.filter((row) => row.candidate_id === "candidate").forEach((row) => { row.dense_score = 1; }); + const result = validateStrictPromotion(evidence, artifacts); + assert.equal(result.decision, "HOLD"); + assert.match(result.errors.join("\n"), /strict-exact count must exceed/); + }); + + it("holds scorer exceptions, missing or duplicate tasks, and prompt mismatch", async () => { + const { validateStrictPromotion } = await import("../dist/campaign-admission/index.js"); + for (const mutate of [ + (e) => { e.scorer_exception_count = 1; }, + (e) => { e.rows = e.rows.filter((row) => !(row.candidate_id === "parent-a" && row.task_id === "dev-2")); }, + (e) => { e.rows.push({ ...e.rows.find((row) => row.candidate_id === "parent-a" && row.task_id === "dev-1") }); }, + (e) => { e.rows[0].evaluated_prompt_sha256 = "f".repeat(64); }, + ]) { + const { evidence, artifacts } = fixture(); mutate(evidence); + assert.equal(validateStrictPromotion(evidence, artifacts).decision, "HOLD"); + } + }); + + it("requires exact named preimages and prompt-bearing private-CAS classification", async () => { + const { validateStrictPromotion } = await import("../dist/campaign-admission/index.js"); + { + const { evidence, artifacts } = fixture(); + artifacts.trustedScorerContract = Buffer.from(JSON.stringify({ schema_version: "attacker.v1", strict_field: "dense_score" })); + evidence.trusted_scorer_contract_sha256 = sha(artifacts.trustedScorerContract); + const result = validateStrictPromotion(evidence, artifacts); + assert.equal(result.decision, "HOLD"); assert.match(result.errors.join("\n"), /independently expected scorer-contract/); + } + { + const { evidence, artifacts } = fixture(); artifacts.namedPreimages.model = bytes("other-model"); + const result = validateStrictPromotion(evidence, artifacts); + assert.equal(result.decision, "HOLD"); assert.match(result.errors.join("\n"), /named preimage model/); + } + { + const { evidence, artifacts } = fixture(); artifacts.rowPreimages["candidate/dev-1"].physical = bytes("other-row"); + const result = validateStrictPromotion(evidence, artifacts); + assert.equal(result.decision, "HOLD"); assert.match(result.errors.join("\n"), /canonical\/physical row hashes/); + } + { + const { evidence, artifacts } = fixture(); + evidence.prompt_bearing_artifacts.find((item) => item.name === "candidate_persistence_payload").externalized = true; + const result = validateStrictPromotion(evidence, artifacts); + assert.equal(result.decision, "HOLD"); assert.match(result.errors.join("\n"), /private CAS|externalized/); + } + }); +});