mostlyright-data 0.31.12__tar.gz → 0.31.13__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.
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/PKG-INFO +8 -1
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/README.md +7 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/router.py +2 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/runs.py +2 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/session.py +3 -1
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/stream.py +2 -0
- mostlyright_data-0.31.13/src/mostlyright/data_harness/thin/user_agent.py +234 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_public.py +3 -1
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_query.py +2 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/attendance.py +11 -6
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/cloud_auth.py +2 -2
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/commands/clarify.py +10 -5
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/login.py +7 -2
- mostlyright_data-0.31.12/src/mostlyright/data_harness/thin/user_agent.py +0 -76
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/.gitignore +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/pyproject.toml +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/scripts/hatch_build.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/SKILL.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/agents/openai.yaml +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/1-open-the-page-and-the-link-to-it-in-the-first-message.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/2-brief-two-to-four-questions-each-with-a-recommended-answer.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/3-probe-read-a-source-before-committing-to-it.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/4-decide-say-what-you-chose-what-you-refused-and-ask-one-question.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/5-draft-one-recipe-document-one-call.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/6-build-one-run-sized-to-acquire-every-measured-source-whole.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/7-interrogate-ask-the-run-what-it-actually-delivered.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/8-fix-revise-the-document-and-register-it-again.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/9-present-only-what-survived-inspection-with-caveats.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/agent-protocol.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/autonomous-delivery.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/before-the-first-tool-call.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/boundaries.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/cloud-authentication-preflight.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/commands.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/cross-repository-protocol-reference.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/enriching-with-small-models.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/installation-parity.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/live-run.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/making-a-table-incremental.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/narrating-the-run.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/not-hosted-yet.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/one-install.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/patterns.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/prediction-labels.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/preparing-table-search.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/promote.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/readers.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/receipts.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/recipe-test.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/recording-a-stream-venue.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/recovering-an-import-failure.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/reference-pages.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/required-protocol.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/source-credentials.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/sources.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/the-one-thing-to-say-about-the-skill-itself.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/transforms.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/user-communication-contract.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/writing-a-decision-record.md +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/scripts/write_research_notebook.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/__init__.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/agent_protocol.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/canonical.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/formats.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/hosted_crawler_protocol.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/key_seam.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/page_coverage.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/part_check_evidence.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/session_probes.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/skill_assets.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/table_manifest.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/__init__.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/acquire.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/acquire_cancel.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/activity.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/approvals.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/backoff.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/categories.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/commands.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/dataset-categories-v1.json +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/delivery.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/description_shape.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/download.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/enrichment.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/fast_features.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/matching_benchmark.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/narrative.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/parity.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/probe.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/progress_rate.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/progress_vocabulary.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/propose.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/recipe.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/recipe_brief.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/recipe_explain.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/recipe_forecast.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/recipe_lint.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/recipe_test.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/refresh_rehearsal.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/release_check.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/research.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/run_diagnose.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/run_prefix.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/stream_venue.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/studio_capabilities.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/support.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/table_search_contract.json +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/table_view.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/transport.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_artifacts.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_catalog.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_connected.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_connections.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_dataset_covers.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_datasets.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_handoff.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_matching.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_narrative.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_reader.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_runs.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_search.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_search_contract.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_secrets.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_stream.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_tables.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/vocabulary.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/__init__.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/clarification.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/commands/__init__.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/commands/auth.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/commands/login.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/commands/whoami.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/credential_native.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/credential_store.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/credentials.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/path_kind.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/plain_file.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/remediation.py +0 -0
- {mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/render.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mostlyright-data
|
|
3
|
-
Version: 0.31.
|
|
3
|
+
Version: 0.31.13
|
|
4
4
|
Summary: Mostly Right hosted CLI for reviewed datasets
|
|
5
5
|
Project-URL: Homepage, https://mostlyright.md/
|
|
6
6
|
Project-URL: Documentation, https://mostlyright.md/docs/guides/cli/
|
|
@@ -46,6 +46,13 @@ Once a day, after a command has printed its answer, `mr-data` asks the Python pa
|
|
|
46
46
|
a newer release is published and says so in one line on stderr. `MOSTLYRIGHT_RELEASE_CHECK=0`
|
|
47
47
|
switches that off.
|
|
48
48
|
|
|
49
|
+
Every call to Mostly Right names the coding agent running `mr-data` in `X-Mostlyright-Agent`
|
|
50
|
+
(`claude-code`, `codex`, `gemini-cli`, `cursor`, `ci` or `none`, read from the variables those
|
|
51
|
+
hosts set), and a program that imports this package sends it too. An `mr-data` command also sends
|
|
52
|
+
one random id in `X-Mostlyright-Invocation`, so the requests of one command can be grouped; a
|
|
53
|
+
library call sends none. Neither is sent to storage hosts. `MOSTLYRIGHT_NO_AGENT_HEADERS=1`
|
|
54
|
+
switches both off.
|
|
55
|
+
|
|
49
56
|
## Sign in
|
|
50
57
|
|
|
51
58
|
```bash
|
|
@@ -31,6 +31,13 @@ Once a day, after a command has printed its answer, `mr-data` asks the Python pa
|
|
|
31
31
|
a newer release is published and says so in one line on stderr. `MOSTLYRIGHT_RELEASE_CHECK=0`
|
|
32
32
|
switches that off.
|
|
33
33
|
|
|
34
|
+
Every call to Mostly Right names the coding agent running `mr-data` in `X-Mostlyright-Agent`
|
|
35
|
+
(`claude-code`, `codex`, `gemini-cli`, `cursor`, `ci` or `none`, read from the variables those
|
|
36
|
+
hosts set), and a program that imports this package sends it too. An `mr-data` command also sends
|
|
37
|
+
one random id in `X-Mostlyright-Invocation`, so the requests of one command can be grouped; a
|
|
38
|
+
library call sends none. Neither is sent to storage hosts. `MOSTLYRIGHT_NO_AGENT_HEADERS=1`
|
|
39
|
+
switches both off.
|
|
40
|
+
|
|
34
41
|
## Sign in
|
|
35
42
|
|
|
36
43
|
```bash
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/router.py
RENAMED
|
@@ -52,6 +52,7 @@ from collections.abc import Callable, Mapping, Sequence
|
|
|
52
52
|
from typing import Any
|
|
53
53
|
|
|
54
54
|
from mostlyright.data_harness import skill_assets
|
|
55
|
+
from mostlyright.data_harness.thin import user_agent
|
|
55
56
|
from mostlyright.data_harness.thin.transport import ThinLaneError
|
|
56
57
|
from mostlyright.data_harness.thin.vocabulary import (
|
|
57
58
|
CLASSIFICATION,
|
|
@@ -781,6 +782,7 @@ def main(argv: Sequence[str] | None = None) -> int:
|
|
|
781
782
|
# not write, it never raises, and `MOSTLYRIGHT_SKILL_AUTOINSTALL=0` turns it off. A skill that
|
|
782
783
|
# arrived only when somebody knew to ask for it helped exactly the people who did not need it.
|
|
783
784
|
skill_assets.ensure_installed()
|
|
785
|
+
user_agent.begin_invocation()
|
|
784
786
|
|
|
785
787
|
arguments = list(sys.argv[1:] if argv is None else argv)
|
|
786
788
|
hosted_requested = _hosted_flag_present(arguments)
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/runs.py
RENAMED
|
@@ -46,6 +46,7 @@ from mostlyright.data_harness.thin.transport import (
|
|
|
46
46
|
UrlLibTransport,
|
|
47
47
|
signed_transfer_url,
|
|
48
48
|
)
|
|
49
|
+
from mostlyright.data_harness.thin.user_agent import agent_headers
|
|
49
50
|
|
|
50
51
|
#: The contract version every payload below is written against. ``studio_boundary`` pins the
|
|
51
52
|
#: generated client to the same 3.0.0 and to one OpenAPI source digest; this constant is the thin
|
|
@@ -279,6 +280,7 @@ class StudioApiClient:
|
|
|
279
280
|
headers = {
|
|
280
281
|
"Accept": "application/json",
|
|
281
282
|
CLIENT_HEADER: CLIENT_NAME,
|
|
283
|
+
**agent_headers(),
|
|
282
284
|
}
|
|
283
285
|
if extra_headers:
|
|
284
286
|
headers.update(extra_headers)
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/session.py
RENAMED
|
@@ -42,6 +42,7 @@ from mostlyright.data_harness.thin.transport import (
|
|
|
42
42
|
UrlLibTransport,
|
|
43
43
|
service_origin,
|
|
44
44
|
)
|
|
45
|
+
from mostlyright.data_harness.thin.user_agent import agent_headers
|
|
45
46
|
from mostlyright.data_harness.ux.credentials import ResolvedCloudCredentials
|
|
46
47
|
|
|
47
48
|
#: Cloud's token-exchange route. Held identical to ``hosted_deploy.CLOUD_TOKEN_PATH`` by a test.
|
|
@@ -396,7 +397,7 @@ def open_studio_session(
|
|
|
396
397
|
status, raw, headers = selected.request(
|
|
397
398
|
"POST",
|
|
398
399
|
f"{cloud_url}{CLOUD_TOKEN_PATH}",
|
|
399
|
-
{"Accept": "application/json", "x-api-key": credentials.raw_key},
|
|
400
|
+
{"Accept": "application/json", "x-api-key": credentials.raw_key, **agent_headers()},
|
|
400
401
|
b"",
|
|
401
402
|
MAX_TOKEN_RESPONSE_BYTES,
|
|
402
403
|
)
|
|
@@ -953,6 +954,7 @@ class CloudClient:
|
|
|
953
954
|
headers = {
|
|
954
955
|
"Accept": "application/json",
|
|
955
956
|
"Authorization": f"Bearer {self._credentials.raw_key}",
|
|
957
|
+
**agent_headers(),
|
|
956
958
|
}
|
|
957
959
|
encoded: bytes | None = None
|
|
958
960
|
if body is not None:
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/stream.py
RENAMED
|
@@ -49,6 +49,7 @@ from mostlyright.data_harness.thin.session import (
|
|
|
49
49
|
stated_sentence,
|
|
50
50
|
)
|
|
51
51
|
from mostlyright.data_harness.thin.transport import ThinLaneError, Transport, UrlLibTransport
|
|
52
|
+
from mostlyright.data_harness.thin.user_agent import agent_headers
|
|
52
53
|
|
|
53
54
|
#: Upstream's frame names. The first two are the tick/proof partition; ``end`` is its
|
|
54
55
|
#: end-of-stream notice.
|
|
@@ -593,6 +594,7 @@ class RunEventStream:
|
|
|
593
594
|
headers = {
|
|
594
595
|
"Accept": "text/event-stream",
|
|
595
596
|
CLIENT_HEADER: CLIENT_NAME,
|
|
597
|
+
**agent_headers(),
|
|
596
598
|
**session.authorization(),
|
|
597
599
|
}
|
|
598
600
|
# Resume in Studio's own cursor space when we have one. `from_seq` is only ever the
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
"""The identity every first-party request to Mostly Right states.
|
|
2
|
+
|
|
3
|
+
Without it the standard library sends ``Python-urllib/3.x``, which is what every unattended
|
|
4
|
+
script on the internet sends: the CLI's own traffic could not be told apart from anything else in
|
|
5
|
+
a server log, so nothing downstream could measure it, rate-limit it separately, or exempt it.
|
|
6
|
+
|
|
7
|
+
The name follows the convention the two crawler lanes already use -- a product token, a version,
|
|
8
|
+
and the contact segment that says where to reach the people running it -- so an origin and our own
|
|
9
|
+
logs see one family of identities from this deployment rather than one per code path.
|
|
10
|
+
|
|
11
|
+
Two more headers ride beside it on first-party calls only (:func:`agent_headers`): which coding
|
|
12
|
+
agent, if any, is driving this process, and, under the ``mr-data`` command, one id shared by every
|
|
13
|
+
request that command makes. They go where ``X-Mostlyright-Client`` goes and on Cloud's own
|
|
14
|
+
routes, never through the transport, for the reason ``thin.runs.CLIENT_HEADER`` gives: the
|
|
15
|
+
transport also carries signed transfers to storage nobody here owns.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import os
|
|
21
|
+
import secrets
|
|
22
|
+
from collections.abc import Mapping
|
|
23
|
+
from functools import cache
|
|
24
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
25
|
+
from typing import NamedTuple
|
|
26
|
+
|
|
27
|
+
#: The contact segment ``hosted_worker.CRAWLER_CONTACT_SEGMENT`` states for the keyed-source
|
|
28
|
+
#: agents and ``hosted_crawler_fetch.PUBLIC_HTTPS_USER_AGENT`` carries for public sources, with
|
|
29
|
+
#: the measurement that makes it load-bearing recorded at the first of those.
|
|
30
|
+
#:
|
|
31
|
+
#: It is spelled again here rather than imported because both of those modules import ``pyarrow``
|
|
32
|
+
#: at module scope and this package installs with no compiled extension at all -- and they are
|
|
33
|
+
#: Studio's now, so importing them is not a choice this repository has. The spellings are held
|
|
34
|
+
#: against each other by ``tests/test_thin_user_agent.py`` under
|
|
35
|
+
#: ``make verify-cross-repo STUDIO_ROOT=...``, which reads the other one out of Studio's source.
|
|
36
|
+
CRAWLER_CONTACT_SEGMENT = "(+https://mostlyright.md/crawler; crawler@mostlyright.md)"
|
|
37
|
+
|
|
38
|
+
#: The distribution this client is installed as, and the product token it therefore reports.
|
|
39
|
+
DISTRIBUTION_NAME = "mostlyright-data"
|
|
40
|
+
|
|
41
|
+
#: The version reported from a source tree, where no distribution metadata exists to read. A
|
|
42
|
+
#: number rather than a word, so every value this header can carry parses the same way.
|
|
43
|
+
UNINSTALLED_VERSION = "0.0.0"
|
|
44
|
+
|
|
45
|
+
_USER_AGENT_HEADER = "User-Agent"
|
|
46
|
+
|
|
47
|
+
#: The header naming the agent driving this process, one of :data:`AGENTS`.
|
|
48
|
+
AGENT_HEADER = "X-Mostlyright-Agent"
|
|
49
|
+
|
|
50
|
+
#: The header carrying :func:`invocation_id`, sent only after :func:`begin_invocation`.
|
|
51
|
+
INVOCATION_HEADER = "X-Mostlyright-Invocation"
|
|
52
|
+
|
|
53
|
+
#: Set to anything but ``0`` or empty, and neither header above is sent.
|
|
54
|
+
NO_AGENT_HEADERS_ENV = "MOSTLYRIGHT_NO_AGENT_HEADERS"
|
|
55
|
+
|
|
56
|
+
AGENT_CLAUDE_CODE = "claude-code"
|
|
57
|
+
AGENT_CODEX = "codex"
|
|
58
|
+
AGENT_GEMINI_CLI = "gemini-cli"
|
|
59
|
+
AGENT_CURSOR = "cursor"
|
|
60
|
+
AGENT_CI = "ci"
|
|
61
|
+
AGENT_NONE = "none"
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class AgentMarker(NamedTuple):
|
|
65
|
+
"""One variable an agent host exports into the commands it runs.
|
|
66
|
+
|
|
67
|
+
``conversation`` says whether the attendance check (``ux.attendance``) reads the variable as
|
|
68
|
+
a conversation existing. Only a marker every headless run of that host lacks may say so:
|
|
69
|
+
``CODEX_SANDBOX`` is set by ``codex exec`` on a cron job too, so it names Codex here and is
|
|
70
|
+
not read as a person being there.
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
agent: str
|
|
74
|
+
variable: str
|
|
75
|
+
conversation: bool
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
#: Every marker, grouped by agent in precedence order.
|
|
79
|
+
#:
|
|
80
|
+
#: Presence of a non-empty value is the signal and the value is never read: these are the hosts'
|
|
81
|
+
#: variables, and their values are theirs to change. A coding agent outranks ``ci``, so
|
|
82
|
+
#: ``claude -p`` inside a GitHub Action reports ``claude-code``. Nothing that every terminal of an
|
|
83
|
+
#: editor exports is listed, because a person typing there would read as the agent.
|
|
84
|
+
AGENT_MARKERS: tuple[AgentMarker, ...] = (
|
|
85
|
+
AgentMarker(AGENT_CLAUDE_CODE, "CLAUDECODE", True),
|
|
86
|
+
AgentMarker(AGENT_CLAUDE_CODE, "CLAUDE_CODE_SESSION", True),
|
|
87
|
+
AgentMarker(AGENT_CODEX, "CODEX_SESSION", True),
|
|
88
|
+
AgentMarker(AGENT_CODEX, "CODEX_SANDBOX", False),
|
|
89
|
+
AgentMarker(AGENT_CODEX, "CODEX_SANDBOX_NETWORK_DISABLED", False),
|
|
90
|
+
AgentMarker(AGENT_GEMINI_CLI, "GEMINI_CLI", False),
|
|
91
|
+
AgentMarker(AGENT_CURSOR, "CURSOR_AGENT", False),
|
|
92
|
+
AgentMarker(AGENT_CI, "CI", False),
|
|
93
|
+
AgentMarker(AGENT_CI, "GITHUB_ACTIONS", False),
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
#: Every value :data:`AGENT_HEADER` can carry.
|
|
97
|
+
AGENTS: tuple[str, ...] = (*dict.fromkeys(marker.agent for marker in AGENT_MARKERS), AGENT_NONE)
|
|
98
|
+
|
|
99
|
+
#: What :func:`invocation_id` returns: 16 random bytes as 32 lowercase hex digits.
|
|
100
|
+
INVOCATION_ID_PATTERN = r"^[0-9a-f]{32}$"
|
|
101
|
+
|
|
102
|
+
_invocation: str | None = None
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@cache
|
|
106
|
+
def client_user_agent() -> str:
|
|
107
|
+
"""Return the ``User-Agent`` this client presents to Mostly Right.
|
|
108
|
+
|
|
109
|
+
Cached because the answer is a property of the installed environment, and reading distribution
|
|
110
|
+
metadata walks ``sys.path``; a command that makes twenty calls would otherwise pay for it
|
|
111
|
+
twenty times.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
try:
|
|
115
|
+
installed = version(DISTRIBUTION_NAME)
|
|
116
|
+
except PackageNotFoundError:
|
|
117
|
+
installed = UNINSTALLED_VERSION
|
|
118
|
+
return f"{DISTRIBUTION_NAME}/{installed} {CRAWLER_CONTACT_SEGMENT}"
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def with_user_agent(headers: Mapping[str, str]) -> dict[str, str]:
|
|
122
|
+
"""Return ``headers`` as a new dict carrying this client's identity.
|
|
123
|
+
|
|
124
|
+
A caller that stated its own ``User-Agent`` keeps it, under whatever spelling it used: HTTP
|
|
125
|
+
header names are case-insensitive, so adding a second one under a different capitalization
|
|
126
|
+
would send two identities rather than override one.
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
resolved = dict(headers)
|
|
130
|
+
if any(name.lower() == "user-agent" for name in resolved):
|
|
131
|
+
return resolved
|
|
132
|
+
resolved[_USER_AGENT_HEADER] = client_user_agent()
|
|
133
|
+
return resolved
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def agent_env(agent: str) -> tuple[str, ...]:
|
|
137
|
+
"""Return the variables that name ``agent``; empty for ``none`` and for a name not listed."""
|
|
138
|
+
|
|
139
|
+
return tuple(marker.variable for marker in AGENT_MARKERS if marker.agent == agent)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def conversation_env() -> tuple[str, ...]:
|
|
143
|
+
"""Return the markers the attendance check reads as a conversation existing."""
|
|
144
|
+
|
|
145
|
+
return tuple(marker.variable for marker in AGENT_MARKERS if marker.conversation)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def first_set(names: tuple[str, ...], environ: Mapping[str, str] | None = None) -> str | None:
|
|
149
|
+
"""Return the first of ``names`` set to a non-empty value, or ``None``."""
|
|
150
|
+
|
|
151
|
+
table = os.environ if environ is None else environ
|
|
152
|
+
return next((name for name in names if (table.get(name) or "").strip()), None)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def detect_agent(environ: Mapping[str, str] | None = None) -> str:
|
|
156
|
+
"""Return the agent driving this process, one of :data:`AGENTS`."""
|
|
157
|
+
|
|
158
|
+
table = os.environ if environ is None else environ
|
|
159
|
+
for marker in AGENT_MARKERS:
|
|
160
|
+
if (table.get(marker.variable) or "").strip():
|
|
161
|
+
return marker.agent
|
|
162
|
+
return AGENT_NONE
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def begin_invocation() -> str:
|
|
166
|
+
"""Draw a fresh invocation id for the command starting now, and return it.
|
|
167
|
+
|
|
168
|
+
Called by the ``mr-data`` entry point once per command. A program importing this package
|
|
169
|
+
never calls it, so its requests carry no invocation id rather than one that lasts as long as
|
|
170
|
+
the process does.
|
|
171
|
+
"""
|
|
172
|
+
|
|
173
|
+
global _invocation
|
|
174
|
+
_invocation = secrets.token_hex(16)
|
|
175
|
+
return _invocation
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def end_invocation() -> None:
|
|
179
|
+
"""Forget the current invocation id, so later requests carry none."""
|
|
180
|
+
|
|
181
|
+
global _invocation
|
|
182
|
+
_invocation = None
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def invocation_id() -> str | None:
|
|
186
|
+
"""Return the current command's id (see :data:`INVOCATION_ID_PATTERN`), or ``None``."""
|
|
187
|
+
|
|
188
|
+
return _invocation
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def agent_headers(environ: Mapping[str, str] | None = None) -> dict[str, str]:
|
|
192
|
+
"""Return the agent and invocation headers, or none when :data:`NO_AGENT_HEADERS_ENV` is set.
|
|
193
|
+
|
|
194
|
+
The invocation header is present only inside a command :func:`begin_invocation` started. A
|
|
195
|
+
first-party call adds these itself; the transport never does.
|
|
196
|
+
"""
|
|
197
|
+
|
|
198
|
+
table = os.environ if environ is None else environ
|
|
199
|
+
if (table.get(NO_AGENT_HEADERS_ENV) or "").strip() not in ("", "0"):
|
|
200
|
+
return {}
|
|
201
|
+
headers = {AGENT_HEADER: detect_agent(table)}
|
|
202
|
+
if _invocation is not None:
|
|
203
|
+
headers[INVOCATION_HEADER] = _invocation
|
|
204
|
+
return headers
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
__all__ = [
|
|
208
|
+
"AGENTS",
|
|
209
|
+
"AGENT_CI",
|
|
210
|
+
"AGENT_CLAUDE_CODE",
|
|
211
|
+
"AGENT_CODEX",
|
|
212
|
+
"AGENT_CURSOR",
|
|
213
|
+
"AGENT_GEMINI_CLI",
|
|
214
|
+
"AGENT_HEADER",
|
|
215
|
+
"AGENT_MARKERS",
|
|
216
|
+
"AGENT_NONE",
|
|
217
|
+
"CRAWLER_CONTACT_SEGMENT",
|
|
218
|
+
"DISTRIBUTION_NAME",
|
|
219
|
+
"INVOCATION_HEADER",
|
|
220
|
+
"INVOCATION_ID_PATTERN",
|
|
221
|
+
"NO_AGENT_HEADERS_ENV",
|
|
222
|
+
"UNINSTALLED_VERSION",
|
|
223
|
+
"AgentMarker",
|
|
224
|
+
"agent_env",
|
|
225
|
+
"agent_headers",
|
|
226
|
+
"begin_invocation",
|
|
227
|
+
"client_user_agent",
|
|
228
|
+
"conversation_env",
|
|
229
|
+
"detect_agent",
|
|
230
|
+
"end_invocation",
|
|
231
|
+
"first_set",
|
|
232
|
+
"invocation_id",
|
|
233
|
+
"with_user_agent",
|
|
234
|
+
]
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_public.py
RENAMED
|
@@ -52,7 +52,7 @@ from mostlyright.data_harness.thin.transport import (
|
|
|
52
52
|
UrlLibTransport,
|
|
53
53
|
service_origin,
|
|
54
54
|
)
|
|
55
|
-
from mostlyright.data_harness.thin.user_agent import with_user_agent
|
|
55
|
+
from mostlyright.data_harness.thin.user_agent import agent_headers, with_user_agent
|
|
56
56
|
from mostlyright.data_harness.ux.credentials import (
|
|
57
57
|
CLOUD_URL_ENV,
|
|
58
58
|
DEFAULT_CLOUD_URL,
|
|
@@ -245,6 +245,7 @@ class PublicCatalogClient:
|
|
|
245
245
|
{
|
|
246
246
|
"Accept": accept,
|
|
247
247
|
CLIENT_HEADER: CLIENT_NAME,
|
|
248
|
+
**agent_headers(),
|
|
248
249
|
}
|
|
249
250
|
)
|
|
250
251
|
|
|
@@ -960,6 +961,7 @@ class PublicQueryClient(CloudClient):
|
|
|
960
961
|
headers = {
|
|
961
962
|
"Accept": "application/json",
|
|
962
963
|
"Authorization": f"Bearer {self._credentials.raw_key}",
|
|
964
|
+
**agent_headers(),
|
|
963
965
|
}
|
|
964
966
|
status, raw, response_headers = self._transport.request(
|
|
965
967
|
"GET",
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_query.py
RENAMED
|
@@ -75,6 +75,7 @@ from mostlyright.data_harness.thin.transport import (
|
|
|
75
75
|
Transport,
|
|
76
76
|
UrlLibTransport,
|
|
77
77
|
)
|
|
78
|
+
from mostlyright.data_harness.thin.user_agent import agent_headers
|
|
78
79
|
from mostlyright.data_harness.thin.v4 import (
|
|
79
80
|
GET_RUN_PATH,
|
|
80
81
|
GET_RUN_QUERY_PATH,
|
|
@@ -329,6 +330,7 @@ class CloudRunQueryClient(CloudClient):
|
|
|
329
330
|
headers = {
|
|
330
331
|
"Accept": "application/json",
|
|
331
332
|
"Authorization": f"Bearer {self._credentials.raw_key}",
|
|
333
|
+
**agent_headers(),
|
|
332
334
|
}
|
|
333
335
|
encoded: bytes | None = None
|
|
334
336
|
if body is not None:
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/attendance.py
RENAMED
|
@@ -107,6 +107,13 @@ from collections.abc import Mapping, Sequence
|
|
|
107
107
|
from dataclasses import dataclass
|
|
108
108
|
from typing import Any
|
|
109
109
|
|
|
110
|
+
from mostlyright.data_harness.thin.user_agent import (
|
|
111
|
+
AGENT_CI,
|
|
112
|
+
agent_env,
|
|
113
|
+
conversation_env,
|
|
114
|
+
first_set,
|
|
115
|
+
)
|
|
116
|
+
|
|
110
117
|
#: The variable the process that spawns ``mr-data`` sets to say whether the session it is driving
|
|
111
118
|
#: has a person in it. Exactly ``"1"`` is attended and exactly ``"0"`` is unattended -- and the
|
|
112
119
|
#: ``"0"`` is a veto no flag overrides, for the reason the module docstring gives. Every other value
|
|
@@ -156,7 +163,7 @@ _UNATTENDED_VALUE = "0"
|
|
|
156
163
|
#: ⚠ AND ONLY A NON-EMPTY VALUE COUNTS. A shell that exports an empty variable has said nothing,
|
|
157
164
|
#: and reading that as "a person is here" would make ``export CLAUDECODE=`` a way to turn the
|
|
158
165
|
#: inference on by accident.
|
|
159
|
-
AGENT_HOST_ENV: tuple[str, ...] = (
|
|
166
|
+
AGENT_HOST_ENV: tuple[str, ...] = conversation_env()
|
|
160
167
|
|
|
161
168
|
#: The variables a headless runner sets, which take an agent-host marker back off the table.
|
|
162
169
|
#:
|
|
@@ -170,7 +177,7 @@ AGENT_HOST_ENV: tuple[str, ...] = ("CLAUDECODE", "CLAUDE_CODE_SESSION", "CODEX_S
|
|
|
170
177
|
#: Buildkite all export it; ``GITHUB_ACTIONS`` is named beside it because the scenario this closes
|
|
171
178
|
#: is literally ``claude -p`` in a GitHub Action. Presence of a non-empty value is the whole test,
|
|
172
179
|
#: for the reason the agent-host markers give: the values are somebody else's to change.
|
|
173
|
-
HEADLESS_HOST_ENV: tuple[str, ...] = (
|
|
180
|
+
HEADLESS_HOST_ENV: tuple[str, ...] = agent_env(AGENT_CI)
|
|
174
181
|
|
|
175
182
|
|
|
176
183
|
@dataclass(frozen=True)
|
|
@@ -264,11 +271,9 @@ def resolve_attendance(
|
|
|
264
271
|
)
|
|
265
272
|
# Step 5: the host named itself, which is a conversation existing -- unless a headless runner
|
|
266
273
|
# named itself too, in which case the conversation is a print-mode one with nobody in it.
|
|
267
|
-
named =
|
|
274
|
+
named = first_set(AGENT_HOST_ENV, table)
|
|
268
275
|
if named is not None:
|
|
269
|
-
headless =
|
|
270
|
-
(name for name in HEADLESS_HOST_ENV if (table.get(name) or "").strip()), None
|
|
271
|
-
)
|
|
276
|
+
headless = first_set(HEADLESS_HOST_ENV, table)
|
|
272
277
|
if headless is not None:
|
|
273
278
|
return Attendance(
|
|
274
279
|
attended=False,
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/cloud_auth.py
RENAMED
|
@@ -16,7 +16,7 @@ from collections.abc import Callable, Mapping
|
|
|
16
16
|
from dataclasses import dataclass
|
|
17
17
|
from typing import Any, Final
|
|
18
18
|
|
|
19
|
-
from mostlyright.data_harness.thin.user_agent import with_user_agent
|
|
19
|
+
from mostlyright.data_harness.thin.user_agent import agent_headers, with_user_agent
|
|
20
20
|
|
|
21
21
|
REQUEST_TIMEOUT_SECONDS: Final = 10.0
|
|
22
22
|
MAX_RESPONSE_BYTES: Final = 64 * 1024
|
|
@@ -241,7 +241,7 @@ class CloudAuthClient:
|
|
|
241
241
|
def _request(self, method: str, path: str) -> CloudAuthResponse:
|
|
242
242
|
request = urllib.request.Request(
|
|
243
243
|
urllib.parse.urljoin(self._base_url + "/", path.lstrip("/")),
|
|
244
|
-
headers=with_user_agent({"x-api-key": self._raw_key}),
|
|
244
|
+
headers=with_user_agent({"x-api-key": self._raw_key, **agent_headers()}),
|
|
245
245
|
method=method,
|
|
246
246
|
)
|
|
247
247
|
try:
|
|
@@ -34,7 +34,12 @@ from collections.abc import Mapping
|
|
|
34
34
|
from typing import Any
|
|
35
35
|
|
|
36
36
|
from mostlyright.data_harness.thin.transport import ThinLaneError
|
|
37
|
-
from mostlyright.data_harness.ux.attendance import
|
|
37
|
+
from mostlyright.data_harness.ux.attendance import (
|
|
38
|
+
AGENT_HOST_ENV,
|
|
39
|
+
ATTENDANCE_ENV,
|
|
40
|
+
HEADLESS_HOST_ENV,
|
|
41
|
+
resolve_attendance,
|
|
42
|
+
)
|
|
38
43
|
from mostlyright.data_harness.ux.clarification import (
|
|
39
44
|
CONTRACT_ALREADY_AGREED,
|
|
40
45
|
checked_question,
|
|
@@ -118,10 +123,10 @@ def add_arguments(parser: argparse.ArgumentParser) -> None:
|
|
|
118
123
|
help=(
|
|
119
124
|
"state that a person is here to answer, which is the one reliable way to say so; an "
|
|
120
125
|
"explicit refusal, by --unattended or MOSTLYRIGHT_ATTENDED=0, still wins. Without it, "
|
|
121
|
-
"an agent host that names itself in the environment
|
|
122
|
-
"
|
|
123
|
-
"but NOT when
|
|
124
|
-
"is headless. A cron job carries none of these and stays unattended"
|
|
126
|
+
"an agent host that names itself in the environment "
|
|
127
|
+
f"({', '.join(AGENT_HOST_ENV)}) is read as a conversation with somebody in it -- "
|
|
128
|
+
f"but NOT when {' or '.join(HEADLESS_HOST_ENV)} is set beside it, because an agent "
|
|
129
|
+
"host on a runner is headless. A cron job carries none of these and stays unattended"
|
|
125
130
|
),
|
|
126
131
|
)
|
|
127
132
|
presence.add_argument(
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/login.py
RENAMED
|
@@ -49,6 +49,7 @@ from urllib.request import (
|
|
|
49
49
|
|
|
50
50
|
from mostlyright.data_harness.canonical import CanonicalJSONError, parse_foreign_json
|
|
51
51
|
from mostlyright.data_harness.key_seam import LEGACY_API_KEY_ENV
|
|
52
|
+
from mostlyright.data_harness.thin.user_agent import agent_headers
|
|
52
53
|
from mostlyright.data_harness.ux.cloud_auth import CloudAuthClient, CloudAuthError
|
|
53
54
|
from mostlyright.data_harness.ux.credential_store import (
|
|
54
55
|
CredentialEnvelope,
|
|
@@ -291,7 +292,11 @@ def _post_json(
|
|
|
291
292
|
"""
|
|
292
293
|
|
|
293
294
|
body = json.dumps(dict(payload), sort_keys=True).encode("utf-8")
|
|
294
|
-
request_headers = {
|
|
295
|
+
request_headers = {
|
|
296
|
+
"Content-Type": "application/json",
|
|
297
|
+
"Accept": "application/json",
|
|
298
|
+
**agent_headers(),
|
|
299
|
+
}
|
|
295
300
|
request_headers.update(headers or {})
|
|
296
301
|
try:
|
|
297
302
|
status, raw = transport.request("POST", url, request_headers, body, MAX_RESPONSE_BYTES)
|
|
@@ -324,7 +329,7 @@ def _get_json(
|
|
|
324
329
|
caller reads a 404 as "this cloud does not offer the endpoint yet" rather than as a failure.
|
|
325
330
|
"""
|
|
326
331
|
|
|
327
|
-
request_headers = {"Accept": "application/json"}
|
|
332
|
+
request_headers = {"Accept": "application/json", **agent_headers()}
|
|
328
333
|
request_headers.update(headers or {})
|
|
329
334
|
try:
|
|
330
335
|
status, raw = transport.request("GET", url, request_headers, None, MAX_RESPONSE_BYTES)
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
"""The identity every first-party request to Mostly Right states.
|
|
2
|
-
|
|
3
|
-
Without it the standard library sends ``Python-urllib/3.x``, which is what every unattended
|
|
4
|
-
script on the internet sends: the CLI's own traffic could not be told apart from anything else in
|
|
5
|
-
a server log, so nothing downstream could measure it, rate-limit it separately, or exempt it.
|
|
6
|
-
|
|
7
|
-
The name follows the convention the two crawler lanes already use -- a product token, a version,
|
|
8
|
-
and the contact segment that says where to reach the people running it -- so an origin and our own
|
|
9
|
-
logs see one family of identities from this deployment rather than one per code path.
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
from __future__ import annotations
|
|
13
|
-
|
|
14
|
-
from collections.abc import Mapping
|
|
15
|
-
from functools import cache
|
|
16
|
-
from importlib.metadata import PackageNotFoundError, version
|
|
17
|
-
|
|
18
|
-
#: The contact segment ``hosted_worker.CRAWLER_CONTACT_SEGMENT`` states for the keyed-source
|
|
19
|
-
#: agents and ``hosted_crawler_fetch.PUBLIC_HTTPS_USER_AGENT`` carries for public sources, with
|
|
20
|
-
#: the measurement that makes it load-bearing recorded at the first of those.
|
|
21
|
-
#:
|
|
22
|
-
#: It is spelled again here rather than imported because both of those modules import ``pyarrow``
|
|
23
|
-
#: at module scope and this package installs with no compiled extension at all -- and they are
|
|
24
|
-
#: Studio's now, so importing them is not a choice this repository has. The spellings are held
|
|
25
|
-
#: against each other by ``tests/test_thin_user_agent.py`` under
|
|
26
|
-
#: ``make verify-cross-repo STUDIO_ROOT=...``, which reads the other one out of Studio's source.
|
|
27
|
-
CRAWLER_CONTACT_SEGMENT = "(+https://mostlyright.md/crawler; crawler@mostlyright.md)"
|
|
28
|
-
|
|
29
|
-
#: The distribution this client is installed as, and the product token it therefore reports.
|
|
30
|
-
DISTRIBUTION_NAME = "mostlyright-data"
|
|
31
|
-
|
|
32
|
-
#: The version reported from a source tree, where no distribution metadata exists to read. A
|
|
33
|
-
#: number rather than a word, so every value this header can carry parses the same way.
|
|
34
|
-
UNINSTALLED_VERSION = "0.0.0"
|
|
35
|
-
|
|
36
|
-
_USER_AGENT_HEADER = "User-Agent"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
@cache
|
|
40
|
-
def client_user_agent() -> str:
|
|
41
|
-
"""Return the ``User-Agent`` this client presents to Mostly Right.
|
|
42
|
-
|
|
43
|
-
Cached because the answer is a property of the installed environment, and reading distribution
|
|
44
|
-
metadata walks ``sys.path``; a command that makes twenty calls would otherwise pay for it
|
|
45
|
-
twenty times.
|
|
46
|
-
"""
|
|
47
|
-
|
|
48
|
-
try:
|
|
49
|
-
installed = version(DISTRIBUTION_NAME)
|
|
50
|
-
except PackageNotFoundError:
|
|
51
|
-
installed = UNINSTALLED_VERSION
|
|
52
|
-
return f"{DISTRIBUTION_NAME}/{installed} {CRAWLER_CONTACT_SEGMENT}"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def with_user_agent(headers: Mapping[str, str]) -> dict[str, str]:
|
|
56
|
-
"""Return ``headers`` as a new dict carrying this client's identity.
|
|
57
|
-
|
|
58
|
-
A caller that stated its own ``User-Agent`` keeps it, under whatever spelling it used: HTTP
|
|
59
|
-
header names are case-insensitive, so adding a second one under a different capitalization
|
|
60
|
-
would send two identities rather than override one.
|
|
61
|
-
"""
|
|
62
|
-
|
|
63
|
-
resolved = dict(headers)
|
|
64
|
-
if any(name.lower() == "user-agent" for name in resolved):
|
|
65
|
-
return resolved
|
|
66
|
-
resolved[_USER_AGENT_HEADER] = client_user_agent()
|
|
67
|
-
return resolved
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
__all__ = [
|
|
71
|
-
"CRAWLER_CONTACT_SEGMENT",
|
|
72
|
-
"DISTRIBUTION_NAME",
|
|
73
|
-
"UNINSTALLED_VERSION",
|
|
74
|
-
"client_user_agent",
|
|
75
|
-
"with_user_agent",
|
|
76
|
-
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/agents/openai.yaml
RENAMED
|
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
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/boundaries.md
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/commands.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/live-run.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/one-install.md
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/patterns.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/promote.md
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/readers.md
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/receipts.md
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/recipe-test.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/sources.md
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/skills/mr-data-build/references/transforms.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/__init__.py
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/agent_protocol.py
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/canonical.py
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/formats.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/key_seam.py
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/page_coverage.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/session_probes.py
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/skill_assets.py
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/table_manifest.py
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/__init__.py
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/acquire.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/activity.py
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/approvals.py
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/backoff.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/commands.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/delivery.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/download.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/narrative.py
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/parity.py
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/probe.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/propose.py
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/recipe.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/research.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/support.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/transport.py
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4.py
RENAMED
|
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
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_reader.py
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_runs.py
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_search.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_stream.py
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/thin/v4_tables.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/credentials.py
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/path_kind.py
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/plain_file.py
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/remediation.py
RENAMED
|
File without changes
|
{mostlyright_data-0.31.12 → mostlyright_data-0.31.13}/src/mostlyright/data_harness/ux/render.py
RENAMED
|
File without changes
|