cmpnd 0.86.0__tar.gz → 0.86.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cmpnd-0.86.0 → cmpnd-0.86.1}/PKG-INFO +1 -1
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/callback.py +4 -28
- {cmpnd-0.86.0 → cmpnd-0.86.1}/docs/sdk-instrumentation.md +2 -2
- {cmpnd-0.86.0 → cmpnd-0.86.1}/pyproject.toml +1 -1
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_lm_usage_shapes.py +0 -70
- cmpnd-0.86.1/tests/test_token_attribution.py +122 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/uv.lock +1 -1
- {cmpnd-0.86.0 → cmpnd-0.86.1}/.gitignore +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/AGENTS.md +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/CLAUDE.md +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/README.md +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/__init__.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/_assessments.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/_authored_import.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/_deployments.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/_exporter_pool.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/_gepa_patch.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/_http.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/_program_patch.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/_rlm_patch.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/_runtime_tools.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/_timespec.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/_traces.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/_valsets.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/authored.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/__init__.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/api_client.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/commands/__init__.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/commands/admin.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/commands/assessments.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/commands/auth.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/commands/datasets.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/commands/deployments.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/commands/evals.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/commands/login.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/commands/optimizations.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/commands/org.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/commands/programs.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/commands/provider_credentials.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/commands/tool_servers.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/commands/top.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/commands/traces.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/commands/valsets.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/credentials.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/deprecation.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/pagination.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/shell.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/trace_render.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/tree_help.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/verbs.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/cli/views.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/client.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/configuration.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/context.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/credentials.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/dataset_sync.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/datasets.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/decorators.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/deployment.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/deployment_metadata.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/deployment_runs.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/eval_handler.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/execution.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/exporter.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/exporter_http.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/helpers.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/identity.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/imaging.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/ir/__init__.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/ir/decode.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/ir/encode.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/ir/hash.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/ir/program.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/ir/reflection.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/ir/types.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/ir/xxh64.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/lm_configuration.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/mcp_servers.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/models.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/named_programs.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/optimization.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/optimizers/__init__.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/optimizers/gepa.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/optimizers/gepa_callback.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/optimizers/resume.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/optimizers/tracker.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/packaging.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/program_naming.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/programs.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/references.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/retry.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/cmpnd/traces.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/docs/2026-04-02-code-review.md +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/docs/cli.md +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/docs/client.md +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/docs/custom-proposer.md +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/docs/plans/2026-04-05-train-val-dataset-capture-design.md +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/docs/plans/2026-04-05-train-val-dataset-capture.md +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/docs/reading-traces.md +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/examples/generalizing_proposer.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/examples/local_ollama.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/ingest/LINEAGE.md +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/ingest/README.md +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/ingest/cmpnd_ingest/__init__.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/ingest/cmpnd_ingest/bodies.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/ingest/cmpnd_ingest/client_floor.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/ingest/cmpnd_ingest/exporter_http.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/ingest/cmpnd_ingest/program_names.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/ingest/cmpnd_ingest/protocols.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/ingest/cmpnd_ingest/py.typed +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/ingest/cmpnd_ingest/request_log.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/ingest/cmpnd_ingest/retry.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/ingest/cmpnd_ingest/span_context.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/ingest/cmpnd_ingest/trace_facts.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/ingest/cmpnd_ingest/user_agent.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/ingest/pyproject.toml +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/scripts/audit-sdist.sh +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/scripts/capture_review_run.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/scripts/check-pip-install.sh +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/scripts/check_release_artifacts.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/scripts/fixtures/review_run.json.gz +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/scripts/gepa_resume_bug.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/scripts/install-test-env.sh +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/scripts/release-gate.sh +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/scripts/release-real-models.sh +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/scripts/require_version_bump.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/scripts/seed_review_run.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/scripts/selfhost_compat.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/scripts/test-in-linux.sh +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/stubs/dspy/__init__.pyi +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/stubs/dspy/primitives/__init__.pyi +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/stubs/dspy/primitives/prediction.pyi +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/stubs/dspy/utils/__init__.pyi +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/stubs/dspy/utils/callback.pyi +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/stubs/dspy/utils/dummies.pyi +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/__init__.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/_credential_route.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/_deployment_signature_helpers.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/_exporter_helpers.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/_fake_clock.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/_identity_helpers.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/_resolve_refs.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/_traced_run.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/conftest.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/__init__.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/committee_task.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/conftest.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/continuation_task.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/data/committee_train.ndjson.gz +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/data/committee_val.ndjson.gz +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/fake_lm.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/helpers.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/target_capabilities.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_assessments_cli.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_capture_prompts.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_composite_module.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_dataset_auto_creation.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_deploy_execute.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_deploy_pandas.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_deploy_programs.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_edge_cases.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_example_hash.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_gepa_optimization.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_interpreter_spans.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_lm_accuracy.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_module_tracing.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_optimization_lineage.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_optimization_metric_identity.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_optimize_authored_metric.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_optimize_continuation.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_optimize_custom_proposer.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_optimize_failures.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_optimize_loop.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_optimize_review_committee.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_optimize_server_owned_completion.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_parallel_export.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_project_attribution.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_react_tool_spans.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_save_load.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_trace_structure.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_traces_read.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_user_attribution.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/e2e/test_valsets_cli.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/identity_vectors/01_predict_qa.json +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/identity_vectors/02_predict_renamed_field.json +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/identity_vectors/03_chain_of_thought_qa.json +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/identity_vectors/04_predict_richer_types.json +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/identity_vectors/05_composite_two_predicts.json +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/identity_vectors/06_multichaincomparison.json +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/identity_vectors/07_program_of_thought.json +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/identity_vectors/08_opaque_module.json +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/identity_vectors/09_predict_pydantic_field.json +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/identity_vectors/10_react.json +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/identity_vectors/11_refine.json +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/identity_vectors/12_retrieve.json +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/identity_vectors/13_knn.json +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/identity_vectors/14_parallel.json +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/identity_vectors/README.md +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/ingest_conformance.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/integration/__init__.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/integration/authored_optimize/judge.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/integration/authored_optimize/optimize_hosted.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/integration/conftest.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/integration/hosted_mcp_tool_optimize_probe.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/integration/hosted_optimize_probe.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/integration/optimization_run_probe.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/integration/test_cli_deploy_smoketest.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/integration/test_logs_renders_traces.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/integration/test_optimization_run.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/integration/test_optimizing_progress.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/integration/test_unhappy_path.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/lm15_prompt_fixture.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/lm15_prompts/four_turn_predict.json +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/lm15_prompts/rlm_six_turns.json +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/load/__init__.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/load/__main__.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/load/drain.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/load/ingest.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/load/latency_transport.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/load/rlm_shape.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/load/rlm_size_report.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/load/sweep.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/load/test_rlm_shape.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/load/test_rlm_size_report.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/parity/__init__.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/parity/conftest.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/parity/seed_parity.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/parity/test_auth.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/parity/test_datasets.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/parity/test_deployments.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/parity/test_evals.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/parity/test_health.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/parity/test_modules.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/parity/test_optimizations.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/parity/test_programs.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/parity/test_signatures.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/parity/test_trace_streaming.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/parity/test_traces.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/real_models/__init__.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/real_models/_provider.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/real_models/_readiness.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/real_models/_reliability.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/real_models/_result.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/real_models/mint_bedrock_token.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/real_models/test_bedrock_converse.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/real_models/test_deploy_programs.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/real_models/test_multi_client_stress.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/real_models/test_optimize_client_committee.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/real_models/test_optimize_continuation.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/real_models/test_optimize_loop.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/real_models/test_optimize_loop_wasm.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/real_models/test_optimize_stress.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/real_models/test_provider_roles.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/real_models/test_readiness.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/real_models/test_real_provider_twins.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/real_models/test_reliability.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/real_models/test_reliability_classify.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/real_models/test_rlm_wasm.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/real_models/test_trace_search.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/span_reference_fixture.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_adapter_reentrancy.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_assessments_api.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_authored.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_authored_binding_credentials.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_authored_bundle_collisions.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_authored_metric_contract.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_authored_named_models.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_authored_optimize.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_callback.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_candidate_lineage.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/__init__.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/conftest.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_admin.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_api_client.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_assessments.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_auth.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_credentials.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_datasets.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_deployment_runs.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_deployments.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_evals.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_login.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_main.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_optimizations.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_org.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_pagination.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_parity.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_programs.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_provider_credentials.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_schema_sample.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_shell.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_tool_servers.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_top.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_traces.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_traces_program_and_module.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_traces_search_wire.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_tree_help.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cli/test_valsets.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_client.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_client_floor.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_client_program_names.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_clustering/__init__.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_clustering/conftest.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_clustering/test_edge_cases.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_clustering/test_hash_consistency.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_clustering/test_type_conversion.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_cmp551_grouping_identity.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_configuration.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_context.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_context_propagation.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_credential_kwargs.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_credential_selection.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_credential_values.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_dataset_polling.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_dataset_sync.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_datasets.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_decision_client_spans.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_decorators.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_deploy.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_deploy_mcp_tool_references.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_deploy_program_id.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_deployment_metadata.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_deployment_runs.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_deployments_read.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_eval.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_eval_example_attribution.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_eval_program_id.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_eval_start.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_eval_trace_grouping.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_exception_paths.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_execute.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_execute_run_identity.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_exporter.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_exporter_program_names.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_exporter_queue.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_exporter_real.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_fake_lm.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_gepa_callback.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_gepa_integration.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_gepa_output_normalization.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_gepa_resume.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_identity.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_imaging.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_import_weight.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_ingest_conformance.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_ingest_second_producer.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_integration.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_interpreter_callback.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_ir_encoder_properties.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_ir_golden_vectors.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_ir_roundtrip.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_lm15_native_calls.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_lm15_prompt_fixtures.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_lm15_prompt_references.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_lm_configuration.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_mcp_tools.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_models.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_multi_client_stress_readiness.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_no_signature_hash_on_the_wire.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_optimization_phase_callback.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_optimization_program_names.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_optimization_progress.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_optimization_start.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_optimize.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_optimize_budget.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_optimize_lift.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_optimize_lms.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_optimize_proposer.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_optimize_reflection_lm.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_optimize_terminal_failure.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_packaging.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_packaging_callable_source.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_packaging_mcp_tools.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_packaging_program_source.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_poll_until.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_program_id_deprecation.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_program_identity.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_program_lineage_persist.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_program_names_in_deploy.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_program_naming.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_programs_create.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_project_payload.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_real_provider_twins_readiness.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_reflector_properties.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_reflector_smoke.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_release_gate_script.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_release_real_models_script.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_replaced_names.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_repro_reactv2_bugs.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_require_version_bump.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_retry.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_reversible_failures.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_rlm_patch.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_run_attribution_paths.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_runtime_tools.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_schemas.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_seal_lm_credential.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_seed_review_run.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_signature_inputs.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_span_references.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_span_sent_once.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_span_submission.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_span_submission_wire_contract.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_system_one.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_trace_context_concurrency.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_trace_fact_wire_contract.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_trace_facts.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_trace_render.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_traces_read.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_tracked_gepa.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_tracker_enrich.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_truncation.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_upload_auth_headers.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_user_agent.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_valsets_api.py +0 -0
- {cmpnd-0.86.0 → cmpnd-0.86.1}/tests/test_xxh64.py +0 -0
|
@@ -1052,8 +1052,10 @@ class _ModuleMixin(_CallbackBase):
|
|
|
1052
1052
|
cleaned_outputs = helpers.clean_outputs(captured_outputs, instance, dspy, self._max_output_field_size)
|
|
1053
1053
|
span.set_outputs(cleaned_outputs)
|
|
1054
1054
|
|
|
1055
|
-
|
|
1056
|
-
|
|
1055
|
+
# A module span records no token usage. Its LM call spans carry each
|
|
1056
|
+
# call's usage, and a trace's totals sum every span, so usage copied
|
|
1057
|
+
# from the Prediction here would count each call once more per
|
|
1058
|
+
# enclosing module.
|
|
1057
1059
|
|
|
1058
1060
|
# Pop from context stack
|
|
1059
1061
|
context.pop_span()
|
|
@@ -1462,32 +1464,6 @@ class _ModuleMixin(_CallbackBase):
|
|
|
1462
1464
|
trace.tags["optimization_phase"] = phase
|
|
1463
1465
|
return trace
|
|
1464
1466
|
|
|
1465
|
-
def _extract_usage_from_prediction(self, span: models.SpanBuilder, outputs: Any, dspy: Any) -> None:
|
|
1466
|
-
"""Sum the LM usage a DSPy Prediction carries onto its module span.
|
|
1467
|
-
|
|
1468
|
-
This is what fills the trace row's own token totals, so a shape read
|
|
1469
|
-
wrongly here reports a trace as having spent no tokens even when the LM
|
|
1470
|
-
spans below it carry the right counts.
|
|
1471
|
-
"""
|
|
1472
|
-
if not isinstance(outputs, dspy.Prediction):
|
|
1473
|
-
return
|
|
1474
|
-
usage_by_model = outputs.get_lm_usage() if hasattr(outputs, "get_lm_usage") else None
|
|
1475
|
-
if not usage_by_model:
|
|
1476
|
-
return
|
|
1477
|
-
for model_usage in usage_by_model.values():
|
|
1478
|
-
counts = _normalize_usage(model_usage)
|
|
1479
|
-
span.prompt_tokens += counts["prompt_tokens"] or 0
|
|
1480
|
-
span.completion_tokens += counts["completion_tokens"] or 0
|
|
1481
|
-
span.total_tokens += counts["total_tokens"] or 0
|
|
1482
|
-
span.cached_prompt_tokens += counts["cached_prompt_tokens"] or 0
|
|
1483
|
-
# Summed only over the models that reported one, so a span whose
|
|
1484
|
-
# models all stayed silent keeps the field absent rather than 0.
|
|
1485
|
-
for name in ("reasoning_tokens", "cache_write_tokens"):
|
|
1486
|
-
reported = counts[name]
|
|
1487
|
-
if reported is None:
|
|
1488
|
-
continue
|
|
1489
|
-
setattr(span, name, (getattr(span, name) or 0) + reported)
|
|
1490
|
-
|
|
1491
1467
|
|
|
1492
1468
|
class _LMMixin(_CallbackBase):
|
|
1493
1469
|
"""DSPy LM callbacks (on_lm_start/on_lm_end)."""
|
|
@@ -115,7 +115,7 @@ bindings, the judge picks one through `lms[name]`. A `TypeSafe` object passed in
|
|
|
115
115
|
The hook methods, in the order you'd expect them to fire for a typical `dspy.ChainOfThought` call:
|
|
116
116
|
|
|
117
117
|
- **Module lifecycle** — `on_module_start` (`callback.py`) creates a new `SpanBuilder`, and, if this is the root module call, also creates a new `TraceBuilder` via `_create_trace`. `on_module_end` closes the span, attaches outputs, and, if it was the root, exports the trace. A call is root when no span is on the stack — or when the only span above it is the `Evaluate` span, which contains many independent program runs and parents none of them, so each run under a `dspy.Evaluate` roots its own trace. Such a root span is built with `create_child_span(..., root=True)` so it does not adopt the `Evaluate` span as its parent.
|
|
118
|
-
- **LM calls.** `on_lm_start` and `on_lm_end` wrap the provider call. The callback records the model, the
|
|
118
|
+
- **LM calls.** `on_lm_start` and `on_lm_end` wrap the provider call. The callback records the model, the LM call span's token counts, and a versioned `lm_usage` evidence object. `capture_prompts` controls whether the prompt payload is recorded. Only an LM call span carries token counts. A module span records none, even when DSPy's `track_usage` puts the usage on its `Prediction`, because the SDK's trace totals and serve's trace fold both add up every span, and a module span holding its calls' usage would count each call again for every module that encloses it (`tests/test_token_attribution.py`).
|
|
119
119
|
- **Adapter format/parse** — `on_adapter_format_start` / `_end` and `on_adapter_parse_start` / `_end`. Both route through the shared helpers `_start_adapter_span` and `_end_adapter_span`. The callback records one span per adapter call. DSPy's `Adapter.__init_subclass__` wraps `format` and `parse` on every subclass, so a `JSONAdapter.format` call fires the hooks twice and a `BAMLAdapter.format` call three times, each with a fresh `call_id` and the same instance. `_start_adapter_span` skips a call when the current span is the same method's adapter span on the same instance, and `_end_adapter_span` returns early for the skipped `call_id`. The outermost span is kept, since its output is what reaches the LM. `tests/test_adapter_reentrancy.py` runs the real adapters under DSPy's dispatch. An adapter span's inputs are the method's arguments, so they include the predictor's `signature`. `helpers.clean_inputs` records any signature class among a span's inputs by its label, the class name or the `in1, in2 -> out1` fields of a string signature. It never records the repr, which embeds the whole instructions and every field's metadata. The same rule covers a `Predict` called with `signature=`, as DSPy's RLM does on every turn from DSPy `main` on. The span records the signature's fields and instructions once, as its own attributes.
|
|
120
120
|
- **Tools** — `on_tool_start` / `on_tool_end` (`callback.py`). One span per `dspy.Tool` invocation, with the tool's args as inputs.
|
|
121
121
|
- **Interpreter (code execution)** — `_InterpreterMixin` (`callback.py`), for the DSPy `CodeInterpreter` hooks DSPy >= 3.3.1 fires around a program running code in the interpreter (`RLM`, `ProgramOfThought`, `CodeAct`, `Flex` — every module reaching it through `_create_interpreter`; `ReAct` / `ReActV2` use no interpreter and fire none). `on_interpreter_execute_start` / `_end` emit one `INTERPRETER_EXECUTE` span per REPL cell — the code in, its captured stdout out, and the `SUBMIT()` result (a DSPy `FinalOutput`) recorded distinctly from stdout. On DSPy 3.4.1 and later, `RLM` runs the sandbox side of its `dspy` stand-in as each session's first cell, marked by the `__dspy_host_token` variable (`dspy.primitives.facade.HOST_TOKEN_VAR`). That cell is DSPy's machinery rather than a step the program took, so it emits no span. `on_interpreter_tool_call_start` / `_end` synthesize a `TOOL` span for a tool called from interpreter code **only when no real `dspy.Tool` span covered the call** (a user tool routes through `Tool.__call__` and fires `on_tool_*`, so its row is suppressed to avoid a duplicate; the `llm_query` builtins fire no tool hook, so they get the synthesized span). `on_interpreter_startup_*` / `on_interpreter_shutdown_*` emit no span — their duration folds into an `interpreter.startup_ms` / `interpreter.shutdown_ms` attribute on the enclosing span, and an event with no enclosing span (a pooled pre-warm) is dropped.
|
|
@@ -840,7 +840,7 @@ A span's dict looks roughly like this:
|
|
|
840
840
|
"span_id": "...",
|
|
841
841
|
"trace_id": "...",
|
|
842
842
|
"parent_span_id": "...",
|
|
843
|
-
"span_type": "
|
|
843
|
+
"span_type": "lm_call",
|
|
844
844
|
"start_time": "2020-01-02T00:00:00+00:00",
|
|
845
845
|
"status": "ok",
|
|
846
846
|
"project_tags": [],
|
|
@@ -5,7 +5,7 @@ name = "cmpnd"
|
|
|
5
5
|
# it's new) — no git tags. Bump with `uv version --bump {minor,patch}` or by
|
|
6
6
|
# hand. Runtime `cmpnd.__version__` reads installed metadata, so it tracks
|
|
7
7
|
# this automatically. See docs/plans/2026-07-02-sdk-pypi-tag-free-publish.md.
|
|
8
|
-
version = "0.86.
|
|
8
|
+
version = "0.86.1"
|
|
9
9
|
description = "DSPy observability and deployment SDK for cmpnd"
|
|
10
10
|
readme = "README.md"
|
|
11
11
|
requires-python = ">=3.11"
|
|
@@ -575,73 +575,3 @@ def test_finish_reason_from_typed_response():
|
|
|
575
575
|
def test_finish_reason_absent_when_nothing_reports_one():
|
|
576
576
|
span = _span_for(_responses_usage(), response=_ResponsesResponse("in_progress"))
|
|
577
577
|
assert span.attributes.get("lm.finish_reason") == "in_progress"
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
# --- Module-level aggregation (the trace's own totals) ---------------------
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
@pytest.mark.parametrize("shape", _SHAPE_PARAMS)
|
|
584
|
-
def test_prediction_usage_aggregates_on_every_shape(shape: str):
|
|
585
|
-
"""``Prediction.get_lm_usage()`` feeds the module span, and so the trace row.
|
|
586
|
-
|
|
587
|
-
A trace reporting no prompt or completion tokens at all, while its LM spans
|
|
588
|
-
below carry counts, is this path reading zeros one level above them.
|
|
589
|
-
"""
|
|
590
|
-
import dspy
|
|
591
|
-
|
|
592
|
-
from cmpnd.callback import CmpndCallback
|
|
593
|
-
|
|
594
|
-
with mock.patch("cmpnd.exporter.ensure_exporter_started", autospec=True):
|
|
595
|
-
callback = CmpndCallback()
|
|
596
|
-
|
|
597
|
-
span = mock.MagicMock()
|
|
598
|
-
span.prompt_tokens = 0
|
|
599
|
-
span.completion_tokens = 0
|
|
600
|
-
span.total_tokens = 0
|
|
601
|
-
span.cached_prompt_tokens = 0
|
|
602
|
-
span.reasoning_tokens = None
|
|
603
|
-
span.cache_write_tokens = None
|
|
604
|
-
|
|
605
|
-
prediction = dspy.Prediction(answer="Paris")
|
|
606
|
-
prediction.set_lm_usage({"openai/gpt-5.6-luna": _SHAPES[shape]()})
|
|
607
|
-
|
|
608
|
-
callback._extract_usage_from_prediction(span, prediction, dspy)
|
|
609
|
-
|
|
610
|
-
assert span.prompt_tokens == 2900
|
|
611
|
-
assert span.completion_tokens == 17
|
|
612
|
-
assert span.total_tokens == 2917
|
|
613
|
-
assert span.cached_prompt_tokens == 1024
|
|
614
|
-
assert span.reasoning_tokens == 12
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
def test_prediction_usage_sums_across_models():
|
|
618
|
-
import dspy
|
|
619
|
-
|
|
620
|
-
from cmpnd.callback import CmpndCallback
|
|
621
|
-
|
|
622
|
-
with mock.patch("cmpnd.exporter.ensure_exporter_started", autospec=True):
|
|
623
|
-
callback = CmpndCallback()
|
|
624
|
-
|
|
625
|
-
span = mock.MagicMock()
|
|
626
|
-
span.prompt_tokens = 0
|
|
627
|
-
span.completion_tokens = 0
|
|
628
|
-
span.total_tokens = 0
|
|
629
|
-
span.cached_prompt_tokens = 0
|
|
630
|
-
span.reasoning_tokens = None
|
|
631
|
-
span.cache_write_tokens = None
|
|
632
|
-
|
|
633
|
-
prediction = dspy.Prediction(answer="Paris")
|
|
634
|
-
prediction.set_lm_usage(
|
|
635
|
-
{
|
|
636
|
-
"openai/gpt-5.6-luna": _chat_usage(),
|
|
637
|
-
"anthropic/claude-sonnet-4": _responses_usage(),
|
|
638
|
-
}
|
|
639
|
-
)
|
|
640
|
-
|
|
641
|
-
callback._extract_usage_from_prediction(span, prediction, dspy)
|
|
642
|
-
|
|
643
|
-
assert span.prompt_tokens == 5800
|
|
644
|
-
assert span.completion_tokens == 34
|
|
645
|
-
assert span.reasoning_tokens == 24
|
|
646
|
-
# Nothing reported a cache write, so the sum stays absent rather than 0.
|
|
647
|
-
assert span.cache_write_tokens is None
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""Each LM call's tokens land on exactly one span: its own LM call span.
|
|
2
|
+
|
|
3
|
+
A trace's token total is the sum over its spans, both in the SDK's own trace
|
|
4
|
+
roll-up and in serve's trace fold. A module span that also carried the usage of
|
|
5
|
+
the LM calls beneath it would count every call once per enclosing module.
|
|
6
|
+
|
|
7
|
+
These tests run real DSPy modules over the in-process fake provider, with DSPy's
|
|
8
|
+
``track_usage`` on so each ``Prediction`` reports its LM usage, and check what
|
|
9
|
+
the callback hands the exporter.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from typing import Any
|
|
15
|
+
from unittest import mock
|
|
16
|
+
|
|
17
|
+
import pytest
|
|
18
|
+
|
|
19
|
+
dspy = pytest.importorskip("dspy")
|
|
20
|
+
litellm = pytest.importorskip("litellm")
|
|
21
|
+
|
|
22
|
+
from cmpnd import configure, shutdown_exporter # noqa: E402
|
|
23
|
+
from cmpnd.callback import CmpndCallback # noqa: E402
|
|
24
|
+
from cmpnd.context import clear_context # noqa: E402
|
|
25
|
+
from cmpnd.models import SpanType # noqa: E402
|
|
26
|
+
from tests.e2e import fake_lm # noqa: E402
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class _RecordingExporter:
|
|
30
|
+
def __init__(self) -> None:
|
|
31
|
+
self.traces: list[Any] = []
|
|
32
|
+
|
|
33
|
+
def export_trace_start(self, trace: Any) -> None:
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
def export_trace_finalize(self, trace: Any) -> None:
|
|
37
|
+
self.traces.append(trace)
|
|
38
|
+
|
|
39
|
+
def export_span(self, span: Any) -> None:
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
def export_trace(self, trace: Any) -> None:
|
|
43
|
+
self.traces.append(trace)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@pytest.fixture
|
|
47
|
+
def traced():
|
|
48
|
+
"""Run a callable under the cmpnd callback and return the exported trace."""
|
|
49
|
+
saved_providers = list(litellm.custom_provider_map)
|
|
50
|
+
fake_lm.register()
|
|
51
|
+
configure(api_key="test_key")
|
|
52
|
+
exporter = _RecordingExporter()
|
|
53
|
+
|
|
54
|
+
def run(program: Any, **kwargs: Any) -> Any:
|
|
55
|
+
with (
|
|
56
|
+
mock.patch("cmpnd.exporter.get_exporter", autospec=True, return_value=exporter),
|
|
57
|
+
mock.patch("cmpnd.exporter.ensure_exporter_started", autospec=True),
|
|
58
|
+
):
|
|
59
|
+
callback = CmpndCallback()
|
|
60
|
+
lm = dspy.LM(fake_lm.FAKE_MODEL, cache=False)
|
|
61
|
+
with dspy.context(lm=lm, callbacks=[callback], track_usage=True):
|
|
62
|
+
prediction = program(**kwargs)
|
|
63
|
+
# The fixture only matters if DSPy really reported usage on the Prediction.
|
|
64
|
+
assert prediction.get_lm_usage(), "track_usage did not attach LM usage"
|
|
65
|
+
assert len(exporter.traces) == 1
|
|
66
|
+
return exporter.traces[0]
|
|
67
|
+
|
|
68
|
+
yield run
|
|
69
|
+
|
|
70
|
+
litellm.custom_provider_map = saved_providers
|
|
71
|
+
clear_context()
|
|
72
|
+
import cmpnd.configuration
|
|
73
|
+
|
|
74
|
+
cmpnd.configuration._config = None
|
|
75
|
+
shutdown_exporter()
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _spans(trace: Any) -> list[Any]:
|
|
79
|
+
return list(trace._batch_spans)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _lm_spans(trace: Any) -> list[Any]:
|
|
83
|
+
return [s for s in _spans(trace) if s.span_type == SpanType.LM_CALL]
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _assert_tokens_only_on_lm_calls(trace: Any) -> None:
|
|
87
|
+
for span in _spans(trace):
|
|
88
|
+
if span.span_type == SpanType.LM_CALL:
|
|
89
|
+
continue
|
|
90
|
+
assert (span.prompt_tokens, span.completion_tokens, span.total_tokens, span.cached_prompt_tokens) == (
|
|
91
|
+
0,
|
|
92
|
+
0,
|
|
93
|
+
0,
|
|
94
|
+
0,
|
|
95
|
+
), f"{span.span_type.value} span carries tokens"
|
|
96
|
+
assert span.reasoning_tokens is None
|
|
97
|
+
assert span.cache_write_tokens is None
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def test_module_over_one_lm_call_counts_the_call_once(traced):
|
|
101
|
+
trace = traced(dspy.Predict("text -> sentiment"), text="I love it")
|
|
102
|
+
|
|
103
|
+
[lm_span] = _lm_spans(trace)
|
|
104
|
+
assert lm_span.prompt_tokens > 0
|
|
105
|
+
assert lm_span.completion_tokens > 0
|
|
106
|
+
_assert_tokens_only_on_lm_calls(trace)
|
|
107
|
+
assert trace.prompt_tokens == lm_span.prompt_tokens
|
|
108
|
+
assert trace.completion_tokens == lm_span.completion_tokens
|
|
109
|
+
assert trace.total_tokens == lm_span.total_tokens
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def test_nested_modules_count_each_call_once(traced):
|
|
113
|
+
"""ChainOfThought wraps a Predict: two module spans over one LM call."""
|
|
114
|
+
trace = traced(dspy.ChainOfThought("question -> answer"), question="What is 2 + 2?")
|
|
115
|
+
|
|
116
|
+
lm_spans = _lm_spans(trace)
|
|
117
|
+
assert len(lm_spans) == 1
|
|
118
|
+
assert len([s for s in _spans(trace) if s.span_type != SpanType.LM_CALL]) >= 2
|
|
119
|
+
_assert_tokens_only_on_lm_calls(trace)
|
|
120
|
+
assert trace.prompt_tokens == sum(s.prompt_tokens for s in lm_spans)
|
|
121
|
+
assert trace.completion_tokens == sum(s.completion_tokens for s in lm_spans)
|
|
122
|
+
assert trace.total_tokens == sum(s.total_tokens for s in lm_spans)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|