atif-sql 0.5.0__tar.gz → 0.6.0__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.
- {atif_sql-0.5.0 → atif_sql-0.6.0}/PKG-INFO +3 -4
- {atif_sql-0.5.0 → atif_sql-0.6.0}/README.md +2 -2
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/pyproject.toml +3 -3
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-cli/README.md +4 -1
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-cli/pyproject.toml +7 -7
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-cli/src/atif_cli/app.py +133 -26
- atif_sql-0.6.0/packages/atif-cli/src/atif_cli/vector_probe.py +137 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/README.md +1 -1
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/pyproject.toml +2 -2
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/model_prices.json +1895 -167
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/pricing.py +77 -38
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/schema_version.py +11 -1
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/pyproject.toml +2 -2
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/src/atif_corpus/domain/slug.py +1 -1
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/pyproject.toml +2 -2
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/infrastructure/registry.py +75 -20
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-embed/README.md +40 -10
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-embed/pyproject.toml +3 -4
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-embed/src/atif_embed/__init__.py +4 -3
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-embed/src/atif_embed/application/embed.py +17 -11
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-embed/src/atif_embed/application/prune.py +1 -1
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-embed/src/atif_embed/domain/errors.py +38 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-embed/src/atif_embed/domain/ports.py +1 -5
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-embed/src/atif_embed/domain/sql_literal.py +12 -9
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-embed/src/atif_embed/infrastructure/cohere_bedrock.py +4 -4
- atif_sql-0.6.0/packages/atif-embed/src/atif_embed/infrastructure/lance_extension.py +74 -0
- atif_sql-0.6.0/packages/atif-embed/src/atif_embed/infrastructure/lance_store.py +706 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-embed/src/atif_embed/infrastructure/settings.py +4 -4
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-models/pyproject.toml +2 -2
- {atif_sql-0.5.0 → atif_sql-0.6.0}/pyproject.toml +20 -8
- atif_sql-0.5.0/packages/atif-embed/src/atif_embed/infrastructure/lance_store.py +0 -440
- {atif_sql-0.5.0 → atif_sql-0.6.0}/.gitignore +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/.vale/styles/Google/LICENSE +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/.vale/styles/proselint/LICENSE +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/.vale/styles/proselint/README.md +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/LICENSE +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/docs/README.md +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/LICENSE +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/README.md +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/application/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/application/analyze.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/application/prompts.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/application/use_cases/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/application/use_cases/_shared.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/application/use_cases/classify.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/application/use_cases/conflicts.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/application/use_cases/friction.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/application/use_cases/perceived.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/domain/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/domain/authorship.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/domain/config.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/domain/costs.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/domain/friction.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/domain/layout.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/domain/models.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/domain/ports.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/domain/transcript.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/infrastructure/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/infrastructure/corpus_reader.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/infrastructure/parquet_cache.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/infrastructure/settings.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/infrastructure/sqlite_state/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/infrastructure/sqlite_state/checkpointer.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/infrastructure/sqlite_state/retry_queue.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-analytics/src/atif_analytics/py.typed +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-cli/LICENSE +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-cli/src/atif_cli/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-cli/src/atif_cli/__main__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-cli/src/atif_cli/converter_adapter.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-cli/src/atif_cli/corpus.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-cli/src/atif_cli/cron.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-cli/src/atif_cli/duck_errors.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-cli/src/atif_cli/embed_lake.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-cli/src/atif_cli/errors.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-cli/src/atif_cli/lake.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-cli/src/atif_cli/lake_sessions.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-cli/src/atif_cli/output.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-cli/src/atif_cli/py.typed +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/LICENSE +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/application/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/application/convert_and_audit.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/application/convert_codex.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/agents.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/atif/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/atif/agent.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/atif/content.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/atif/final_metrics.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/atif/metrics.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/atif/observation.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/atif/observation_result.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/atif/step.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/atif/subagent_trajectory_ref.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/atif/tool_call.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/atif/trajectory.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/atif/trajectory_validator.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/blobs.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/claude_code_conversion.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/codex_conversion.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/codex_edges.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/codex_enrichment.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/codex_fidelity.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/codex_nested_calls.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/edges.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/enrichment.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/errors.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/fidelity.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/result_signals.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/domain/session_events.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/infrastructure/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/infrastructure/census.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/infrastructure/claude_code_converter.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/infrastructure/codex_adapter.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/infrastructure/codex_census.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/infrastructure/codex_converter.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/infrastructure/harbor_adapter.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/infrastructure/raw_records.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/infrastructure/source_archive.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-converter/src/atif_converter/py.typed +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/LICENSE +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/README.md +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/src/atif_corpus/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/src/atif_corpus/application/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/src/atif_corpus/application/materialize.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/src/atif_corpus/domain/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/src/atif_corpus/domain/agents.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/src/atif_corpus/domain/generation.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/src/atif_corpus/domain/layout.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/src/atif_corpus/domain/ports.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/src/atif_corpus/domain/session_id.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/src/atif_corpus/domain/sessions.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/src/atif_corpus/domain/source_layout.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/src/atif_corpus/domain/watermark.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/src/atif_corpus/infrastructure/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/src/atif_corpus/infrastructure/atomic.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/src/atif_corpus/infrastructure/compress_artifacts.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/src/atif_corpus/infrastructure/fake_converter.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/src/atif_corpus/infrastructure/scanner.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/src/atif_corpus/infrastructure/settings.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/src/atif_corpus/infrastructure/source_archive.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-corpus/src/atif_corpus/py.typed +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/LICENSE +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/README.md +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/domain/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/domain/artifacts.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/domain/authorship.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/domain/catalog.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/domain/columnar.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/domain/embedding_guard.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/domain/examples.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/domain/lake.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/domain/lake_sessions.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/domain/raw_readers.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/domain/session_id.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/domain/sql_literal.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/infrastructure/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/infrastructure/analytics.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/infrastructure/authorship.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/infrastructure/columnar.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/infrastructure/lake.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/infrastructure/lake_sessions.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/infrastructure/lake_settings.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/infrastructure/lake_steps.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/infrastructure/projections.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/infrastructure/stored_artifacts.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-duck/src/atif_duck/py.typed +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-embed/LICENSE +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-embed/src/atif_embed/application/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-embed/src/atif_embed/domain/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-embed/src/atif_embed/domain/discovery.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-embed/src/atif_embed/domain/embedding_guard.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-embed/src/atif_embed/domain/text_stamp.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-embed/src/atif_embed/infrastructure/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-embed/src/atif_embed/infrastructure/corpus_text_rows.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-embed/src/atif_embed/infrastructure/gemma_local.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-embed/src/atif_embed/infrastructure/lake_text_rows.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-embed/src/atif_embed/infrastructure/providers.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-embed/src/atif_embed/py.typed +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-models/LICENSE +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-models/README.md +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-models/src/atif_models/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-models/src/atif_models/domain/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-models/src/atif_models/domain/ports.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-models/src/atif_models/domain/registry.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-models/src/atif_models/domain/schema.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-models/src/atif_models/infrastructure/__init__.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-models/src/atif_models/infrastructure/anthropic_bedrock.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-models/src/atif_models/infrastructure/bedrock_common.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-models/src/atif_models/infrastructure/openai_bedrock.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-models/src/atif_models/infrastructure/providers.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-models/src/atif_models/infrastructure/settings.py +0 -0
- {atif_sql-0.5.0 → atif_sql-0.6.0}/packages/atif-models/src/atif_models/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: atif-sql
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: ATIF-native analytics over Claude Code agent trajectories: convert, materialize, and query agent sessions with DuckDB.
|
|
5
5
|
Project-URL: Homepage, https://github.com/laithalsaadoon/atif-sql
|
|
6
6
|
Project-URL: Repository, https://github.com/laithalsaadoon/atif-sql
|
|
@@ -23,7 +23,6 @@ Requires-Dist: boto3>=1.42.91
|
|
|
23
23
|
Requires-Dist: cyclopts>=5.1.1
|
|
24
24
|
Requires-Dist: duckdb<3,>=2.0.0
|
|
25
25
|
Requires-Dist: imagesize>=2.0
|
|
26
|
-
Requires-Dist: lancedb<0.40,>=0.30
|
|
27
26
|
Requires-Dist: loguru>=0.7.3
|
|
28
27
|
Requires-Dist: polars>=1.40.0
|
|
29
28
|
Requires-Dist: pyarrow>=23.0.1
|
|
@@ -83,7 +82,7 @@ uv tool install 'atif-sql[local]' --torch-backend cpu
|
|
|
83
82
|
```
|
|
84
83
|
|
|
85
84
|
Python 3.13 or newer. The install is substantial and deliberately so, because the analytics and
|
|
86
|
-
vector paths carry `polars`, `pyarrow`,
|
|
85
|
+
vector paths carry `polars`, `pyarrow`, and `duckdb`. Conversion itself needs none of
|
|
87
86
|
that weight: the ATIF models are vendored from Harbor and step pricing reads a vendored copy of
|
|
88
87
|
litellm's price data, so neither `harbor` nor `litellm` is installed. Prebuilt wheels cover CPython
|
|
89
88
|
3.13 on manylinux x86_64 and aarch64, macOS arm64, and Windows x86_64. Alpine and other musl targets
|
|
@@ -151,7 +150,7 @@ the only thing documented as installable is the `atif-sql` CLI above.
|
|
|
151
150
|
| `atif-duck` | DuckDB views + macros over the materialized corpus (core surface plus the v2 analytics surface) |
|
|
152
151
|
| `atif-models` | Model alias registry + structured-output LLM clients for GPT-6 and Claude 5.5 on Bedrock; no other package hardcodes an LLM model id |
|
|
153
152
|
| `atif-analytics` | the LLM pipelines `atif-sql analyze` runs: classify, conflicts, friction, and perceived |
|
|
154
|
-
| `atif-embed` | Cohere Embed v4 on Bedrock or EmbeddingGemma 2 on this machine +
|
|
153
|
+
| `atif-embed` | Cohere Embed v4 on Bedrock or EmbeddingGemma 2 on this machine + a Lance vector store written through DuckDB's lance extension + embedding backfill |
|
|
155
154
|
| `atif-cli` | the composition root, and the source of the `atif-sql` command (see [What you can do](#what-you-can-do)) |
|
|
156
155
|
|
|
157
156
|
## Quick start
|
|
@@ -41,7 +41,7 @@ uv tool install 'atif-sql[local]' --torch-backend cpu
|
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
Python 3.13 or newer. The install is substantial and deliberately so, because the analytics and
|
|
44
|
-
vector paths carry `polars`, `pyarrow`,
|
|
44
|
+
vector paths carry `polars`, `pyarrow`, and `duckdb`. Conversion itself needs none of
|
|
45
45
|
that weight: the ATIF models are vendored from Harbor and step pricing reads a vendored copy of
|
|
46
46
|
litellm's price data, so neither `harbor` nor `litellm` is installed. Prebuilt wheels cover CPython
|
|
47
47
|
3.13 on manylinux x86_64 and aarch64, macOS arm64, and Windows x86_64. Alpine and other musl targets
|
|
@@ -109,7 +109,7 @@ the only thing documented as installable is the `atif-sql` CLI above.
|
|
|
109
109
|
| `atif-duck` | DuckDB views + macros over the materialized corpus (core surface plus the v2 analytics surface) |
|
|
110
110
|
| `atif-models` | Model alias registry + structured-output LLM clients for GPT-6 and Claude 5.5 on Bedrock; no other package hardcodes an LLM model id |
|
|
111
111
|
| `atif-analytics` | the LLM pipelines `atif-sql analyze` runs: classify, conflicts, friction, and perceived |
|
|
112
|
-
| `atif-embed` | Cohere Embed v4 on Bedrock or EmbeddingGemma 2 on this machine +
|
|
112
|
+
| `atif-embed` | Cohere Embed v4 on Bedrock or EmbeddingGemma 2 on this machine + a Lance vector store written through DuckDB's lance extension + embedding backfill |
|
|
113
113
|
| `atif-cli` | the composition root, and the source of the `atif-sql` command (see [What you can do](#what-you-can-do)) |
|
|
114
114
|
|
|
115
115
|
## Quick start
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "atif-analytics"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.6.0"
|
|
4
4
|
description = "LLM analytics pipelines over the materialized ATIF corpus: session classification, stance conflicts, user friction, and perceived errors."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -20,7 +20,7 @@ dependencies = [
|
|
|
20
20
|
# a LOCAL source an external installer never sees, so a bare name would ship as
|
|
21
21
|
# `Requires-Dist: atif-models` and resolve to whatever the newest release of
|
|
22
22
|
# that name is. `[tool.commitizen] version_files` rewrites this line on a bump.
|
|
23
|
-
"atif-models==0.
|
|
23
|
+
"atif-models==0.6.0",
|
|
24
24
|
"loguru>=0.7.3",
|
|
25
25
|
"polars>=1.40.0",
|
|
26
26
|
"pyarrow>=23.0.1",
|
|
@@ -37,7 +37,7 @@ Issues = "https://github.com/laithalsaadoon/atif-sql/issues"
|
|
|
37
37
|
Changelog = "https://github.com/laithalsaadoon/atif-sql/blob/main/CHANGELOG.md"
|
|
38
38
|
|
|
39
39
|
[build-system]
|
|
40
|
-
requires = ["uv_build>=0.11.14,<0.
|
|
40
|
+
requires = ["uv_build>=0.11.14,<0.14"]
|
|
41
41
|
build-backend = "uv_build"
|
|
42
42
|
|
|
43
43
|
[tool.uv.build-backend]
|
|
@@ -16,13 +16,16 @@ atif-sql materialize [--force] [--quiesce-seconds N]
|
|
|
16
16
|
[--sessions id,id] # contract-compatible extension:
|
|
17
17
|
# plan only the named sessions
|
|
18
18
|
atif-sql status # corpus freshness, read-only
|
|
19
|
+
atif-sql status --vector-probe # time search's exact kNN over the store
|
|
20
|
+
# (no Bedrock; the nightly compact lane
|
|
21
|
+
# logs it per corpus)
|
|
19
22
|
atif-sql query 'SQL' [--format auto|table|json|csv]
|
|
20
23
|
atif-sql schema # static catalog, no duckdb bind, <50ms
|
|
21
24
|
atif-sql examples # tested example queries per view/macro
|
|
22
25
|
# (alias: atif-sql query --examples)
|
|
23
26
|
atif-sql analyze # v2 analytics pipelines; dry-run by
|
|
24
27
|
# default, spends only with --no-dry-run
|
|
25
|
-
atif-sql embed --all --no-dry-run # embed corpus steps into
|
|
28
|
+
atif-sql embed --all --no-dry-run # embed corpus steps into the Lance store
|
|
26
29
|
# (a real run needs --all or --limit N)
|
|
27
30
|
atif-sql search '<text>' # embed the text, then semantic kNN
|
|
28
31
|
atif-sql cron install | status # print the refresh crontab block, or
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# import-linter can read what it is allowed to import, and so its tests have a
|
|
6
6
|
# home — none of which needs an index.
|
|
7
7
|
name = "atif-cli"
|
|
8
|
-
version = "0.
|
|
8
|
+
version = "0.6.0"
|
|
9
9
|
description = "ATIF-native analytics over Claude Code agent trajectories: convert, materialize, and query agent sessions with DuckDB."
|
|
10
10
|
readme = "README.md"
|
|
11
11
|
license = "Apache-2.0"
|
|
@@ -29,11 +29,11 @@ dependencies = [
|
|
|
29
29
|
# namespace to whatever the newest release of that name is, by whoever owns it.
|
|
30
30
|
# One version moves the whole workspace, so `==` is the honest constraint, and
|
|
31
31
|
# `[tool.commitizen] version_files` rewrites every one of these on each bump.
|
|
32
|
-
"atif-analytics==0.
|
|
33
|
-
"atif-converter==0.
|
|
34
|
-
"atif-corpus==0.
|
|
35
|
-
"atif-duck==0.
|
|
36
|
-
"atif-embed==0.
|
|
32
|
+
"atif-analytics==0.6.0",
|
|
33
|
+
"atif-converter==0.6.0",
|
|
34
|
+
"atif-corpus==0.6.0",
|
|
35
|
+
"atif-duck==0.6.0",
|
|
36
|
+
"atif-embed==0.6.0",
|
|
37
37
|
"cyclopts>=5.1.1",
|
|
38
38
|
# Imported directly by duck_errors.py to classify a DuckDB failure into the
|
|
39
39
|
# parse/catalog/runtime exit-code taxonomy. Reaching it transitively through
|
|
@@ -50,7 +50,7 @@ Issues = "https://github.com/laithalsaadoon/atif-sql/issues"
|
|
|
50
50
|
Changelog = "https://github.com/laithalsaadoon/atif-sql/blob/main/CHANGELOG.md"
|
|
51
51
|
|
|
52
52
|
[build-system]
|
|
53
|
-
requires = ["uv_build>=0.11.14,<0.
|
|
53
|
+
requires = ["uv_build>=0.11.14,<0.14"]
|
|
54
54
|
build-backend = "uv_build"
|
|
55
55
|
|
|
56
56
|
[tool.uv.build-backend]
|
|
@@ -16,7 +16,7 @@ The twelve registered commands — nine ``@app.command`` functions plus the
|
|
|
16
16
|
* ``status`` corpus freshness — read-only, fast
|
|
17
17
|
* ``query`` SQL over the atif-duck views/macros with classified errors
|
|
18
18
|
* ``analyze`` run the analytics pipelines — CALLS BEDROCK, spends money
|
|
19
|
-
* ``embed`` backfill step embeddings into
|
|
19
|
+
* ``embed`` backfill step embeddings into the Lance store — CALLS BEDROCK
|
|
20
20
|
* ``search`` embed one query string, then kNN over the store — CALLS BEDROCK
|
|
21
21
|
* ``examples`` derived, test-executed example queries (also ``query --examples``)
|
|
22
22
|
* ``schema`` static catalog dump, no DuckDB bind, <50ms
|
|
@@ -1151,6 +1151,55 @@ def _lake_surface(corpus_root: Path) -> dict[str, Any]:
|
|
|
1151
1151
|
}
|
|
1152
1152
|
|
|
1153
1153
|
|
|
1154
|
+
def _emit_vector_probe(corpus_root: Path, fmt: OutputFormat) -> None:
|
|
1155
|
+
"""``status --vector-probe``: time ``search``'s exact kNN over this corpus's store."""
|
|
1156
|
+
import duckdb
|
|
1157
|
+
|
|
1158
|
+
from atif_cli.duck_errors import classify_duckdb_error
|
|
1159
|
+
from atif_cli.vector_probe import PROBE_K, probe_store
|
|
1160
|
+
from atif_embed.domain.errors import DomainError, LanceExtensionMissing
|
|
1161
|
+
|
|
1162
|
+
store = _embed_settings(fmt).resolve_lance_uri(corpus_root)
|
|
1163
|
+
try:
|
|
1164
|
+
probe = probe_store(store, corpus=corpus_root.name)
|
|
1165
|
+
except LanceExtensionMissing as exc:
|
|
1166
|
+
err = ClassifiedError(
|
|
1167
|
+
kind="extension_missing",
|
|
1168
|
+
exit_code=EXIT_CODES["extension_missing"],
|
|
1169
|
+
message=f"the lance DuckDB extension is not installed, so the embeddings "
|
|
1170
|
+
f"store at {store} cannot be read",
|
|
1171
|
+
hint="run: atif-sql embed --install-extension (a one-time download)",
|
|
1172
|
+
)
|
|
1173
|
+
emit_error(err, fmt)
|
|
1174
|
+
raise SystemExit(err.exit_code) from exc
|
|
1175
|
+
except DomainError as exc:
|
|
1176
|
+
# A store the extension can't open is terminal, as it is for embed.
|
|
1177
|
+
kind = "terminal_state" if exc.terminal else "runtime_error"
|
|
1178
|
+
err = ClassifiedError(kind=kind, exit_code=EXIT_CODES[kind], message=str(exc))
|
|
1179
|
+
emit_error(err, fmt)
|
|
1180
|
+
raise SystemExit(err.exit_code) from exc
|
|
1181
|
+
except duckdb.Error as exc:
|
|
1182
|
+
err = classify_duckdb_error(exc)
|
|
1183
|
+
emit_error(err, fmt)
|
|
1184
|
+
raise SystemExit(err.exit_code) from exc
|
|
1185
|
+
if probe is None:
|
|
1186
|
+
err = ClassifiedError(
|
|
1187
|
+
kind="no_embeddings",
|
|
1188
|
+
exit_code=EXIT_CODES["no_embeddings"],
|
|
1189
|
+
message=f"no embeddings to scan at {store}",
|
|
1190
|
+
hint="Run: atif-sql embed --all --no-dry-run (or --limit N)",
|
|
1191
|
+
)
|
|
1192
|
+
emit_error(err, fmt)
|
|
1193
|
+
raise SystemExit(err.exit_code)
|
|
1194
|
+
if resolve_format(fmt) is OutputFormat.TABLE:
|
|
1195
|
+
print(
|
|
1196
|
+
f"vector probe: {probe.vector_rows:,} vectors, exact top-{PROBE_K} scan in "
|
|
1197
|
+
f"{probe.scan_s:.3f}s ({probe.store})"
|
|
1198
|
+
)
|
|
1199
|
+
else:
|
|
1200
|
+
emit_json(probe.as_dict(), fmt)
|
|
1201
|
+
|
|
1202
|
+
|
|
1154
1203
|
def _dir_bytes(root: Path) -> int:
|
|
1155
1204
|
"""Total bytes of every file under ``root`` (0 if absent)."""
|
|
1156
1205
|
if not root.is_dir():
|
|
@@ -1165,6 +1214,7 @@ def status(
|
|
|
1165
1214
|
source_root: Path | None = None,
|
|
1166
1215
|
corpus_root: Path | None = None,
|
|
1167
1216
|
quiesce_seconds: int | None = None,
|
|
1217
|
+
vector_probe: Annotated[bool, cyclopts.Parameter(name="--vector-probe")] = False,
|
|
1168
1218
|
fmt: Annotated[OutputFormat, cyclopts.Parameter(name="--format")] = OutputFormat.AUTO,
|
|
1169
1219
|
) -> None:
|
|
1170
1220
|
"""Report corpus freshness: watermark age, counts, bytes, staleness.
|
|
@@ -1204,7 +1254,26 @@ def status(
|
|
|
1204
1254
|
not installed; ``query`` binds ``message_embeddings`` empty rather than
|
|
1205
1255
|
downloading it, so run ``atif-sql embed --install-extension``). Read
|
|
1206
1256
|
from DuckDB's local extension listing; never installs anything.
|
|
1257
|
+
|
|
1258
|
+
``--vector-probe`` prints a timing instead of the report. It runs the
|
|
1259
|
+
exact top-10 cosine scan ``search`` runs over the embeddings store, with
|
|
1260
|
+
the stored embedding of the smallest uuid as the query vector, so it
|
|
1261
|
+
calls no embedding model and reaches no network. Only the scan is timed,
|
|
1262
|
+
on the store's own bounded connection (1 GiB, 2 threads). Output:
|
|
1263
|
+
``{corpus, store, vector_rows, scan_s}``. It reads every stored vector,
|
|
1264
|
+
so it costs what a ``search`` costs, and a plain ``status`` never runs
|
|
1265
|
+
it. The nightly compact lane logs it per corpus to tell when ``search``
|
|
1266
|
+
needs a vector index. Exit codes: 0, 2 no_embeddings (no store, or one
|
|
1267
|
+
with no rows), 78 extension_missing (the lance extension isn't
|
|
1268
|
+
installed; the probe never downloads it) or terminal_state (the store
|
|
1269
|
+
holds a Lance dataset the extension can't open), and a DuckDB error
|
|
1270
|
+
during the scan exits the way ``query``'s do (70 for a runtime error).
|
|
1207
1271
|
"""
|
|
1272
|
+
if vector_probe:
|
|
1273
|
+
settings = _corpus_settings(source_root, corpus_root, agent)
|
|
1274
|
+
_emit_vector_probe(settings.corpus_root, fmt)
|
|
1275
|
+
return
|
|
1276
|
+
|
|
1208
1277
|
import time
|
|
1209
1278
|
|
|
1210
1279
|
from atif_cli.corpus import storage_layout
|
|
@@ -1805,8 +1874,9 @@ def _install_lance_extension(fmt: OutputFormat, *, quiet: bool = False) -> None:
|
|
|
1805
1874
|
from loguru import logger
|
|
1806
1875
|
|
|
1807
1876
|
logger.warning(
|
|
1808
|
-
"Could not install the lance DuckDB extension ({});
|
|
1809
|
-
"
|
|
1877
|
+
"Could not install the lance DuckDB extension ({}); the embeddings store "
|
|
1878
|
+
"can't be written or searched until `atif-sql embed --install-extension` "
|
|
1879
|
+
"succeeds",
|
|
1810
1880
|
str(exc).splitlines()[0],
|
|
1811
1881
|
)
|
|
1812
1882
|
return
|
|
@@ -1831,7 +1901,7 @@ def embed(
|
|
|
1831
1901
|
corpus_root: Path | None = None,
|
|
1832
1902
|
fmt: Annotated[OutputFormat, cyclopts.Parameter(name="--format")] = OutputFormat.AUTO,
|
|
1833
1903
|
) -> None:
|
|
1834
|
-
"""Embed unembedded corpus steps and append them to
|
|
1904
|
+
"""Embed unembedded corpus steps and append them to the Lance store.
|
|
1835
1905
|
|
|
1836
1906
|
Provider
|
|
1837
1907
|
--------
|
|
@@ -1869,14 +1939,17 @@ def embed(
|
|
|
1869
1939
|
|
|
1870
1940
|
Extension
|
|
1871
1941
|
---------
|
|
1872
|
-
|
|
1873
|
-
and never install it themselves (installing is a
|
|
1874
|
-
the extension repository, and ``query`` runs
|
|
1875
|
-
installed here, where the network is already a
|
|
1876
|
-
REAL run installs it first, and
|
|
1877
|
-
exits without touching Bedrock
|
|
1878
|
-
"
|
|
1879
|
-
|
|
1942
|
+
The store is written and read only through DuckDB's lance extension.
|
|
1943
|
+
``query`` and ``search`` never install it themselves (installing is a
|
|
1944
|
+
242 MB download from the extension repository, and ``query`` runs
|
|
1945
|
+
unattended). It is installed here, where the network is already a
|
|
1946
|
+
deliberate act: every REAL run installs it first, and
|
|
1947
|
+
``--install-extension`` installs it and exits without touching Bedrock
|
|
1948
|
+
or the store (``{"extension": "lance", "installed": true,
|
|
1949
|
+
"install_path": ...}``). A dry run never installs it, so a dry run over
|
|
1950
|
+
an existing store without the extension exits 78 and names
|
|
1951
|
+
``--install-extension``. ``atif-sql status`` reports whether it is
|
|
1952
|
+
present.
|
|
1880
1953
|
|
|
1881
1954
|
Cost
|
|
1882
1955
|
----
|
|
@@ -1991,6 +2064,7 @@ def _prune_orphans(corpus_root: Path | None, *, dry_run: bool, fmt: OutputFormat
|
|
|
1991
2064
|
from atif_corpus.application.materialize import read_sink_pending
|
|
1992
2065
|
from atif_corpus.domain.layout import CorpusLayout
|
|
1993
2066
|
from atif_embed.application.prune import prune_orphans
|
|
2067
|
+
from atif_embed.domain.errors import DomainError
|
|
1994
2068
|
from atif_embed.infrastructure.lance_store import LanceVectorStore
|
|
1995
2069
|
|
|
1996
2070
|
settings = _corpus_settings(None, corpus_root)
|
|
@@ -2009,12 +2083,21 @@ def _prune_orphans(corpus_root: Path | None, *, dry_run: bool, fmt: OutputFormat
|
|
|
2009
2083
|
fmt,
|
|
2010
2084
|
)
|
|
2011
2085
|
raise SystemExit(EXIT_CODES["lake_unavailable"])
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2086
|
+
try:
|
|
2087
|
+
report = prune_orphans(
|
|
2088
|
+
settings.corpus_root,
|
|
2089
|
+
lake=lake_steps_port(),
|
|
2090
|
+
store=LanceVectorStore(
|
|
2091
|
+
lance_uri, dim=embed_settings.embedding_dim, install_extension=not dry_run
|
|
2092
|
+
),
|
|
2093
|
+
dry_run=dry_run,
|
|
2094
|
+
)
|
|
2095
|
+
except DomainError as exc:
|
|
2096
|
+
# The store's own errors (a missing extension on a dry prune, a store
|
|
2097
|
+
# the extension can't open) get the same envelope as embed's.
|
|
2098
|
+
kind = "terminal_state" if exc.terminal else "runtime_error"
|
|
2099
|
+
emit_error(ClassifiedError(kind=kind, exit_code=EXIT_CODES[kind], message=str(exc)), fmt)
|
|
2100
|
+
raise SystemExit(EXIT_CODES[kind]) from exc
|
|
2018
2101
|
if report is None:
|
|
2019
2102
|
emit_error(
|
|
2020
2103
|
ClassifiedError(
|
|
@@ -2094,7 +2177,8 @@ def search(
|
|
|
2094
2177
|
extension_missing (a store exists but the lance DuckDB extension is not
|
|
2095
2178
|
installed; run ``atif-sql embed --install-extension``), lake_unavailable
|
|
2096
2179
|
(``--all-corpora`` without a usable lake) or terminal_state (the gemma
|
|
2097
|
-
provider is selected and the ``local`` extra is not installed
|
|
2180
|
+
provider is selected and the ``local`` extra is not installed, or the store
|
|
2181
|
+
holds a Lance dataset the extension can't open).
|
|
2098
2182
|
"""
|
|
2099
2183
|
_refuse_root("search", fmt)
|
|
2100
2184
|
|
|
@@ -2105,7 +2189,11 @@ def search(
|
|
|
2105
2189
|
classify_duckdb_error,
|
|
2106
2190
|
classify_registration_error,
|
|
2107
2191
|
)
|
|
2108
|
-
from atif_duck.infrastructure.registry import
|
|
2192
|
+
from atif_duck.infrastructure.registry import (
|
|
2193
|
+
lance_extension_installed,
|
|
2194
|
+
lance_store_unreadable,
|
|
2195
|
+
register,
|
|
2196
|
+
)
|
|
2109
2197
|
from atif_embed.application.embed import embed_query
|
|
2110
2198
|
from atif_embed.domain.errors import DomainError
|
|
2111
2199
|
|
|
@@ -2166,6 +2254,23 @@ def search(
|
|
|
2166
2254
|
|
|
2167
2255
|
row = con.execute("SELECT count(*) FROM message_embeddings").fetchone()
|
|
2168
2256
|
if not row or int(row[0]) == 0:
|
|
2257
|
+
# No rows can also mean a store the extension can't open, which
|
|
2258
|
+
# binds as an empty one; embedding into it can't fix that.
|
|
2259
|
+
unreadable = [uri for uri in stores or [lance_uri] if lance_store_unreadable(con, uri)]
|
|
2260
|
+
if unreadable:
|
|
2261
|
+
emit_error(
|
|
2262
|
+
ClassifiedError(
|
|
2263
|
+
kind="terminal_state",
|
|
2264
|
+
exit_code=EXIT_CODES["terminal_state"],
|
|
2265
|
+
message=f"the embeddings store at {unreadable[0]} holds a Lance dataset "
|
|
2266
|
+
"the lance extension can't open; its newest manifest may be damaged "
|
|
2267
|
+
"or partly written",
|
|
2268
|
+
hint="restore the store from a backup, or move it aside and re-embed "
|
|
2269
|
+
"with `atif-sql embed --all --no-dry-run`",
|
|
2270
|
+
),
|
|
2271
|
+
fmt,
|
|
2272
|
+
)
|
|
2273
|
+
raise SystemExit(EXIT_CODES["terminal_state"])
|
|
2169
2274
|
emit_error(
|
|
2170
2275
|
ClassifiedError(
|
|
2171
2276
|
kind="no_embeddings",
|
|
@@ -2199,12 +2304,14 @@ def search(
|
|
|
2199
2304
|
|
|
2200
2305
|
|
|
2201
2306
|
#: ``search``'s kNN, one text per shape. Rank by cosine similarity
|
|
2202
|
-
#: descending: ORDER BY array_cosine_distance (== 1 - sim) ASC
|
|
2203
|
-
#:
|
|
2204
|
-
#:
|
|
2205
|
-
#:
|
|
2206
|
-
#:
|
|
2207
|
-
#:
|
|
2307
|
+
#: descending: ORDER BY array_cosine_distance (== 1 - sim) ASC with a LIMIT,
|
|
2308
|
+
#: which DuckDB runs as an exact top-k over a full scan of the Lance table
|
|
2309
|
+
#: (EXPLAIN shows a ``Lance Table Scan`` with ``Lance Limit: none`` under the
|
|
2310
|
+
#: join and a ``Top N`` above it; no vector index is read).
|
|
2311
|
+
#: Cosine is the only correct metric here, not a speed choice: the raw
|
|
2312
|
+
#: int8-cast-to-float document vectors have magnitudes in the thousands while
|
|
2313
|
+
#: the query vector is unit-normalized, so array_distance (L2) would give wrong
|
|
2314
|
+
#: ranks. ``{dim}`` is the only placeholder, filled with ``int(len(vector))``.
|
|
2208
2315
|
_SEARCH_SQL = """
|
|
2209
2316
|
WITH qv AS (SELECT CAST(? AS FLOAT[{dim}]) AS v)
|
|
2210
2317
|
SELECT me.uuid AS uuid,
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
|
|
3
|
+
"""Time the exact kNN scan ``search`` runs, with no Bedrock call and no network.
|
|
4
|
+
|
|
5
|
+
``atif-sql status --vector-probe`` runs this, and the nightly compact lane in
|
|
6
|
+
``scripts/atif-sql-refresh.sh`` logs the result for each corpus. ``search``
|
|
7
|
+
reads no vector index: it ranks every stored vector, so what it pays grows
|
|
8
|
+
with the store, and this number is how the lane notices when it's grown too
|
|
9
|
+
far.
|
|
10
|
+
|
|
11
|
+
The probe runs :data:`PROBE_SQL`, which ranks the store's rows the way
|
|
12
|
+
``search`` ranks them (the same ``qv`` CTE, cosine similarity, and ``ORDER BY
|
|
13
|
+
array_cosine_distance ... ASC`` with a ``LIMIT``), minus ``search``'s join back
|
|
14
|
+
to ``steps``. Its query vector is the stored embedding of the smallest uuid,
|
|
15
|
+
read in the same single statement that picks it, so a store gives the same
|
|
16
|
+
statement every night and nothing is embedded. Only the scan is timed.
|
|
17
|
+
Attaching the store, counting its rows and reading the probe vector all
|
|
18
|
+
happen before the clock starts. Reading the probe vector reads every vector
|
|
19
|
+
once, so the timed scan always runs on a warm page cache.
|
|
20
|
+
|
|
21
|
+
The connection is the store's own, from
|
|
22
|
+
:func:`atif_embed.infrastructure.lance_store.connect_db`: 1 GiB of DuckDB
|
|
23
|
+
memory, 2 threads, a private spill directory, no extension autoload, and no
|
|
24
|
+
download of the lance extension. The compact lane runs inside a 4G memory
|
|
25
|
+
scope, and an unbounded connection would size itself from the whole host.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
import time
|
|
31
|
+
from dataclasses import dataclass
|
|
32
|
+
from pathlib import Path
|
|
33
|
+
from typing import Any
|
|
34
|
+
|
|
35
|
+
#: How many neighbors the probe asks for: ``search``'s default ``-k``.
|
|
36
|
+
PROBE_K = 10
|
|
37
|
+
|
|
38
|
+
#: The probe's kNN. Every line from the ``qv`` CTE to ``LIMIT ?`` except the
|
|
39
|
+
#: ``FROM`` matches a line of ``atif_cli.app._SEARCH_SQL``, and
|
|
40
|
+
#: ``tests/test_vector_probe.py`` checks that, so a change to how ``search``
|
|
41
|
+
#: ranks has to change this too. ``{dim}`` is filled with ``int()`` and
|
|
42
|
+
#: ``{table}`` with the store's table name, never with caller text.
|
|
43
|
+
PROBE_SQL = """
|
|
44
|
+
WITH qv AS (SELECT CAST(? AS FLOAT[{dim}]) AS v)
|
|
45
|
+
SELECT me.uuid AS uuid,
|
|
46
|
+
array_cosine_similarity(me.embedding, (SELECT v FROM qv)) AS sim
|
|
47
|
+
FROM {table} me
|
|
48
|
+
ORDER BY array_cosine_distance(me.embedding, (SELECT v FROM qv)) ASC
|
|
49
|
+
LIMIT ?
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass(frozen=True)
|
|
54
|
+
class VectorProbe:
|
|
55
|
+
"""One timed scan of one store.
|
|
56
|
+
|
|
57
|
+
``hits`` holds the ``(uuid, sim)`` rows the scan returned, best first.
|
|
58
|
+
It's for tests and isn't part of :meth:`as_dict`: the lane logs the
|
|
59
|
+
timing, not the neighbors.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
corpus: str
|
|
63
|
+
store: Path
|
|
64
|
+
vector_rows: int
|
|
65
|
+
scan_s: float
|
|
66
|
+
hits: tuple[tuple[str, float], ...]
|
|
67
|
+
|
|
68
|
+
def as_dict(self) -> dict[str, Any]:
|
|
69
|
+
"""The probe's JSON payload: ``{corpus, store, vector_rows, scan_s}``."""
|
|
70
|
+
return {
|
|
71
|
+
"corpus": self.corpus,
|
|
72
|
+
"store": str(self.store),
|
|
73
|
+
"vector_rows": self.vector_rows,
|
|
74
|
+
"scan_s": self.scan_s,
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def probe_sql(*, dim: int, table: str) -> str:
|
|
79
|
+
""":data:`PROBE_SQL` for a ``dim``-wide store whose table is ``table``."""
|
|
80
|
+
return PROBE_SQL.format(dim=int(dim), table=table)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def probe_store(store: Path, *, corpus: str, k: int = PROBE_K) -> VectorProbe | None:
|
|
84
|
+
"""Time one exact top-``k`` scan of the store at ``store``.
|
|
85
|
+
|
|
86
|
+
Returns ``None`` when there's nothing to scan: no store directory, no
|
|
87
|
+
embeddings table in it, or no rows. The directory is checked before
|
|
88
|
+
connecting, because opening a store creates its directory.
|
|
89
|
+
|
|
90
|
+
Raises
|
|
91
|
+
------
|
|
92
|
+
LanceExtensionMissing
|
|
93
|
+
The lance extension isn't installed. The probe never downloads it.
|
|
94
|
+
duckdb.Error
|
|
95
|
+
The store couldn't be read.
|
|
96
|
+
"""
|
|
97
|
+
from atif_embed.infrastructure.lance_store import (
|
|
98
|
+
STORE_ALIAS,
|
|
99
|
+
TABLE_NAME,
|
|
100
|
+
connect_db,
|
|
101
|
+
has_table,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
if not store.is_dir():
|
|
105
|
+
return None
|
|
106
|
+
table = f"{STORE_ALIAS}.main.{TABLE_NAME}"
|
|
107
|
+
with connect_db(store) as conn:
|
|
108
|
+
if not has_table(conn):
|
|
109
|
+
return None
|
|
110
|
+
con = conn.con
|
|
111
|
+
vector_rows = int(con.execute(f"SELECT count(*) FROM {table}").fetchall()[0][0]) # noqa: S608 # nosec B608 - table is the store's constant name
|
|
112
|
+
if vector_rows == 0:
|
|
113
|
+
return None
|
|
114
|
+
# One statement, so a delete landing between "which uuid" and "its
|
|
115
|
+
# vector" can't leave nothing to read. It's one scan that reads every
|
|
116
|
+
# vector, which also leaves them in the page cache: the timed scan
|
|
117
|
+
# below runs warm every night, so nights compare like with like.
|
|
118
|
+
first = con.execute(
|
|
119
|
+
f"SELECT uuid, embedding FROM {table} ORDER BY uuid LIMIT 1" # noqa: S608 # nosec B608 - table is the store's constant name
|
|
120
|
+
).fetchall()
|
|
121
|
+
if not first:
|
|
122
|
+
return None
|
|
123
|
+
vector = first[0][1]
|
|
124
|
+
sql = probe_sql(dim=len(vector), table=table)
|
|
125
|
+
started = time.perf_counter()
|
|
126
|
+
rows = con.execute(sql, [list(vector), int(k)]).fetchall()
|
|
127
|
+
scan_s = time.perf_counter() - started
|
|
128
|
+
return VectorProbe(
|
|
129
|
+
corpus=corpus,
|
|
130
|
+
store=store,
|
|
131
|
+
vector_rows=vector_rows,
|
|
132
|
+
scan_s=round(scan_s, 3),
|
|
133
|
+
hits=tuple((str(uuid), float(sim)) for uuid, sim in rows),
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
__all__ = ["PROBE_K", "PROBE_SQL", "VectorProbe", "probe_sql", "probe_store"]
|
|
@@ -29,7 +29,7 @@ value: `atif_converter.domain.pricing` returns the same floats, bit for bit,
|
|
|
29
29
|
without litellm being installed. It reads `domain/model_prices.json`, a
|
|
30
30
|
filtered copy of litellm's public `model_prices_and_context_window.json` (MIT;
|
|
31
31
|
the notice and source ref are in its `meta` block), and repeats litellm
|
|
32
|
-
1.
|
|
32
|
+
1.106.3's arithmetic in the same float operation order. The table holds the
|
|
33
33
|
Claude and OpenAI text models our transcripts name under the `anthropic`,
|
|
34
34
|
`openai`, `bedrock` and `bedrock_converse` providers, and keeps litellm's
|
|
35
35
|
`fallback_generalizations` rules, which route an unmapped `claude-<family>-<n>`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "atif-converter"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.6.0"
|
|
4
4
|
description = "Claude Code and Codex transcripts -> ATIF conversion, with the fidelity policy per agent."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -37,7 +37,7 @@ Issues = "https://github.com/laithalsaadoon/atif-sql/issues"
|
|
|
37
37
|
Changelog = "https://github.com/laithalsaadoon/atif-sql/blob/main/CHANGELOG.md"
|
|
38
38
|
|
|
39
39
|
[build-system]
|
|
40
|
-
requires = ["uv_build>=0.11.14,<0.
|
|
40
|
+
requires = ["uv_build>=0.11.14,<0.14"]
|
|
41
41
|
build-backend = "uv_build"
|
|
42
42
|
|
|
43
43
|
[tool.uv.build-backend]
|