@r1z4x/tezgah 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +738 -0
- package/LICENSE +21 -0
- package/MANIFEST +753 -0
- package/README.de.md +169 -0
- package/README.es.md +168 -0
- package/README.fr.md +166 -0
- package/README.md +161 -0
- package/README.tr.md +163 -0
- package/agents/tezgah-reviewer.md +70 -0
- package/bin/codegen +337 -0
- package/bin/consult +797 -0
- package/bin/tezgah-adhd +50 -0
- package/bin/tezgah-agents +45 -0
- package/bin/tezgah-capture +66 -0
- package/bin/tezgah-context +96 -0
- package/bin/tezgah-decisions +213 -0
- package/bin/tezgah-design +953 -0
- package/bin/tezgah-docs +1199 -0
- package/bin/tezgah-doctor +497 -0
- package/bin/tezgah-dsh +37 -0
- package/bin/tezgah-dsh.cmd +70 -0
- package/bin/tezgah-gate +75 -0
- package/bin/tezgah-import-ai-research +439 -0
- package/bin/tezgah-index +32 -0
- package/bin/tezgah-lessons +148 -0
- package/bin/tezgah-mcp +322 -0
- package/bin/tezgah-migrate +324 -0
- package/bin/tezgah-pony +50 -0
- package/bin/tezgah-research +772 -0
- package/bin/tezgah-rollback +93 -0
- package/bin/tezgah-route +124 -0
- package/bin/tezgah-setup +5798 -0
- package/bin/tezgah-status +383 -0
- package/bin/tezgah-task +607 -0
- package/bin/tezgah-taste +423 -0
- package/bin/tezgah-triage +485 -0
- package/bin/tezgah.js +36 -0
- package/commands/adhd.md +21 -0
- package/commands/ponytail.md +21 -0
- package/docs/README.md +112 -0
- package/docs/architecture.md +226 -0
- package/docs/citations-baseline.json +59 -0
- package/docs/clarity-baseline.json +116 -0
- package/docs/contract.md +416 -0
- package/docs/environment.md +141 -0
- package/docs/evidence.md +831 -0
- package/docs/feature-audit.md +139 -0
- package/docs/gate.md +407 -0
- package/docs/glossary.md +201 -0
- package/docs/hosts.md +400 -0
- package/docs/index.json +471 -0
- package/docs/judge.md +193 -0
- package/docs/layers.md +189 -0
- package/docs/models.md +160 -0
- package/docs/operations.md +666 -0
- package/docs/research.md +809 -0
- package/docs/results/paired-outcome-2026-10.jsonl +254 -0
- package/docs/results/paired-outcome-2026-10.md +204 -0
- package/docs/skills.md +236 -0
- package/docs/status-line.md +315 -0
- package/docs/testing.md +287 -0
- package/docs/vision.md +117 -0
- package/hooks/hooks.json +33 -0
- package/hooks/projects-auto-init.py +98 -0
- package/hooks/projects-posttooluse.py +149 -0
- package/hooks/projects-pretooluse.py +40 -0
- package/hooks/projects-stop.py +60 -0
- package/hooks/tezgah_agents.py +817 -0
- package/hooks/tezgah_apps.py +266 -0
- package/hooks/tezgah_attest.py +255 -0
- package/hooks/tezgah_clarity.py +171 -0
- package/hooks/tezgah_components.py +140 -0
- package/hooks/tezgah_context.py +2953 -0
- package/hooks/tezgah_embed.py +765 -0
- package/hooks/tezgah_gate.py +2736 -0
- package/hooks/tezgah_guard.py +177 -0
- package/hooks/tezgah_index.py +124 -0
- package/hooks/tezgah_integrity.py +5141 -0
- package/hooks/tezgah_judge.py +487 -0
- package/hooks/tezgah_lang.py +230 -0
- package/hooks/tezgah_lessons.py +210 -0
- package/hooks/tezgah_models.py +855 -0
- package/hooks/tezgah_paths.py +1132 -0
- package/hooks/tezgah_policy.py +1039 -0
- package/hooks/tezgah_rank.py +77 -0
- package/hooks/tezgah_replay.py +1109 -0
- package/hooks/tezgah_research.py +5176 -0
- package/hooks/tezgah_shapes.py +305 -0
- package/hooks/tezgah_skill_pick.py +227 -0
- package/hooks/tezgah_snapshot.py +490 -0
- package/hooks/tezgah_stopspec.py +320 -0
- package/hooks/tezgah_task.py +458 -0
- package/hooks/tezgah_taste.py +201 -0
- package/hooks/tezgah_untrusted.py +112 -0
- package/hooks/tezgah_update.py +430 -0
- package/hosts/codex/hook.py +268 -0
- package/hosts/codex/hooks.json +26 -0
- package/hosts/cursor/hook.py +461 -0
- package/hosts/cursor/hooks.json +44 -0
- package/hosts/dsh/hooks.json +21 -0
- package/hosts/dsh/statusline/lib/client.js +138 -0
- package/hosts/dsh/statusline/lib/index.js +104 -0
- package/hosts/dsh/statusline/package.json +28 -0
- package/hosts/omp/hook.py +277 -0
- package/hosts/omp/tezgah-hook.ts.in +701 -0
- package/hosts/opencode/plugins/tezgah.js +2742 -0
- package/hosts/opencode/tui/tezgah-tui.tsx +151 -0
- package/output-styles/tezgah.md +142 -0
- package/package.json +32 -0
- package/packaging/build.sh +342 -0
- package/packaging/install.ps1 +166 -0
- package/packaging/install.sh +56 -0
- package/packaging/upgrade.sh +142 -0
- package/skills/ai-research/0-autoresearch-skill/SKILL.md +411 -0
- package/skills/ai-research/0-autoresearch-skill/references/agent-continuity.md +95 -0
- package/skills/ai-research/0-autoresearch-skill/references/progress-reporting.md +166 -0
- package/skills/ai-research/0-autoresearch-skill/references/skill-routing.md +219 -0
- package/skills/ai-research/0-autoresearch-skill/templates/findings.md +44 -0
- package/skills/ai-research/0-autoresearch-skill/templates/research-log.md +41 -0
- package/skills/ai-research/01-model-architecture/litgpt/SKILL.md +469 -0
- package/skills/ai-research/01-model-architecture/litgpt/references/custom-models.md +569 -0
- package/skills/ai-research/01-model-architecture/litgpt/references/distributed-training.md +452 -0
- package/skills/ai-research/01-model-architecture/litgpt/references/supported-models.md +337 -0
- package/skills/ai-research/01-model-architecture/litgpt/references/training-recipes.md +620 -0
- package/skills/ai-research/01-model-architecture/mamba/SKILL.md +260 -0
- package/skills/ai-research/01-model-architecture/mamba/references/architecture-details.md +207 -0
- package/skills/ai-research/01-model-architecture/mamba/references/benchmarks.md +256 -0
- package/skills/ai-research/01-model-architecture/mamba/references/training-guide.md +389 -0
- package/skills/ai-research/01-model-architecture/nanogpt/SKILL.md +290 -0
- package/skills/ai-research/01-model-architecture/nanogpt/references/architecture.md +383 -0
- package/skills/ai-research/01-model-architecture/nanogpt/references/data.md +477 -0
- package/skills/ai-research/01-model-architecture/nanogpt/references/training.md +565 -0
- package/skills/ai-research/01-model-architecture/rwkv/SKILL.md +260 -0
- package/skills/ai-research/01-model-architecture/rwkv/references/architecture-details.md +345 -0
- package/skills/ai-research/01-model-architecture/rwkv/references/rwkv7.md +387 -0
- package/skills/ai-research/01-model-architecture/rwkv/references/state-management.md +370 -0
- package/skills/ai-research/01-model-architecture/torchtitan/SKILL.md +358 -0
- package/skills/ai-research/01-model-architecture/torchtitan/references/checkpoint.md +182 -0
- package/skills/ai-research/01-model-architecture/torchtitan/references/custom-models.md +259 -0
- package/skills/ai-research/01-model-architecture/torchtitan/references/float8.md +134 -0
- package/skills/ai-research/01-model-architecture/torchtitan/references/fsdp.md +127 -0
- package/skills/ai-research/02-tokenization/huggingface-tokenizers/SKILL.md +516 -0
- package/skills/ai-research/02-tokenization/huggingface-tokenizers/references/algorithms.md +654 -0
- package/skills/ai-research/02-tokenization/huggingface-tokenizers/references/integration.md +638 -0
- package/skills/ai-research/02-tokenization/huggingface-tokenizers/references/pipeline.md +724 -0
- package/skills/ai-research/02-tokenization/huggingface-tokenizers/references/training.md +566 -0
- package/skills/ai-research/02-tokenization/sentencepiece/SKILL.md +235 -0
- package/skills/ai-research/02-tokenization/sentencepiece/references/algorithms.md +201 -0
- package/skills/ai-research/02-tokenization/sentencepiece/references/training.md +305 -0
- package/skills/ai-research/03-fine-tuning/axolotl/SKILL.md +158 -0
- package/skills/ai-research/03-fine-tuning/axolotl/references/api.md +5549 -0
- package/skills/ai-research/03-fine-tuning/axolotl/references/dataset-formats.md +1030 -0
- package/skills/ai-research/03-fine-tuning/axolotl/references/index.md +16 -0
- package/skills/ai-research/03-fine-tuning/axolotl/references/other.md +3564 -0
- package/skills/ai-research/03-fine-tuning/llama-factory/SKILL.md +80 -0
- package/skills/ai-research/03-fine-tuning/llama-factory/references/_images.md +24 -0
- package/skills/ai-research/03-fine-tuning/llama-factory/references/advanced.md +1056 -0
- package/skills/ai-research/03-fine-tuning/llama-factory/references/getting_started.md +350 -0
- package/skills/ai-research/03-fine-tuning/llama-factory/references/index.md +20 -0
- package/skills/ai-research/03-fine-tuning/llama-factory/references/other.md +32 -0
- package/skills/ai-research/03-fine-tuning/peft/SKILL.md +431 -0
- package/skills/ai-research/03-fine-tuning/peft/references/advanced-usage.md +515 -0
- package/skills/ai-research/03-fine-tuning/peft/references/troubleshooting.md +481 -0
- package/skills/ai-research/03-fine-tuning/unsloth/SKILL.md +80 -0
- package/skills/ai-research/03-fine-tuning/unsloth/references/index.md +8 -0
- package/skills/ai-research/03-fine-tuning/unsloth/references/llms.md +83 -0
- package/skills/ai-research/04-mechanistic-interpretability/nnsight/SKILL.md +436 -0
- package/skills/ai-research/04-mechanistic-interpretability/nnsight/references/README.md +79 -0
- package/skills/ai-research/04-mechanistic-interpretability/nnsight/references/api.md +345 -0
- package/skills/ai-research/04-mechanistic-interpretability/nnsight/references/tutorials.md +301 -0
- package/skills/ai-research/04-mechanistic-interpretability/pyvene/SKILL.md +473 -0
- package/skills/ai-research/04-mechanistic-interpretability/pyvene/references/README.md +74 -0
- package/skills/ai-research/04-mechanistic-interpretability/pyvene/references/api.md +384 -0
- package/skills/ai-research/04-mechanistic-interpretability/pyvene/references/tutorials.md +377 -0
- package/skills/ai-research/04-mechanistic-interpretability/saelens/SKILL.md +386 -0
- package/skills/ai-research/04-mechanistic-interpretability/saelens/references/README.md +71 -0
- package/skills/ai-research/04-mechanistic-interpretability/saelens/references/api.md +334 -0
- package/skills/ai-research/04-mechanistic-interpretability/saelens/references/tutorials.md +319 -0
- package/skills/ai-research/04-mechanistic-interpretability/transformer-lens/SKILL.md +346 -0
- package/skills/ai-research/04-mechanistic-interpretability/transformer-lens/references/README.md +55 -0
- package/skills/ai-research/04-mechanistic-interpretability/transformer-lens/references/api.md +363 -0
- package/skills/ai-research/04-mechanistic-interpretability/transformer-lens/references/tutorials.md +340 -0
- package/skills/ai-research/05-data-processing/nemo-curator/SKILL.md +383 -0
- package/skills/ai-research/05-data-processing/nemo-curator/references/deduplication.md +88 -0
- package/skills/ai-research/05-data-processing/nemo-curator/references/filtering.md +103 -0
- package/skills/ai-research/05-data-processing/ray-data/SKILL.md +326 -0
- package/skills/ai-research/05-data-processing/ray-data/references/integration.md +83 -0
- package/skills/ai-research/05-data-processing/ray-data/references/transformations.md +84 -0
- package/skills/ai-research/06-post-training/grpo-rl-training/README.md +98 -0
- package/skills/ai-research/06-post-training/grpo-rl-training/SKILL.md +572 -0
- package/skills/ai-research/06-post-training/miles/SKILL.md +315 -0
- package/skills/ai-research/06-post-training/miles/references/api-reference.md +142 -0
- package/skills/ai-research/06-post-training/miles/references/troubleshooting.md +353 -0
- package/skills/ai-research/06-post-training/openrlhf/SKILL.md +249 -0
- package/skills/ai-research/06-post-training/openrlhf/references/algorithm-comparison.md +405 -0
- package/skills/ai-research/06-post-training/openrlhf/references/custom-rewards.md +531 -0
- package/skills/ai-research/06-post-training/openrlhf/references/hybrid-engine.md +288 -0
- package/skills/ai-research/06-post-training/openrlhf/references/multi-node-training.md +455 -0
- package/skills/ai-research/06-post-training/simpo/SKILL.md +219 -0
- package/skills/ai-research/06-post-training/simpo/references/datasets.md +479 -0
- package/skills/ai-research/06-post-training/simpo/references/hyperparameters.md +453 -0
- package/skills/ai-research/06-post-training/simpo/references/loss-functions.md +351 -0
- package/skills/ai-research/06-post-training/slime/SKILL.md +464 -0
- package/skills/ai-research/06-post-training/slime/references/api-reference.md +393 -0
- package/skills/ai-research/06-post-training/slime/references/troubleshooting.md +387 -0
- package/skills/ai-research/06-post-training/torchforge/SKILL.md +433 -0
- package/skills/ai-research/06-post-training/torchforge/references/api-reference.md +328 -0
- package/skills/ai-research/06-post-training/torchforge/references/troubleshooting.md +410 -0
- package/skills/ai-research/06-post-training/trl-fine-tuning/SKILL.md +455 -0
- package/skills/ai-research/06-post-training/trl-fine-tuning/references/dpo-variants.md +228 -0
- package/skills/ai-research/06-post-training/trl-fine-tuning/references/online-rl.md +83 -0
- package/skills/ai-research/06-post-training/trl-fine-tuning/references/reward-modeling.md +123 -0
- package/skills/ai-research/06-post-training/trl-fine-tuning/references/sft-training.md +169 -0
- package/skills/ai-research/06-post-training/verl/SKILL.md +391 -0
- package/skills/ai-research/06-post-training/verl/references/api-reference.md +302 -0
- package/skills/ai-research/06-post-training/verl/references/troubleshooting.md +392 -0
- package/skills/ai-research/07-safety-alignment/constitutional-ai/SKILL.md +290 -0
- package/skills/ai-research/07-safety-alignment/llamaguard/SKILL.md +337 -0
- package/skills/ai-research/07-safety-alignment/nemo-guardrails/SKILL.md +297 -0
- package/skills/ai-research/07-safety-alignment/prompt-guard/SKILL.md +312 -0
- package/skills/ai-research/08-distributed-training/accelerate/SKILL.md +332 -0
- package/skills/ai-research/08-distributed-training/accelerate/references/custom-plugins.md +454 -0
- package/skills/ai-research/08-distributed-training/accelerate/references/megatron-integration.md +490 -0
- package/skills/ai-research/08-distributed-training/accelerate/references/performance.md +526 -0
- package/skills/ai-research/08-distributed-training/deepspeed/SKILL.md +141 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/08.md +18 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/09.md +174 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/2020.md +379 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/2023.md +280 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/assets.md +180 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/index.md +36 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/mii.md +119 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/other.md +1192 -0
- package/skills/ai-research/08-distributed-training/megatron-core/SKILL.md +366 -0
- package/skills/ai-research/08-distributed-training/megatron-core/references/benchmarks.md +250 -0
- package/skills/ai-research/08-distributed-training/megatron-core/references/parallelism-guide.md +405 -0
- package/skills/ai-research/08-distributed-training/megatron-core/references/production-examples.md +474 -0
- package/skills/ai-research/08-distributed-training/megatron-core/references/training-recipes.md +548 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/SKILL.md +231 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_dcp_async_recipe.md +14 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_dcp_overview.md +19 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_dcp_recipe.md +18 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_ddp_notes.md +10 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_device_mesh_tutorial.md +22 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_examples_fsdp2.md +15 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_fsdp1_api.md +9 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_fsdp2_tutorial.md +45 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_fully_shard_api.md +49 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_tp_tutorial.md +22 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/ray_train_fsdp2_example.md +13 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/torchtitan_fsdp_notes.md +14 -0
- package/skills/ai-research/08-distributed-training/pytorch-lightning/SKILL.md +346 -0
- package/skills/ai-research/08-distributed-training/pytorch-lightning/references/callbacks.md +437 -0
- package/skills/ai-research/08-distributed-training/pytorch-lightning/references/distributed.md +491 -0
- package/skills/ai-research/08-distributed-training/pytorch-lightning/references/hyperparameter-tuning.md +557 -0
- package/skills/ai-research/08-distributed-training/ray-train/SKILL.md +406 -0
- package/skills/ai-research/08-distributed-training/ray-train/references/multi-node.md +629 -0
- package/skills/ai-research/09-infrastructure/lambda-labs/SKILL.md +545 -0
- package/skills/ai-research/09-infrastructure/lambda-labs/references/advanced-usage.md +612 -0
- package/skills/ai-research/09-infrastructure/lambda-labs/references/troubleshooting.md +531 -0
- package/skills/ai-research/09-infrastructure/modal/SKILL.md +341 -0
- package/skills/ai-research/09-infrastructure/modal/references/advanced-usage.md +504 -0
- package/skills/ai-research/09-infrastructure/modal/references/troubleshooting.md +495 -0
- package/skills/ai-research/09-infrastructure/skypilot/SKILL.md +509 -0
- package/skills/ai-research/09-infrastructure/skypilot/references/advanced-usage.md +492 -0
- package/skills/ai-research/09-infrastructure/skypilot/references/troubleshooting.md +571 -0
- package/skills/ai-research/10-optimization/awq/SKILL.md +310 -0
- package/skills/ai-research/10-optimization/awq/references/advanced-usage.md +325 -0
- package/skills/ai-research/10-optimization/awq/references/troubleshooting.md +345 -0
- package/skills/ai-research/10-optimization/bitsandbytes/SKILL.md +411 -0
- package/skills/ai-research/10-optimization/bitsandbytes/references/memory-optimization.md +522 -0
- package/skills/ai-research/10-optimization/bitsandbytes/references/qlora-training.md +522 -0
- package/skills/ai-research/10-optimization/bitsandbytes/references/quantization-formats.md +448 -0
- package/skills/ai-research/10-optimization/flash-attention/SKILL.md +367 -0
- package/skills/ai-research/10-optimization/flash-attention/references/benchmarks.md +216 -0
- package/skills/ai-research/10-optimization/flash-attention/references/transformers-integration.md +294 -0
- package/skills/ai-research/10-optimization/gguf/SKILL.md +427 -0
- package/skills/ai-research/10-optimization/gguf/references/advanced-usage.md +505 -0
- package/skills/ai-research/10-optimization/gguf/references/troubleshooting.md +443 -0
- package/skills/ai-research/10-optimization/gptq/SKILL.md +450 -0
- package/skills/ai-research/10-optimization/gptq/references/calibration.md +338 -0
- package/skills/ai-research/10-optimization/gptq/references/integration.md +130 -0
- package/skills/ai-research/10-optimization/gptq/references/troubleshooting.md +96 -0
- package/skills/ai-research/10-optimization/hqq/SKILL.md +445 -0
- package/skills/ai-research/10-optimization/hqq/references/advanced-usage.md +529 -0
- package/skills/ai-research/10-optimization/hqq/references/troubleshooting.md +504 -0
- package/skills/ai-research/10-optimization/ml-training-recipes/SKILL.md +319 -0
- package/skills/ai-research/10-optimization/ml-training-recipes/references/architecture.md +320 -0
- package/skills/ai-research/10-optimization/ml-training-recipes/references/biomedical.md +498 -0
- package/skills/ai-research/10-optimization/ml-training-recipes/references/domain-specific.md +626 -0
- package/skills/ai-research/10-optimization/ml-training-recipes/references/experiment-loop.md +129 -0
- package/skills/ai-research/10-optimization/ml-training-recipes/references/optimizers.md +330 -0
- package/skills/ai-research/10-optimization/ml-training-recipes/references/scaling-and-selection.md +428 -0
- package/skills/ai-research/11-evaluation/bigcode-evaluation-harness/SKILL.md +405 -0
- package/skills/ai-research/11-evaluation/bigcode-evaluation-harness/references/benchmarks.md +394 -0
- package/skills/ai-research/11-evaluation/bigcode-evaluation-harness/references/custom-tasks.md +425 -0
- package/skills/ai-research/11-evaluation/bigcode-evaluation-harness/references/issues.md +395 -0
- package/skills/ai-research/11-evaluation/lm-evaluation-harness/SKILL.md +490 -0
- package/skills/ai-research/11-evaluation/lm-evaluation-harness/references/api-evaluation.md +491 -0
- package/skills/ai-research/11-evaluation/lm-evaluation-harness/references/benchmark-guide.md +489 -0
- package/skills/ai-research/11-evaluation/lm-evaluation-harness/references/custom-tasks.md +603 -0
- package/skills/ai-research/11-evaluation/lm-evaluation-harness/references/distributed-eval.md +520 -0
- package/skills/ai-research/11-evaluation/nemo-evaluator/SKILL.md +494 -0
- package/skills/ai-research/11-evaluation/nemo-evaluator/references/adapter-system.md +341 -0
- package/skills/ai-research/11-evaluation/nemo-evaluator/references/configuration.md +448 -0
- package/skills/ai-research/11-evaluation/nemo-evaluator/references/custom-benchmarks.md +316 -0
- package/skills/ai-research/11-evaluation/nemo-evaluator/references/execution-backends.md +362 -0
- package/skills/ai-research/12-inference-serving/llama-cpp/SKILL.md +258 -0
- package/skills/ai-research/12-inference-serving/llama-cpp/references/optimization.md +90 -0
- package/skills/ai-research/12-inference-serving/llama-cpp/references/quantization.md +214 -0
- package/skills/ai-research/12-inference-serving/llama-cpp/references/server.md +126 -0
- package/skills/ai-research/12-inference-serving/sglang/SKILL.md +442 -0
- package/skills/ai-research/12-inference-serving/sglang/references/deployment.md +491 -0
- package/skills/ai-research/12-inference-serving/sglang/references/radix-attention.md +414 -0
- package/skills/ai-research/12-inference-serving/sglang/references/structured-generation.md +542 -0
- package/skills/ai-research/12-inference-serving/tensorrt-llm/SKILL.md +187 -0
- package/skills/ai-research/12-inference-serving/tensorrt-llm/references/multi-gpu.md +299 -0
- package/skills/ai-research/12-inference-serving/tensorrt-llm/references/optimization.md +243 -0
- package/skills/ai-research/12-inference-serving/tensorrt-llm/references/serving.md +471 -0
- package/skills/ai-research/12-inference-serving/vllm/SKILL.md +364 -0
- package/skills/ai-research/12-inference-serving/vllm/references/optimization.md +227 -0
- package/skills/ai-research/12-inference-serving/vllm/references/quantization.md +285 -0
- package/skills/ai-research/12-inference-serving/vllm/references/server-deployment.md +256 -0
- package/skills/ai-research/12-inference-serving/vllm/references/troubleshooting.md +448 -0
- package/skills/ai-research/13-mlops/mlflow/SKILL.md +704 -0
- package/skills/ai-research/13-mlops/mlflow/references/deployment.md +745 -0
- package/skills/ai-research/13-mlops/mlflow/references/model-registry.md +771 -0
- package/skills/ai-research/13-mlops/mlflow/references/tracking.md +681 -0
- package/skills/ai-research/13-mlops/swanlab/SKILL.md +406 -0
- package/skills/ai-research/13-mlops/swanlab/references/integrations.md +305 -0
- package/skills/ai-research/13-mlops/swanlab/references/visualization.md +234 -0
- package/skills/ai-research/13-mlops/tensorboard/SKILL.md +629 -0
- package/skills/ai-research/13-mlops/tensorboard/references/integrations.md +639 -0
- package/skills/ai-research/13-mlops/tensorboard/references/profiling.md +546 -0
- package/skills/ai-research/13-mlops/tensorboard/references/visualization.md +621 -0
- package/skills/ai-research/13-mlops/weights-and-biases/SKILL.md +590 -0
- package/skills/ai-research/13-mlops/weights-and-biases/references/artifacts.md +585 -0
- package/skills/ai-research/13-mlops/weights-and-biases/references/integrations.md +701 -0
- package/skills/ai-research/13-mlops/weights-and-biases/references/sweeps.md +848 -0
- package/skills/ai-research/14-agents/a-evolve/SKILL.md +383 -0
- package/skills/ai-research/14-agents/a-evolve/references/README.md +831 -0
- package/skills/ai-research/14-agents/a-evolve/references/api.md +594 -0
- package/skills/ai-research/14-agents/a-evolve/references/architecture.md +417 -0
- package/skills/ai-research/14-agents/a-evolve/references/design-patterns.md +462 -0
- package/skills/ai-research/14-agents/a-evolve/references/examples.md +352 -0
- package/skills/ai-research/14-agents/a-evolve/references/issues.md +591 -0
- package/skills/ai-research/14-agents/a-evolve/references/releases.md +112 -0
- package/skills/ai-research/14-agents/a-evolve/references/tutorials.md +819 -0
- package/skills/ai-research/14-agents/autogpt/SKILL.md +403 -0
- package/skills/ai-research/14-agents/autogpt/references/advanced-usage.md +536 -0
- package/skills/ai-research/14-agents/autogpt/references/troubleshooting.md +421 -0
- package/skills/ai-research/14-agents/crewai/SKILL.md +498 -0
- package/skills/ai-research/14-agents/crewai/references/flows.md +439 -0
- package/skills/ai-research/14-agents/crewai/references/tools.md +430 -0
- package/skills/ai-research/14-agents/crewai/references/troubleshooting.md +481 -0
- package/skills/ai-research/14-agents/langchain/SKILL.md +480 -0
- package/skills/ai-research/14-agents/langchain/references/agents.md +500 -0
- package/skills/ai-research/14-agents/langchain/references/integration.md +563 -0
- package/skills/ai-research/14-agents/langchain/references/rag.md +601 -0
- package/skills/ai-research/14-agents/llamaindex/SKILL.md +569 -0
- package/skills/ai-research/14-agents/llamaindex/references/agents.md +84 -0
- package/skills/ai-research/14-agents/llamaindex/references/data_connectors.md +109 -0
- package/skills/ai-research/14-agents/llamaindex/references/query_engines.md +407 -0
- package/skills/ai-research/15-rag/chroma/SKILL.md +406 -0
- package/skills/ai-research/15-rag/chroma/references/integration.md +39 -0
- package/skills/ai-research/15-rag/faiss/SKILL.md +221 -0
- package/skills/ai-research/15-rag/faiss/references/index_types.md +281 -0
- package/skills/ai-research/15-rag/pinecone/SKILL.md +358 -0
- package/skills/ai-research/15-rag/pinecone/references/deployment.md +182 -0
- package/skills/ai-research/15-rag/qdrant/SKILL.md +493 -0
- package/skills/ai-research/15-rag/qdrant/references/advanced-usage.md +649 -0
- package/skills/ai-research/15-rag/qdrant/references/troubleshooting.md +632 -0
- package/skills/ai-research/15-rag/sentence-transformers/SKILL.md +255 -0
- package/skills/ai-research/15-rag/sentence-transformers/references/models.md +124 -0
- package/skills/ai-research/16-prompt-engineering/dspy/SKILL.md +590 -0
- package/skills/ai-research/16-prompt-engineering/dspy/references/examples.md +664 -0
- package/skills/ai-research/16-prompt-engineering/dspy/references/modules.md +476 -0
- package/skills/ai-research/16-prompt-engineering/dspy/references/optimizers.md +567 -0
- package/skills/ai-research/16-prompt-engineering/guidance/SKILL.md +572 -0
- package/skills/ai-research/16-prompt-engineering/guidance/references/backends.md +555 -0
- package/skills/ai-research/16-prompt-engineering/guidance/references/constraints.md +675 -0
- package/skills/ai-research/16-prompt-engineering/guidance/references/examples.md +768 -0
- package/skills/ai-research/16-prompt-engineering/instructor/SKILL.md +740 -0
- package/skills/ai-research/16-prompt-engineering/instructor/references/examples.md +108 -0
- package/skills/ai-research/16-prompt-engineering/instructor/references/providers.md +71 -0
- package/skills/ai-research/16-prompt-engineering/instructor/references/validation.md +607 -0
- package/skills/ai-research/16-prompt-engineering/outlines/SKILL.md +652 -0
- package/skills/ai-research/16-prompt-engineering/outlines/references/backends.md +616 -0
- package/skills/ai-research/16-prompt-engineering/outlines/references/examples.md +774 -0
- package/skills/ai-research/16-prompt-engineering/outlines/references/json_generation.md +653 -0
- package/skills/ai-research/17-observability/langsmith/SKILL.md +422 -0
- package/skills/ai-research/17-observability/langsmith/references/advanced-usage.md +549 -0
- package/skills/ai-research/17-observability/langsmith/references/troubleshooting.md +538 -0
- package/skills/ai-research/17-observability/phoenix/SKILL.md +475 -0
- package/skills/ai-research/17-observability/phoenix/references/advanced-usage.md +620 -0
- package/skills/ai-research/17-observability/phoenix/references/troubleshooting.md +539 -0
- package/skills/ai-research/18-multimodal/audiocraft/SKILL.md +564 -0
- package/skills/ai-research/18-multimodal/audiocraft/references/advanced-usage.md +667 -0
- package/skills/ai-research/18-multimodal/audiocraft/references/troubleshooting.md +505 -0
- package/skills/ai-research/18-multimodal/blip-2/SKILL.md +564 -0
- package/skills/ai-research/18-multimodal/blip-2/references/advanced-usage.md +681 -0
- package/skills/ai-research/18-multimodal/blip-2/references/troubleshooting.md +527 -0
- package/skills/ai-research/18-multimodal/clip/SKILL.md +253 -0
- package/skills/ai-research/18-multimodal/clip/references/applications.md +208 -0
- package/skills/ai-research/18-multimodal/cosmos-policy/SKILL.md +402 -0
- package/skills/ai-research/18-multimodal/cosmos-policy/references/libero-commands.md +175 -0
- package/skills/ai-research/18-multimodal/cosmos-policy/references/robocasa-commands.md +147 -0
- package/skills/ai-research/18-multimodal/llava/SKILL.md +304 -0
- package/skills/ai-research/18-multimodal/llava/references/training.md +198 -0
- package/skills/ai-research/18-multimodal/openpi/SKILL.md +480 -0
- package/skills/ai-research/18-multimodal/openpi/references/checkpoints-and-env-map.md +86 -0
- package/skills/ai-research/18-multimodal/openpi/references/config-recipes.md +50 -0
- package/skills/ai-research/18-multimodal/openpi/references/pytorch-gotchas.md +49 -0
- package/skills/ai-research/18-multimodal/openpi/references/remote-client-pattern.md +48 -0
- package/skills/ai-research/18-multimodal/openpi/references/training-debugging.md +46 -0
- package/skills/ai-research/18-multimodal/openvla-oft/SKILL.md +441 -0
- package/skills/ai-research/18-multimodal/openvla-oft/references/aloha-workflow.md +141 -0
- package/skills/ai-research/18-multimodal/openvla-oft/references/config-troubleshooting.md +97 -0
- package/skills/ai-research/18-multimodal/openvla-oft/references/libero-workflow.md +115 -0
- package/skills/ai-research/18-multimodal/openvla-oft/references/paper-and-checkpoints.md +84 -0
- package/skills/ai-research/18-multimodal/segment-anything/SKILL.md +500 -0
- package/skills/ai-research/18-multimodal/segment-anything/references/advanced-usage.md +590 -0
- package/skills/ai-research/18-multimodal/segment-anything/references/troubleshooting.md +485 -0
- package/skills/ai-research/18-multimodal/stable-diffusion/SKILL.md +519 -0
- package/skills/ai-research/18-multimodal/stable-diffusion/references/advanced-usage.md +717 -0
- package/skills/ai-research/18-multimodal/stable-diffusion/references/troubleshooting.md +556 -0
- package/skills/ai-research/18-multimodal/whisper/SKILL.md +317 -0
- package/skills/ai-research/18-multimodal/whisper/references/languages.md +190 -0
- package/skills/ai-research/19-emerging-techniques/knowledge-distillation/SKILL.md +458 -0
- package/skills/ai-research/19-emerging-techniques/knowledge-distillation/references/minillm.md +335 -0
- package/skills/ai-research/19-emerging-techniques/long-context/SKILL.md +536 -0
- package/skills/ai-research/19-emerging-techniques/long-context/references/extension_methods.md +469 -0
- package/skills/ai-research/19-emerging-techniques/long-context/references/fine_tuning.md +612 -0
- package/skills/ai-research/19-emerging-techniques/long-context/references/rope.md +403 -0
- package/skills/ai-research/19-emerging-techniques/model-merging/SKILL.md +497 -0
- package/skills/ai-research/19-emerging-techniques/model-merging/references/coefficient-tuning.md +415 -0
- package/skills/ai-research/19-emerging-techniques/model-merging/references/evaluation.md +463 -0
- package/skills/ai-research/19-emerging-techniques/model-merging/references/examples.md +429 -0
- package/skills/ai-research/19-emerging-techniques/model-merging/references/methods.md +353 -0
- package/skills/ai-research/19-emerging-techniques/model-pruning/SKILL.md +495 -0
- package/skills/ai-research/19-emerging-techniques/model-pruning/references/wanda.md +348 -0
- package/skills/ai-research/19-emerging-techniques/moe-training/SKILL.md +526 -0
- package/skills/ai-research/19-emerging-techniques/moe-training/references/architectures.md +433 -0
- package/skills/ai-research/19-emerging-techniques/moe-training/references/inference.md +349 -0
- package/skills/ai-research/19-emerging-techniques/moe-training/references/training.md +426 -0
- package/skills/ai-research/19-emerging-techniques/speculative-decoding/SKILL.md +467 -0
- package/skills/ai-research/19-emerging-techniques/speculative-decoding/references/lookahead.md +310 -0
- package/skills/ai-research/19-emerging-techniques/speculative-decoding/references/medusa.md +351 -0
- package/skills/ai-research/20-ml-paper-writing/academic-plotting/SKILL.md +479 -0
- package/skills/ai-research/20-ml-paper-writing/academic-plotting/references/data-visualization.md +509 -0
- package/skills/ai-research/20-ml-paper-writing/academic-plotting/references/diagram-generation.md +395 -0
- package/skills/ai-research/20-ml-paper-writing/academic-plotting/references/style-guide.md +305 -0
- package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/SKILL.md +982 -0
- package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/checklists.md +348 -0
- package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/citation-workflow.md +563 -0
- package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/reviewer-guidelines.md +349 -0
- package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/sources.md +165 -0
- package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/writing-guide.md +477 -0
- package/skills/ai-research/20-ml-paper-writing/presenting-conference-talks/SKILL.md +298 -0
- package/skills/ai-research/20-ml-paper-writing/presenting-conference-talks/references/slide-templates.md +505 -0
- package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/SKILL.md +270 -0
- package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/checklist.md +279 -0
- package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/reviewer-guidelines.md +116 -0
- package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/section-blueprints.md +400 -0
- package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/systems-conferences.md +261 -0
- package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/writing-patterns.md +231 -0
- package/skills/ai-research/21-research-ideation/brainstorming-research-ideas/SKILL.md +384 -0
- package/skills/ai-research/21-research-ideation/creative-thinking-for-research/SKILL.md +366 -0
- package/skills/ai-research/22-agent-native-research-artifact/compiler/SKILL.md +245 -0
- package/skills/ai-research/22-agent-native-research-artifact/compiler/references/ara-schema.md +439 -0
- package/skills/ai-research/22-agent-native-research-artifact/compiler/references/exploration-tree-spec.md +125 -0
- package/skills/ai-research/22-agent-native-research-artifact/compiler/references/validation-checklist.md +149 -0
- package/skills/ai-research/22-agent-native-research-artifact/research-manager/SKILL.md +324 -0
- package/skills/ai-research/22-agent-native-research-artifact/research-manager/references/event-taxonomy.md +124 -0
- package/skills/ai-research/22-agent-native-research-artifact/research-manager/references/provenance-tags.md +190 -0
- package/skills/ai-research/22-agent-native-research-artifact/research-manager/references/session-protocol.md +162 -0
- package/skills/ai-research/22-agent-native-research-artifact/rigor-reviewer/SKILL.md +322 -0
- package/skills/ai-research/22-agent-native-research-artifact/rigor-reviewer/references/review-dimensions.md +182 -0
- package/skills/ai-research/SKILL.md +101 -0
- package/skills/ai-research/SOURCE +38 -0
- package/skills/ai-research/index/1-frame.md +18 -0
- package/skills/ai-research/index/2-data.md +21 -0
- package/skills/ai-research/index/3-train.md +48 -0
- package/skills/ai-research/index/4-measure.md +25 -0
- package/skills/ai-research/index/5-run.md +23 -0
- package/skills/ai-research/index/6-write.md +35 -0
- package/skills/ai-research/library.json +3456 -0
- package/skills/analyze-app/EVALS.md +82 -0
- package/skills/analyze-app/SKILL.md +188 -0
- package/skills/design-contract/EVALS.md +80 -0
- package/skills/design-contract/SKILL.md +171 -0
- package/skills/design-library/EVALS.md +85 -0
- package/skills/design-library/INDEX.md +59 -0
- package/skills/design-library/SKILL.md +58 -0
- package/skills/design-library/SOURCE +131 -0
- package/skills/design-library/adaptive-interfaces/skills/colour-independence/SKILL.md +90 -0
- package/skills/design-library/adaptive-interfaces/skills/flexible-typography/SKILL.md +83 -0
- package/skills/design-library/adaptive-interfaces/skills/information-density/SKILL.md +87 -0
- package/skills/design-library/adaptive-interfaces/skills/preference-audit/SKILL.md +70 -0
- package/skills/design-library/adaptive-interfaces/skills/responsive-accessibility/SKILL.md +86 -0
- package/skills/design-library/adaptive-interfaces/skills/responsive-review/SKILL.md +76 -0
- package/skills/design-library/adaptive-interfaces/skills/simplified-views/SKILL.md +97 -0
- package/skills/design-library/adaptive-interfaces/skills/specify/SKILL.md +63 -0
- package/skills/design-library/adaptive-interfaces/skills/user-preference-respect/SKILL.md +100 -0
- package/skills/design-library/cognitive-accessibility/skills/adaptive-personalisation/SKILL.md +61 -0
- package/skills/design-library/cognitive-accessibility/skills/assess-load/SKILL.md +48 -0
- package/skills/design-library/cognitive-accessibility/skills/cognitive-load-assessment/SKILL.md +60 -0
- package/skills/design-library/cognitive-accessibility/skills/contextual-help-design/SKILL.md +61 -0
- package/skills/design-library/cognitive-accessibility/skills/error-prevention-recovery/SKILL.md +71 -0
- package/skills/design-library/cognitive-accessibility/skills/focus-attention-design/SKILL.md +67 -0
- package/skills/design-library/cognitive-accessibility/skills/memory-load-reduction/SKILL.md +60 -0
- package/skills/design-library/cognitive-accessibility/skills/plain-language-design/SKILL.md +78 -0
- package/skills/design-library/cognitive-accessibility/skills/review/SKILL.md +56 -0
- package/skills/design-library/cognitive-accessibility/skills/simplify/SKILL.md +39 -0
- package/skills/design-library/cognitive-accessibility/skills/wayfinding-navigation/SKILL.md +64 -0
- package/skills/design-library/design-research/skills/behavioural-analytics/SKILL.md +33 -0
- package/skills/design-library/design-research/skills/qual-quant-triangulation/SKILL.md +33 -0
- package/skills/design-library/inclusive-interaction/skills/audit/SKILL.md +50 -0
- package/skills/design-library/inclusive-interaction/skills/design-flow/SKILL.md +58 -0
- package/skills/design-library/inclusive-interaction/skills/feedback-and-status/SKILL.md +76 -0
- package/skills/design-library/inclusive-interaction/skills/gesture-alternatives/SKILL.md +70 -0
- package/skills/design-library/inclusive-interaction/skills/keyboard-navigation/SKILL.md +99 -0
- package/skills/design-library/inclusive-interaction/skills/keyboard-review/SKILL.md +54 -0
- package/skills/design-library/inclusive-interaction/skills/motion-sensitivity/SKILL.md +79 -0
- package/skills/design-library/inclusive-interaction/skills/multi-modal-input/SKILL.md +70 -0
- package/skills/design-library/inclusive-interaction/skills/touch-target-design/SKILL.md +71 -0
- package/skills/design-library/inclusive-interaction/skills/voice-interaction/SKILL.md +68 -0
- package/skills/design-library/visual-critique/skills/critique-affordance/SKILL.md +45 -0
- package/skills/design-library/visual-critique/skills/critique-brand-consistency/SKILL.md +42 -0
- package/skills/design-library/visual-critique/skills/critique-color/SKILL.md +44 -0
- package/skills/design-library/visual-critique/skills/critique-composition/SKILL.md +46 -0
- package/skills/design-library/visual-critique/skills/critique-information-density/SKILL.md +45 -0
- package/skills/design-library/visual-critique/skills/critique-typography/SKILL.md +45 -0
- package/skills/design-library/visual-critique/skills/critique-visual-hierarchy/SKILL.md +40 -0
- package/skills/feature-audit/EVALS.md +83 -0
- package/skills/feature-audit/SKILL.md +326 -0
- package/skills/harness/EVALS.md +81 -0
- package/skills/harness/SKILL.md +88 -0
- package/skills/i-have-adhd/EVALS.md +80 -0
- package/skills/i-have-adhd/SKILL.md +183 -0
- package/skills/no-ai-slop/EVALS.md +89 -0
- package/skills/no-ai-slop/SKILL.md +209 -0
- package/skills/no-ai-slop/eval.md +52 -0
- package/skills/plan-add/EVALS.md +79 -0
- package/skills/plan-add/SKILL.md +179 -0
- package/skills/plan-add/render_table.py +72 -0
- package/skills/plan-status/EVALS.md +78 -0
- package/skills/plan-status/SKILL.md +52 -0
- package/skills/plan-sync/EVALS.md +80 -0
- package/skills/plan-sync/SKILL.md +69 -0
- package/skills/pm-frameworks/SKILL.md +33 -0
- package/skills/pm-frameworks/SOURCE +39 -0
- package/skills/pm-frameworks/intended-vs-implemented/SKILL.md +42 -0
- package/skills/pm-frameworks/opportunity-solution-tree/SKILL.md +64 -0
- package/skills/ponytail/EVALS.md +80 -0
- package/skills/ponytail/SKILL.md +124 -0
- package/skills/product-analysis/EVALS.md +103 -0
- package/skills/product-analysis/SKILL.md +361 -0
- package/skills/research/EVALS.md +104 -0
- package/skills/research/SKILL.md +570 -0
- package/skills/rl-env/SKILL.md +53 -0
- package/skills/rl-env/SOURCE +41 -0
- package/skills/rl-env/generate-nemo-gym-env/SKILL.md +169 -0
- package/skills/rl-env/generate-nemo-gym-env/references/architecture.md +114 -0
- package/skills/rl-env/generate-openenv-env/SKILL.md +183 -0
- package/skills/rl-env/generate-openenv-env/references/architecture.md +82 -0
- package/skills/rl-env/generate-ors-env/SKILL.md +209 -0
- package/skills/rl-env/generate-ors-env/references/architecture.md +113 -0
- package/skills/rl-env/generate-verifiers-env/SKILL.md +188 -0
- package/skills/rl-env/generate-verifiers-env/references/architecture.md +119 -0
- package/skills/rl-env/rl-env-from-description/SKILL.md +124 -0
- package/skills/rl-env/rl-env-from-description/references/interview.md +75 -0
- package/skills/rl-env/rl-env-from-description/references/nemo_gym.md +41 -0
- package/skills/rl-env/rl-env-from-description/references/openenv.md +35 -0
- package/skills/rl-env/rl-env-from-description/references/ors.md +50 -0
- package/skills/rl-env/rl-env-from-description/references/verifiers.md +39 -0
- package/skills/tezgah-contract/EVALS.md +78 -0
- package/skills/tezgah-contract/SKILL.md +792 -0
- package/statusline.py +129 -0
- package/workflows/graph-impact.js +153 -0
- package/workflows/graph-map.js +158 -0
- package/workflows/graph-review.js +170 -0
|
@@ -0,0 +1,855 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""The phase x tier x family model table, and the tier judgement the router asks for.
|
|
3
|
+
|
|
4
|
+
Which model runs which delegated task. The main thread keeps one model for the
|
|
5
|
+
whole session - a model switch re-reads the whole cached prefix at write price,
|
|
6
|
+
and the prompt cache is per model - so routing happens where it is free: at the
|
|
7
|
+
subagent a task is handed to. Every generated agent has a slot, every slot a model
|
|
8
|
+
per family, and each host gets the family it can run:
|
|
9
|
+
|
|
10
|
+
Claude Code / Cursor anthropic frontmatter `model:` + `effort:`
|
|
11
|
+
Codex openai `model` + `model_reasoning_effort`
|
|
12
|
+
opencode any a selector `refresh` found in `opencode models`
|
|
13
|
+
omp anthropic when the session default is an Anthropic model,
|
|
14
|
+
any otherwise (or `tezgah-route --mode`); written to omp's
|
|
15
|
+
`task.agentModelOverrides` as a per-agent fallback chain
|
|
16
|
+
(the mode's family, then every other family this machine
|
|
17
|
+
holds a credential for), and to its `modelRoles.plan` and
|
|
18
|
+
`.slow`, on the frontier row, with their fallbacks in
|
|
19
|
+
`retry.fallbackChains`
|
|
20
|
+
|
|
21
|
+
Two accessors are the table's public face, so a caller that needs a cheap or a
|
|
22
|
+
strong model names none of its own: `frontier_model(family)` and
|
|
23
|
+
`cheap_model(family)` return that row's `(model, effort)`, or None when the
|
|
24
|
+
family has no such row.
|
|
25
|
+
|
|
26
|
+
The table is a dated snapshot: prices and ids are re-read from OpenRouter's public
|
|
27
|
+
model list by `tezgah-route --refresh` into CONFIG_DIR/models.json, which also
|
|
28
|
+
flags an id that left the list or a price that moved; scores are not re-read (they
|
|
29
|
+
need a key) and the snapshot says how old they are. Why these models, with the
|
|
30
|
+
measurements behind them: docs/models.md.
|
|
31
|
+
|
|
32
|
+
The tier judgement is deterministic first and a model second: a brief naming
|
|
33
|
+
stored data, a migration, credentials, the gate or security goes to frontier by
|
|
34
|
+
rule, because that is the one class the measured judge under-routed; otherwise
|
|
35
|
+
Jev answers one Choice over the tiers; with no key the caller's phase picks the
|
|
36
|
+
tier from the static table, and with no phase the middle tier is used.
|
|
37
|
+
|
|
38
|
+
Stdlib only; every network or subprocess failure is a fallback, never a raise.
|
|
39
|
+
"""
|
|
40
|
+
import datetime
|
|
41
|
+
import json
|
|
42
|
+
import os
|
|
43
|
+
import re
|
|
44
|
+
import shutil
|
|
45
|
+
import sqlite3
|
|
46
|
+
import subprocess
|
|
47
|
+
import urllib.request
|
|
48
|
+
|
|
49
|
+
import tezgah_integrity as ti
|
|
50
|
+
import tezgah_judge as tj
|
|
51
|
+
import tezgah_paths as tp
|
|
52
|
+
|
|
53
|
+
READ_ON = "2026-09-30"
|
|
54
|
+
STALE_DAYS = 60
|
|
55
|
+
OVERLAY = os.path.join(tp.CONFIG_DIR, "models.json")
|
|
56
|
+
OPENROUTER_MODELS = "https://openrouter.ai/api/v1/models"
|
|
57
|
+
MODES = ("auto", "anthropic", "zai", "any", "off")
|
|
58
|
+
# The two status markers `bin/tezgah-setup` classifies an `apply_omp()` line by:
|
|
59
|
+
# a skip is not a write and not a failure - the user's omp is left untouched, and
|
|
60
|
+
# nothing is left to repair, which is why the status report excuses it rather
|
|
61
|
+
# than showing it as a missing row.
|
|
62
|
+
SKIP_MARK = "skipped:"
|
|
63
|
+
FAIL_MARK = "NOT written"
|
|
64
|
+
# omp's own agent dir: the same one `omp_config` in bin/tezgah-setup pins with
|
|
65
|
+
# PI_CODING_AGENT_DIR, so a write lands beside the hook the installer registered.
|
|
66
|
+
OMP_AGENT = os.path.join(tp.HOME, ".omp", "agent")
|
|
67
|
+
# The agents omp bundles (omp://task-agent-discovery.md:129-130). They resolve
|
|
68
|
+
# through `task.agentModelOverrides` before their own model
|
|
69
|
+
# (omp://task-agent-discovery.md:217), which is the only way to route them, so
|
|
70
|
+
# `scout`/`sonic`/`task` ride the slots this table writes. omp's own `reviewer`
|
|
71
|
+
# and `security-reviewer` are not tezgah's to route: the generated
|
|
72
|
+
# `tezgah-reviewer` is the one that carries the frontier row.
|
|
73
|
+
BUNDLED = {"scout": "explore", "sonic": "cheap", "task": "standard"}
|
|
74
|
+
TIERS = ("cheap", "standard", "frontier")
|
|
75
|
+
|
|
76
|
+
# slot -> family -> (model, effort). Anthropic and OpenAI names are the hosts'
|
|
77
|
+
# own ids; `any` names are OpenRouter ids.
|
|
78
|
+
# The `zai` column names the provider the way omp's own config does
|
|
79
|
+
# (`zai/glm-5.3-flash:auto` in this machine's `modelRoles.memory`), so a machine
|
|
80
|
+
# whose funded provider is z.ai routes without a hand-edit. Both ids were probed
|
|
81
|
+
# on 2026-10-01 (`omp -p --model zai/glm-5.3-flash "..."` -> `ok`), and the split
|
|
82
|
+
# follows the snapshot: GLM-5.3 Flash 92.0 SWE-bench Verified at $0.018/test
|
|
83
|
+
# against GLM-5.3's 95.4 at $0.34 (vals.ai, artifacts/model-table.json), so the
|
|
84
|
+
# cheap slots take the flash id and standard the plain one.
|
|
85
|
+
SLOTS = {
|
|
86
|
+
"cheap": {"anthropic": ("claude-opus-5-5", "low"),
|
|
87
|
+
"openai": ("gpt-6.1-sol", "low"),
|
|
88
|
+
"zai": ("zai/glm-5.3-flash", None),
|
|
89
|
+
"any": ("z-ai/glm-5.3-flash", None)},
|
|
90
|
+
"explore": {"anthropic": ("claude-opus-5-5", "medium"),
|
|
91
|
+
"openai": ("gpt-6.1-sol", "low"),
|
|
92
|
+
"zai": ("zai/glm-5.3-flash", None),
|
|
93
|
+
"any": ("deepseek/deepseek-v4.1-flash", None)},
|
|
94
|
+
"standard": {"anthropic": ("claude-opus-5-5", "medium"),
|
|
95
|
+
"openai": ("gpt-6.1-sol", "high"),
|
|
96
|
+
"zai": ("zai/glm-5.3", None),
|
|
97
|
+
"any": ("openai/gpt-6.1-sol", "high")},
|
|
98
|
+
# The frontier row names a concrete model on every family: the strongest
|
|
99
|
+
# Anthropic run the snapshot prices (Opus 5.5 @high, 56.6 Terminal-Bench 4.0
|
|
100
|
+
# at $1.82/task on AA v4.3), OpenAI's own frontier id, and the same Opus 5.5
|
|
101
|
+
# through OpenRouter at $4/$20 per 1M (docs/models.md, read 2026-09-30).
|
|
102
|
+
"frontier": {"anthropic": ("claude-opus-5-5", "high"),
|
|
103
|
+
"openai": ("gpt-6-astra", "high"),
|
|
104
|
+
"zai": ("zai/glm-5.3", None),
|
|
105
|
+
"any": ("anthropic/claude-opus-5.5", "high")},
|
|
106
|
+
}
|
|
107
|
+
AGENT_SLOT = {"tezgah-cheap": "cheap", "tezgah-standard": "standard",
|
|
108
|
+
"tezgah-frontier": "frontier", "tezgah-reviewer": "frontier"}
|
|
109
|
+
# The OpenRouter id of every model the table names, with its list price per 1M
|
|
110
|
+
# tokens (input, output) on READ_ON, so `refresh` can say what moved.
|
|
111
|
+
SNAPSHOT = {"anthropic/claude-opus-5.5": (4.0, 20.0),
|
|
112
|
+
"openai/gpt-6.1-sol": (2.0, 10.0),
|
|
113
|
+
"openai/gpt-6-astra": (10.0, 50.0),
|
|
114
|
+
"z-ai/glm-5.3-flash": (0.15, 0.5),
|
|
115
|
+
"deepseek/deepseek-v4.1-flash": (0.0198, 0.396)}
|
|
116
|
+
|
|
117
|
+
# ---------------------------------------------------------------- overlay ----
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
# The overlay's known fields and the type each has to be: a field of another
|
|
121
|
+
# type reads as absent, so a hand-edited or half-written file cannot make a
|
|
122
|
+
# caller raise (agent generation reads `opencode` on every session start) or
|
|
123
|
+
# make `--check` print one flag per character.
|
|
124
|
+
OVERLAY_TYPES = {"mode": str, "read_on": str, "prices": dict, "opencode": dict,
|
|
125
|
+
"omp_written": dict, "flags": list}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def overlay():
|
|
129
|
+
try:
|
|
130
|
+
with open(OVERLAY, encoding="utf-8") as fh:
|
|
131
|
+
data = json.load(fh)
|
|
132
|
+
except (OSError, ValueError):
|
|
133
|
+
return {}
|
|
134
|
+
if not isinstance(data, dict):
|
|
135
|
+
return {}
|
|
136
|
+
return {k: v for k, v in data.items()
|
|
137
|
+
if k not in OVERLAY_TYPES or isinstance(v, OVERLAY_TYPES[k])}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def save_overlay(data):
|
|
141
|
+
try:
|
|
142
|
+
os.makedirs(tp.CONFIG_DIR, exist_ok=True)
|
|
143
|
+
tmp = OVERLAY + ".tmp"
|
|
144
|
+
with open(tmp, "w", encoding="utf-8") as fh:
|
|
145
|
+
json.dump(data, fh, indent=2, sort_keys=True)
|
|
146
|
+
fh.write("\n")
|
|
147
|
+
os.replace(tmp, OVERLAY)
|
|
148
|
+
return True
|
|
149
|
+
except OSError:
|
|
150
|
+
return False
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
# ------------------------------------------------------------ host models ----
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def pick(agent, family):
|
|
157
|
+
"""(model, effort) for a generated agent on a family, or None: no slot."""
|
|
158
|
+
slot = AGENT_SLOT.get(agent)
|
|
159
|
+
return SLOTS[slot][family] if slot else None
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def frontier_model(family):
|
|
163
|
+
"""(model, effort) the frontier row names on `family`, or None: no such row.
|
|
164
|
+
|
|
165
|
+
What the design surface and omp's plan role run on, so neither has to name a
|
|
166
|
+
model of its own (docs/models.md)."""
|
|
167
|
+
return SLOTS["frontier"].get(family)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def cheap_model(family):
|
|
171
|
+
"""(model, effort) the cheap row names on `family`, or None: no such row.
|
|
172
|
+
|
|
173
|
+
The one place the cheap tier is named: `bin/codegen`'s default and the
|
|
174
|
+
judge's fallback read this, so a refresh moves every cheap path."""
|
|
175
|
+
return SLOTS["cheap"].get(family)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def opencode_model(agent):
|
|
179
|
+
"""The selector `refresh` resolved for this agent's slot, or None (inherit)."""
|
|
180
|
+
slot = AGENT_SLOT.get(agent)
|
|
181
|
+
found = overlay().get("opencode") or {}
|
|
182
|
+
return found.get(slot) if slot else None
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def openrouter_ready():
|
|
186
|
+
"""Whether an OpenRouter credential resolves, the channels `consult` and the
|
|
187
|
+
judge's fallback use (`tp.PROVIDER_KEYS`)."""
|
|
188
|
+
env, home = tp.PROVIDER_KEYS["openrouter"]
|
|
189
|
+
if os.environ.get(env, "").strip():
|
|
190
|
+
return True
|
|
191
|
+
try:
|
|
192
|
+
with open(os.path.join(tp.HOME, home), encoding="utf-8") as fh:
|
|
193
|
+
return bool(fh.read().strip())
|
|
194
|
+
except OSError:
|
|
195
|
+
return False
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
# The families omp can run from this table, in fallback order once the mode's own
|
|
199
|
+
# family has gone first. `openai` is absent on purpose: omp's `openai-codex`
|
|
200
|
+
# provider lists none of the column's ids on this machine (`omp models
|
|
201
|
+
# openai-codex`, 2026-10-01: gpt-5.5, gpt-5.6-luna/-terra, gpt-6-luna), so a
|
|
202
|
+
# pattern for it would never resolve.
|
|
203
|
+
OMP_FAMILIES = ("anthropic", "zai", "any")
|
|
204
|
+
# family -> (omp's auth-store provider id, the env names omp reads for it)
|
|
205
|
+
# (omp://providers.md:39, omp://environment-variables.md:39-40,71,73).
|
|
206
|
+
OMP_AUTH = {"anthropic": ("anthropic", ("ANTHROPIC_OAUTH_TOKEN", "ANTHROPIC_API_KEY")),
|
|
207
|
+
"zai": ("zai", ("ZAI_API_KEY",)),
|
|
208
|
+
"any": ("openrouter", ("OPENROUTER_API_KEY",))}
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def _omp_stored_providers():
|
|
212
|
+
"""The provider ids omp's local auth store holds an enabled credential for.
|
|
213
|
+
|
|
214
|
+
Only the provider column is read, never a secret. An auth broker, a store
|
|
215
|
+
that cannot be opened or a schema that moved all read as empty: what this
|
|
216
|
+
cannot see it does not claim."""
|
|
217
|
+
path = os.path.join(OMP_AGENT, "agent.db")
|
|
218
|
+
if not os.path.exists(path):
|
|
219
|
+
return set()
|
|
220
|
+
try:
|
|
221
|
+
con = sqlite3.connect("file:%s?mode=ro" % path, uri=True, timeout=1)
|
|
222
|
+
try:
|
|
223
|
+
rows = con.execute("SELECT provider FROM auth_credentials "
|
|
224
|
+
"WHERE disabled_cause IS NULL").fetchall()
|
|
225
|
+
finally:
|
|
226
|
+
con.close()
|
|
227
|
+
except sqlite3.Error:
|
|
228
|
+
return set()
|
|
229
|
+
return {row[0] for row in rows}
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def funded_families():
|
|
233
|
+
"""The `OMP_FAMILIES` with a credential this machine shows: an omp auth-store
|
|
234
|
+
entry, an env key omp reads, or (for `any`) `openrouter_ready`.
|
|
235
|
+
|
|
236
|
+
A credential is not a balance - a funded-looking key can still answer 402 -
|
|
237
|
+
which is why each agent gets a chain rather than one more pin. A family whose
|
|
238
|
+
credential cannot be detected is left out, never guessed in."""
|
|
239
|
+
stored = _omp_stored_providers()
|
|
240
|
+
return [family for family in OMP_FAMILIES
|
|
241
|
+
if OMP_AUTH[family][0] in stored
|
|
242
|
+
or any(os.environ.get(env, "").strip() for env in OMP_AUTH[family][1])
|
|
243
|
+
or (family == "any" and openrouter_ready())]
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def omp_mode(default_selector=None):
|
|
247
|
+
"""`anthropic`, `zai` or `any`: the saved mode, else the default's own family.
|
|
248
|
+
|
|
249
|
+
A non-Anthropic default reads as `any`, never as a silent fall back to the
|
|
250
|
+
Anthropic column - the caller decides what to do when the OpenRouter
|
|
251
|
+
credential the `any` selectors need is missing (`apply_omp` writes nothing
|
|
252
|
+
and says so)."""
|
|
253
|
+
mode = overlay().get("mode")
|
|
254
|
+
if mode in ("anthropic", "zai", "any", "off"):
|
|
255
|
+
return mode
|
|
256
|
+
for family in ("anthropic", "zai"):
|
|
257
|
+
if str(default_selector or "").startswith(family + "/"):
|
|
258
|
+
return family
|
|
259
|
+
return "any"
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
# The omp roles this table writes, as flat `modelRoles.<role>` keys: `plan` is
|
|
263
|
+
# the model plan mode designs on - the one surface where a session spends its own
|
|
264
|
+
# tokens on design - and `slow` is omp's hard-question role (omp://models.md:483,
|
|
265
|
+
# omp://settings.md:116-118). Both carry the frontier row.
|
|
266
|
+
OMP_ROLES = ("plan", "slow")
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
# The prefix each family's stored id needs to become an omp selector. `zai` needs
|
|
270
|
+
# none: its id already is `<provider>/<model>`, the shape omp's own config uses.
|
|
271
|
+
FAMILY_PREFIX = {"anthropic": "anthropic/", "zai": "", "any": "openrouter/"}
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def _selector(family, slot):
|
|
275
|
+
"""`<provider>/<model>[:<effort>]` for one slot on one family, the shape omp
|
|
276
|
+
takes for a model override and for a role alike (omp://models.md:492-505):
|
|
277
|
+
the Anthropic column names the host's own id, `zai` a z.ai id, `any` an
|
|
278
|
+
OpenRouter one."""
|
|
279
|
+
model, effort = SLOTS[slot][family]
|
|
280
|
+
return FAMILY_PREFIX[family] + model + (":" + effort if effort else "")
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def _chain(mode, slot, funded, agent=""):
|
|
284
|
+
"""[selector, ...] for one slot: the mode's family first - the user picked it,
|
|
285
|
+
so it leads even when its credential is not visible from here - then every
|
|
286
|
+
other funded family, each on that slot's own row.
|
|
287
|
+
|
|
288
|
+
The fallbacks are rotated by the agent's own name (`agent`): identical chains
|
|
289
|
+
for every agent meant one family's 429 moved all of them onto the same next
|
|
290
|
+
family in the same moment, which is the cascade the chain exists to break
|
|
291
|
+
(independent review, 2026-10-01). The rotation is deterministic - the same
|
|
292
|
+
agent resolves the same order on every machine - so nothing here is random."""
|
|
293
|
+
families = [mode] + [f for f in OMP_FAMILIES if f != mode and f in funded]
|
|
294
|
+
tail = families[1:]
|
|
295
|
+
if agent and len(tail) > 1:
|
|
296
|
+
shift = sum(ord(c) for c in agent) % len(tail)
|
|
297
|
+
families = families[:1] + tail[shift:] + tail[:shift]
|
|
298
|
+
return [_selector(family, slot) for family in families]
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def _runnable(mode):
|
|
302
|
+
return mode in OMP_FAMILIES and not (mode == "any" and not openrouter_ready())
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def omp_overrides(mode):
|
|
306
|
+
"""{agent: omp selector chain} for `task.agentModelOverrides`, tezgah roles
|
|
307
|
+
and the bundled agents alike, or {} when the mode cannot run on this machine.
|
|
308
|
+
|
|
309
|
+
Each value is a comma-separated chain, which omp splits into one pattern per
|
|
310
|
+
entry and turns into a per-spawn fallback chain - the first resolvable
|
|
311
|
+
pattern is primary, the rest its fallbacks (omp://settings.md:544,
|
|
312
|
+
omp://task-agent-discovery.md:42). One pin per agent made one provider's 429
|
|
313
|
+
every subagent's failure, the account being the one the main thread spends
|
|
314
|
+
(measured 2026-10-01: 24 of 26 post-routing 429s at a subagent's first
|
|
315
|
+
request, all on one Opus account). With one funded family the chain is that
|
|
316
|
+
family's selector alone.
|
|
317
|
+
|
|
318
|
+
Every slot is written, frontier included: a frontier agent the record left
|
|
319
|
+
out would run on whatever model the session started with, and in the `any`
|
|
320
|
+
mode that is measured as a flash model, so security-sensitive work would run
|
|
321
|
+
below the row. Only `tezgah-orchestrator` stays outside the record - it is
|
|
322
|
+
the main thread's own agent."""
|
|
323
|
+
if not _runnable(mode):
|
|
324
|
+
return {} # `off` asks for nothing; `any` without a key cannot run here
|
|
325
|
+
funded = funded_families()
|
|
326
|
+
return {agent: ",".join(_chain(mode, slot, funded, agent))
|
|
327
|
+
for agent, slot in dict(AGENT_SLOT, **BUNDLED).items()}
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def omp_role_overrides(mode):
|
|
331
|
+
"""{"modelRoles.<role>": selector} for `OMP_ROLES`, or {} when the mode
|
|
332
|
+
cannot run here.
|
|
333
|
+
|
|
334
|
+
Plan mode is the one surface where a session designs on its own tokens, so
|
|
335
|
+
it is pinned to the frontier row of the mode's family rather than left on
|
|
336
|
+
whatever model the session happened to start with; `slow` follows it. A role
|
|
337
|
+
holds one selector (omp://models.md, "Role aliases and settings"): its
|
|
338
|
+
fallbacks are `omp_role_chains`. The same OpenRouter gate as `omp_overrides`
|
|
339
|
+
applies, and `off` resolves to {} - it writes nothing."""
|
|
340
|
+
if not _runnable(mode):
|
|
341
|
+
return {}
|
|
342
|
+
return {"modelRoles." + role: _selector(mode, "frontier")
|
|
343
|
+
for role in OMP_ROLES}
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def omp_role_chains(mode):
|
|
347
|
+
"""{"retry.fallbackChains.<role>": [selector, ...]} for `OMP_ROLES`: the
|
|
348
|
+
frontier row of every other funded family, which omp tries after the role's
|
|
349
|
+
own model fails (omp://settings.md:544). Empty with one funded family, and
|
|
350
|
+
for a mode that cannot run. Only these two role keys are tezgah's: the
|
|
351
|
+
`default` chain and the provider-keyed ones stay the user's."""
|
|
352
|
+
if not _runnable(mode):
|
|
353
|
+
return {}
|
|
354
|
+
rest = _chain(mode, "frontier", funded_families())[1:]
|
|
355
|
+
return {"retry.fallbackChains." + role: rest
|
|
356
|
+
for role in OMP_ROLES} if rest else {}
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def _omp(*args):
|
|
360
|
+
"""Run `omp config <args>` the way the installer does.
|
|
361
|
+
|
|
362
|
+
`tp.omp_bin()` is the installer's own lookup (TEZGAH_OMP_BIN, then PATH,
|
|
363
|
+
then a per-user bin dir) and PI_CODING_AGENT_DIR pins the CLI to the agent
|
|
364
|
+
dir tezgah writes into, so the value is read and written in one profile.
|
|
365
|
+
|
|
366
|
+
`cwd` is HOME on purpose: `config get` answers the EFFECTIVE value, with the
|
|
367
|
+
project layer of the working directory merged in, while `config set` writes
|
|
368
|
+
the global file - so from a repository that carries a `.omp/config.yml`, a
|
|
369
|
+
project entry would be copied machine-wide and the mode would be chosen from
|
|
370
|
+
a project default (omp://settings.md:64-65)."""
|
|
371
|
+
exe = tp.omp_bin()
|
|
372
|
+
if not exe:
|
|
373
|
+
return None
|
|
374
|
+
env = dict(os.environ, PI_CODING_AGENT_DIR=OMP_AGENT)
|
|
375
|
+
try:
|
|
376
|
+
proc = subprocess.run([exe, "config"] + list(args), capture_output=True,
|
|
377
|
+
text=True, timeout=30, env=env, cwd=tp.HOME)
|
|
378
|
+
except (OSError, subprocess.SubprocessError):
|
|
379
|
+
return None
|
|
380
|
+
return proc if proc.returncode == 0 else None
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def _omp_set(key, value):
|
|
384
|
+
return (_omp("set", key, json.dumps(value)) if value
|
|
385
|
+
else _omp("reset", key))
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def omp_get(key):
|
|
389
|
+
proc = _omp("get", key, "--json")
|
|
390
|
+
try:
|
|
391
|
+
value = json.loads(proc.stdout).get("value") if proc else None
|
|
392
|
+
except (ValueError, AttributeError):
|
|
393
|
+
return None
|
|
394
|
+
return value if isinstance(value, dict) else None
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
def _ours_by_shape(key, value):
|
|
398
|
+
"""True when `value` is exactly a selector this table generates for `key`.
|
|
399
|
+
|
|
400
|
+
The adoption rule for a machine tezgah wrote to before it recorded
|
|
401
|
+
`omp_written`: only one of our own selectors is ever taken over, so a value
|
|
402
|
+
the user picked by hand is never claimed - unless it is a byte-identical copy
|
|
403
|
+
of the selector this table generates for that key in some mode, which is
|
|
404
|
+
indistinguishable from our own write and is treated as ours. A role key is
|
|
405
|
+
adopted the same way, from `omp_role_overrides`."""
|
|
406
|
+
if not isinstance(value, str):
|
|
407
|
+
return False
|
|
408
|
+
# every column, not the two that existed first: a machine whose funded
|
|
409
|
+
# provider is z.ai holds the zai column's own selectors, and reading those as
|
|
410
|
+
# the user's left three entries behind on a mode switch (measured 2026-10-01).
|
|
411
|
+
# A plain selector still counts on every column even though the table now
|
|
412
|
+
# writes chains: pre-chain installs hold single-family selectors, and the
|
|
413
|
+
# bytes are ours whichever shape we wrote.
|
|
414
|
+
slot = AGENT_SLOT.get(key) or BUNDLED.get(key)
|
|
415
|
+
if slot and any(_selector(family, slot) == value for family in OMP_FAMILIES):
|
|
416
|
+
return True
|
|
417
|
+
if key.split(".", 1)[-1] in OMP_ROLES and any(
|
|
418
|
+
_selector(family, "frontier") == value for family in OMP_FAMILIES):
|
|
419
|
+
return True
|
|
420
|
+
return any((omp_overrides(mode) or {}).get(key) == value or
|
|
421
|
+
(omp_role_overrides(mode) or {}).get(key) == value
|
|
422
|
+
for mode in MODES)
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def _reconcile(current, written, want):
|
|
426
|
+
"""(new, owns) for one flat {key: value} record, keys tezgah's own and the
|
|
427
|
+
user's alike: `current` what omp holds, `written` the last recorded write,
|
|
428
|
+
`want` what this mode asks for.
|
|
429
|
+
|
|
430
|
+
An entry is tezgah's to change only while it is absent or still carries what
|
|
431
|
+
`omp_written` recorded (or, on a machine written before that record existed,
|
|
432
|
+
one of the table's own selectors - `_ours_by_shape`). A value the user
|
|
433
|
+
changed by hand is left alone, an entry tezgah never wrote is never dropped,
|
|
434
|
+
and ours that is no longer wanted goes."""
|
|
435
|
+
new, owns = {}, {}
|
|
436
|
+
for key in sorted(set(current) | set(written) | set(want)):
|
|
437
|
+
cur = current.get(key)
|
|
438
|
+
mine = (key in written and cur == written[key]) or (
|
|
439
|
+
key not in written and _ours_by_shape(key, cur))
|
|
440
|
+
if key in want:
|
|
441
|
+
# byte-identical to what we want counts as ours: claiming it writes
|
|
442
|
+
# the same value and only records ownership, which is what lets the
|
|
443
|
+
# next mode switch move it instead of leaving it behind
|
|
444
|
+
if cur is None or mine or cur == want[key]:
|
|
445
|
+
new[key], owns[key] = want[key], want[key]
|
|
446
|
+
else:
|
|
447
|
+
new[key] = cur # the user's own choice for this key wins
|
|
448
|
+
elif mine:
|
|
449
|
+
# ours, and no longer wanted: drop it. `cur != written.get(key)` is
|
|
450
|
+
# only a user change when tezgah actually recorded a value - an
|
|
451
|
+
# adopted entry has no record, so comparing against None would keep
|
|
452
|
+
# every pre-record install's overrides forever.
|
|
453
|
+
if key in written and cur is not None and cur != written[key]:
|
|
454
|
+
new[key] = cur # the user changed ours: keep it
|
|
455
|
+
elif cur is not None:
|
|
456
|
+
new[key] = cur
|
|
457
|
+
return new, owns
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
def apply_omp(remove=False):
|
|
461
|
+
"""Write (or, with `remove`, drop) this table's entries of omp's
|
|
462
|
+
`task.agentModelOverrides` and its `modelRoles.plan` and `.slow`, leaving
|
|
463
|
+
everything else as it is.
|
|
464
|
+
|
|
465
|
+
Ownership, because `config set` replaces the whole record: an entry is
|
|
466
|
+
tezgah's to change only while it is absent or still carries what the last
|
|
467
|
+
write recorded in `omp_written` (or, on a machine written before that
|
|
468
|
+
record existed, one of the table's own selectors - `_ours_by_shape`); roles
|
|
469
|
+
are recorded under their flat `modelRoles.<role>` key in the same record. A
|
|
470
|
+
value the user changed by hand is left alone, and an entry tezgah never
|
|
471
|
+
wrote is never dropped. omp's bundled agents are covered too (see BUNDLED),
|
|
472
|
+
and the roles are the same rule applied to `modelRoles`.
|
|
473
|
+
|
|
474
|
+
`any` needs a resolvable OpenRouter credential: without one the overrides
|
|
475
|
+
could not run, so nothing is written and the status says so. Returns a
|
|
476
|
+
one-line status, or None when omp is not answering."""
|
|
477
|
+
current = omp_get("task.agentModelOverrides")
|
|
478
|
+
roles = omp_get("modelRoles")
|
|
479
|
+
chains = omp_get("retry.fallbackChains") or {}
|
|
480
|
+
if current is None or roles is None:
|
|
481
|
+
return None
|
|
482
|
+
written = overlay().get("omp_written") or {}
|
|
483
|
+
mode, want, want_roles = None, {}, {}
|
|
484
|
+
if not remove:
|
|
485
|
+
mode = omp_mode(roles.get("default"))
|
|
486
|
+
if mode == "off":
|
|
487
|
+
# the user asked for no routing: drop every entry this table wrote
|
|
488
|
+
# and write nothing. A provider the selectors need can run out of
|
|
489
|
+
# budget (measured: an OpenRouter key that could not afford the
|
|
490
|
+
# request), and the way back must not have to be `--uninstall`.
|
|
491
|
+
remove = True
|
|
492
|
+
elif mode == "any" and not openrouter_ready():
|
|
493
|
+
return ("omp model overrides %s the any mode needs an OpenRouter key "
|
|
494
|
+
"(or `tezgah-route --mode anthropic`)" % SKIP_MARK)
|
|
495
|
+
else:
|
|
496
|
+
want = omp_overrides(mode)
|
|
497
|
+
want_roles = omp_role_overrides(mode)
|
|
498
|
+
flat_roles = {"modelRoles." + role: roles.get(role) for role in OMP_ROLES}
|
|
499
|
+
new, owns = _reconcile(current, written, want)
|
|
500
|
+
new_roles, owns_roles = _reconcile(flat_roles, written, want_roles)
|
|
501
|
+
owns.update(owns_roles)
|
|
502
|
+
merged = dict(roles) # every other role the user set stays as it is
|
|
503
|
+
for key in flat_roles: # a role this table drops leaves no key behind
|
|
504
|
+
role = key.split(".", 1)[1]
|
|
505
|
+
value = new_roles.get(key)
|
|
506
|
+
if value is None:
|
|
507
|
+
merged.pop(role, None)
|
|
508
|
+
else:
|
|
509
|
+
merged[role] = value
|
|
510
|
+
# the roles' fallbacks live in omp's retry table, under keys tezgah owns:
|
|
511
|
+
# `default` and the provider-keyed chains stay the user's
|
|
512
|
+
flat_chains = {"retry.fallbackChains." + role: chains.get(role)
|
|
513
|
+
for role in OMP_ROLES}
|
|
514
|
+
want_chains = {} if remove else omp_role_chains(mode)
|
|
515
|
+
new_chains, owns_chains = _reconcile(flat_chains, written, want_chains)
|
|
516
|
+
owns.update(owns_chains)
|
|
517
|
+
merged_chains = dict(chains)
|
|
518
|
+
for key in flat_chains:
|
|
519
|
+
role = key.split(".", 1)[1]
|
|
520
|
+
value = new_chains.get(key)
|
|
521
|
+
if value is None:
|
|
522
|
+
merged_chains.pop(role, None)
|
|
523
|
+
else:
|
|
524
|
+
merged_chains[role] = value
|
|
525
|
+
if owns == written and new == current and merged == roles \
|
|
526
|
+
and merged_chains == chains:
|
|
527
|
+
return "omp model overrides current (%s)" % (mode or "none")
|
|
528
|
+
# the write comes first: recording what tezgah owns before the record it
|
|
529
|
+
# describes exists would leave a failed write claiming entries it never wrote
|
|
530
|
+
if new != current and _omp_set("task.agentModelOverrides", new) is None:
|
|
531
|
+
return "omp model overrides NOT written"
|
|
532
|
+
if merged != roles and _omp_set("modelRoles", merged) is None:
|
|
533
|
+
return "omp model overrides NOT written"
|
|
534
|
+
if merged_chains != chains and _omp_set("retry.fallbackChains",
|
|
535
|
+
merged_chains) is None:
|
|
536
|
+
return "omp model overrides NOT written"
|
|
537
|
+
data = overlay()
|
|
538
|
+
data["omp_written"] = owns
|
|
539
|
+
if not save_overlay(data):
|
|
540
|
+
return ("omp model overrides written, ownership NOT recorded "
|
|
541
|
+
"(overlay unreadable)")
|
|
542
|
+
return ("omp model overrides removed (%s)" % (mode or "uninstall") if remove
|
|
543
|
+
else "omp model overrides written (%s)" % mode)
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
# ---------------------------------------------------------------- refresh ----
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
def refresh(timeout=20):
|
|
550
|
+
"""Re-read prices and ids from OpenRouter, resolve opencode selectors, and
|
|
551
|
+
write the overlay. Returns (lines, ok)."""
|
|
552
|
+
data = overlay()
|
|
553
|
+
lines = []
|
|
554
|
+
try:
|
|
555
|
+
with urllib.request.urlopen(OPENROUTER_MODELS, timeout=timeout) as resp:
|
|
556
|
+
listed = {m["id"]: m for m in json.load(resp).get("data", [])}
|
|
557
|
+
except Exception as exc: # ponytail: any fetch failure keeps the old overlay
|
|
558
|
+
return ["could not read %s (%s); nothing changed" % (OPENROUTER_MODELS, exc)], False
|
|
559
|
+
ids = sorted(set(SNAPSHOT))
|
|
560
|
+
prices, flags = {}, []
|
|
561
|
+
for mid in ids:
|
|
562
|
+
m = listed.get(mid)
|
|
563
|
+
if not m:
|
|
564
|
+
flags.append("%s is no longer in the OpenRouter list" % mid)
|
|
565
|
+
continue
|
|
566
|
+
p = m.get("pricing") or {}
|
|
567
|
+
now = (round(float(p.get("prompt", 0)) * 1e6, 4),
|
|
568
|
+
round(float(p.get("completion", 0)) * 1e6, 4))
|
|
569
|
+
prices[mid] = now
|
|
570
|
+
if tuple(now) != SNAPSHOT[mid]:
|
|
571
|
+
flags.append("%s price moved: %s -> %s per 1M in/out" % (mid, SNAPSHOT[mid], now))
|
|
572
|
+
data.update(read_on=datetime.date.today().isoformat(), prices=prices, flags=flags)
|
|
573
|
+
oc = resolve_opencode()
|
|
574
|
+
if oc is not None:
|
|
575
|
+
data["opencode"] = oc
|
|
576
|
+
lines.append("opencode selectors: %s" % (", ".join(
|
|
577
|
+
"%s=%s" % kv for kv in sorted(oc.items())) or "none found"))
|
|
578
|
+
if not save_overlay(data):
|
|
579
|
+
return lines + ["could not write %s" % OVERLAY], False
|
|
580
|
+
lines.insert(0, "%d model(s) read, %d flag(s)" % (len(prices), len(flags)))
|
|
581
|
+
return lines + flags, True
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
def resolve_opencode(timeout=30):
|
|
585
|
+
"""{slot: selector} from `opencode models`, matching each slot's `any` id by
|
|
586
|
+
its model name under whatever provider this machine configured; None when
|
|
587
|
+
opencode is absent."""
|
|
588
|
+
exe = shutil.which("opencode")
|
|
589
|
+
if not exe:
|
|
590
|
+
return None
|
|
591
|
+
try:
|
|
592
|
+
out = subprocess.run([exe, "models"], capture_output=True, text=True,
|
|
593
|
+
timeout=timeout).stdout.split()
|
|
594
|
+
except (OSError, subprocess.SubprocessError):
|
|
595
|
+
return None
|
|
596
|
+
found = {}
|
|
597
|
+
for slot, fams in SLOTS.items():
|
|
598
|
+
want = fams["any"][0]
|
|
599
|
+
name = want.split("/", 1)[-1]
|
|
600
|
+
exact = [s for s in out if s == want]
|
|
601
|
+
near = [s for s in out if s.endswith("/" + name)]
|
|
602
|
+
if exact or near:
|
|
603
|
+
found[slot] = (exact or near)[0]
|
|
604
|
+
return found
|
|
605
|
+
|
|
606
|
+
|
|
607
|
+
def check(today=None):
|
|
608
|
+
"""(lines, stale): the table's age and the flags the last refresh left."""
|
|
609
|
+
data = overlay()
|
|
610
|
+
today = today or datetime.date.today()
|
|
611
|
+
read = data.get("read_on") or READ_ON
|
|
612
|
+
age = (today - datetime.date.fromisoformat(READ_ON)).days
|
|
613
|
+
lines = ["scores and picks read %s (%d days ago); prices read %s" % (READ_ON, age, read),
|
|
614
|
+
"omp mode: %s" % (data.get("mode") or "auto")]
|
|
615
|
+
flags = data.get("flags") or []
|
|
616
|
+
lines += ["flag: %s" % f for f in flags]
|
|
617
|
+
stale = age > STALE_DAYS or bool(flags)
|
|
618
|
+
if age > STALE_DAYS:
|
|
619
|
+
lines.append("stale: re-read the phase scores (docs/models.md) and update the table")
|
|
620
|
+
return lines, stale
|
|
621
|
+
|
|
622
|
+
|
|
623
|
+
# ------------------------------------------------------------------ route ----
|
|
624
|
+
|
|
625
|
+
# The classes that go to frontier by rule, before any judgement: the data and
|
|
626
|
+
# secret shapes a wrong call cannot be undone on, destructive data and history
|
|
627
|
+
# operations, privilege changes, and the gate's own files. Word-bounded on
|
|
628
|
+
# purpose - `migrate_rows` is a rename, `secretary` is not a secret,
|
|
629
|
+
# `password-less` is a property, `dropdown` drops nothing - while `\bsecurity\b`
|
|
630
|
+
# is kept even when it names a file, because an over-route costs money and an
|
|
631
|
+
# under-route costs a rework loop.
|
|
632
|
+
OVERRIDE = re.compile(
|
|
633
|
+
r"stored data|on disk|\bpersist\w*|\bschemas?\b|"
|
|
634
|
+
r"\bmigrat(?:e|es|ed|ing|ion|ions|or)\b|"
|
|
635
|
+
r"\bcredential\w*|\bsecrets?\b|\bpasswords?\b(?!-less)|"
|
|
636
|
+
r"\bapi[- ]keys?\b|\baccess token\b|\brefresh token\b|\bsession token\b|"
|
|
637
|
+
r"\bsession cookies?\b|\bsigning keys?\b|\bjwt\b|\boauth\b|\bauthn\b|"
|
|
638
|
+
r"\bauthz?\b|tezgah_gate|tezgah_integrity|\bsecurity\b|threat model|"
|
|
639
|
+
r"\bencrypt\w*|\bauthentication\b|\bauthorization\b|\bpii\b|"
|
|
640
|
+
r"customer records|"
|
|
641
|
+
# destructive data and history
|
|
642
|
+
r"\bdrop\s+(?:the\s+)?(?:\w+\s+)?(?:tables?|databases?|columns?|indexes)\b|"
|
|
643
|
+
r"\btruncate\s+(?:the\s+)?(?:\w+\s+)?tables?\b|"
|
|
644
|
+
r"\bdelete\s+(?:\w+\s+){0,3}(?:rows?|records?|accounts?)\b|"
|
|
645
|
+
r"\bproduction (?:database|db|data)\b|\brm -rf\b|\bforce[- ]push\w*|"
|
|
646
|
+
r"\brewr\w* (?:the |git )?history\b|\brewritten history\b|\bfilter-(?:repo|branch)\b|"
|
|
647
|
+
# keys, certificates and tokens the list above did not name; `PAT` only in
|
|
648
|
+
# capitals, so the name Pat and the plural "pats" stay ordinary words
|
|
649
|
+
r"\bprivate keys?\b|\bssh keys?\b|\bcertificates?\b|\btls\b|\bbearer\b|"
|
|
650
|
+
r"(?-i:\bPATs?\b)|\bpersonal access tokens?\b|\btoken refresh\b|\blogin tokens?\b|"
|
|
651
|
+
# privilege
|
|
652
|
+
r"\bsudo\w*|\bfile permissions?\b|\bchmod\b|\bprivilege\w*|\bsetuid\b", re.I)
|
|
653
|
+
JEV_TIER = {"mechanical": "cheap", "standard": "standard", "frontier": "frontier"}
|
|
654
|
+
PHASE_TIER = {"explore": "standard", "code": "standard", "mechanical": "cheap",
|
|
655
|
+
"plan": "frontier", "review": "frontier", "research": "frontier"}
|
|
656
|
+
TIER_QUESTION = {
|
|
657
|
+
"type": "choice",
|
|
658
|
+
"instructions": (
|
|
659
|
+
"A coding-agent orchestrator must pick the cheapest model tier that can do "
|
|
660
|
+
"`task` correctly on the first attempt. Under-routing (a tier too weak) "
|
|
661
|
+
"costs a rework loop; over-routing only costs money. Which tier does the "
|
|
662
|
+
"task need?"),
|
|
663
|
+
"criteria": {
|
|
664
|
+
"mechanical": "files and change fully specified, no judgement: rename, "
|
|
665
|
+
"fixture, boilerplate, formatting, commit message, version "
|
|
666
|
+
"bump, a listed mechanical migration or translation",
|
|
667
|
+
"standard": "bounded feature or bug fix in known code with a clear cause, "
|
|
668
|
+
"writing tests, code search and summarising, routine review of "
|
|
669
|
+
"a small diff, release notes",
|
|
670
|
+
"frontier": "design or architecture choice, security-sensitive code, a "
|
|
671
|
+
"stored-data or ordering invariant, debugging with an unknown "
|
|
672
|
+
"cause, adversarial review of a large diff, research synthesis, "
|
|
673
|
+
"a hard-to-reverse decision",
|
|
674
|
+
},
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
def route(brief, phase=None, ask=None):
|
|
679
|
+
"""{"agent", "tier", "why", "via", "judge", "judged"} for one delegation
|
|
680
|
+
brief; `via` is what set the tier: `rule`, `jev`, `phase` or `default`, and
|
|
681
|
+
`judge` is the `provider/model` that answered when a judgement set it.
|
|
682
|
+
|
|
683
|
+
`ask` is the judge call (tezgah_judge.ask) - injected so the rule order is
|
|
684
|
+
testable without the network; None means no judge is available. The brief
|
|
685
|
+
goes out redacted (`ti.redact`, the reader the ledger uses) and only when no
|
|
686
|
+
override matched: a brief matching the override vocabulary never leaves the
|
|
687
|
+
machine. Answers are read through the seam's own accessors, so a malformed
|
|
688
|
+
reply is the same as no reply and this never raises."""
|
|
689
|
+
hit = OVERRIDE.search(brief or "")
|
|
690
|
+
if hit:
|
|
691
|
+
return _pick("frontier", "override: %r" % hit.group(0), "rule")
|
|
692
|
+
result = ask({"task": ti.redact(brief or "")}, {"tier": TIER_QUESTION}) if ask else None
|
|
693
|
+
choice = tj.choice(result, "tier")
|
|
694
|
+
if choice in JEV_TIER:
|
|
695
|
+
chance = tj.noul(result, "tier", choice)
|
|
696
|
+
out = _pick(JEV_TIER[choice], "jev %s%s" % (
|
|
697
|
+
choice, "" if chance is None else " %.2f" % chance), "jev")
|
|
698
|
+
out["judge"] = "%s/%s" % (result.get("provider") or "-",
|
|
699
|
+
result.get("model") or "-")
|
|
700
|
+
out["judged"] = result
|
|
701
|
+
return out
|
|
702
|
+
if phase in PHASE_TIER:
|
|
703
|
+
return _pick(PHASE_TIER[phase], "no judgement; static table for phase %s" % phase,
|
|
704
|
+
"phase")
|
|
705
|
+
return _pick("standard", "no judgement and no phase; the middle tier", "default")
|
|
706
|
+
|
|
707
|
+
|
|
708
|
+
def _pick(tier, why, via):
|
|
709
|
+
return {"agent": "tezgah-" + tier, "tier": tier, "why": why, "via": via,
|
|
710
|
+
"judge": None, "judged": None}
|
|
711
|
+
|
|
712
|
+
|
|
713
|
+
def worker_model(agent):
|
|
714
|
+
"""(model, override) the routed agent runs on, as far as this host shows.
|
|
715
|
+
|
|
716
|
+
On omp the agent's own `task.agentModelOverrides` entry is the truth: an
|
|
717
|
+
entry `omp_written` does not hold is the user's (`override` "user"), and no
|
|
718
|
+
entry means the session model (`override` "mode": the mode is `off`, or
|
|
719
|
+
nothing was written). On Claude Code the table's Anthropic row is what the
|
|
720
|
+
generated agent's frontmatter carries. Any other host: (None, None)."""
|
|
721
|
+
if os.environ.get("OMPCODE"): # read first: omp sets CLAUDECODE too
|
|
722
|
+
held = (omp_get("task.agentModelOverrides") or {}).get(agent)
|
|
723
|
+
if not held:
|
|
724
|
+
return None, "mode"
|
|
725
|
+
mine = (overlay().get("omp_written") or {}).get(agent)
|
|
726
|
+
first = held[0] if isinstance(held, list) else held
|
|
727
|
+
return str(first), (None if held == mine else "user")
|
|
728
|
+
picked = pick(agent, "anthropic") if os.environ.get("CLAUDECODE") else None
|
|
729
|
+
if not picked:
|
|
730
|
+
return None, None
|
|
731
|
+
model, effort = picked
|
|
732
|
+
return model + (":" + effort if effort else ""), None
|
|
733
|
+
|
|
734
|
+
|
|
735
|
+
def route_detail(out, phase=None, model=None, override=None):
|
|
736
|
+
"""The `route` ledger row's detail: one `key=value` word per field, so the
|
|
737
|
+
report fold reads it back without a field the ledger contract lacks. `static`
|
|
738
|
+
is the tier the static table (V1b) would have picked, when a phase was given;
|
|
739
|
+
`judge` is who answered a `via=jev` route - `via` keeps its name because the
|
|
740
|
+
fold groups history by it, even when the chat fallback answered."""
|
|
741
|
+
static = " static=" + PHASE_TIER[phase] if phase in PHASE_TIER else ""
|
|
742
|
+
return "tezgah-route tier=%s agent=%s via=%s%s model=%s override=%s judge=%s" % (
|
|
743
|
+
out["tier"], out["agent"], out["via"], static, model or "-", override or "-",
|
|
744
|
+
out.get("judge") or "-")
|
|
745
|
+
|
|
746
|
+
|
|
747
|
+
def route_fields(row):
|
|
748
|
+
"""{field: value} of a `route` row's detail, or None for any other row."""
|
|
749
|
+
words = str(row.get("detail") or "").split()
|
|
750
|
+
if row.get("kind") != "route" or words[:1] != ["tezgah-route"]:
|
|
751
|
+
return None
|
|
752
|
+
fields = dict(w.split("=", 1) for w in words[1:] if "=" in w)
|
|
753
|
+
return fields if fields.get("tier") in TIERS and fields.get("via") else None
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
CHECK_KINDS = ("verify", "verify_ok", "verify_fail")
|
|
757
|
+
|
|
758
|
+
|
|
759
|
+
def _outcome(rows):
|
|
760
|
+
"""The worker's first check: pass, fail, ran (an outcome nobody saw) or none."""
|
|
761
|
+
row = next((r for r in rows if r.get("kind") in CHECK_KINDS), None)
|
|
762
|
+
if row is None:
|
|
763
|
+
return "none"
|
|
764
|
+
if row.get("kind") == "verify_fail":
|
|
765
|
+
return "fail"
|
|
766
|
+
return "pass" if ti.passing_check(row) else "ran"
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
def _in_order(routes, kids):
|
|
770
|
+
"""[child stem] for `routes` [(ts, fields)] in ledger order, or None when
|
|
771
|
+
order cannot prove which child is whose: the counts differ, two spawns share
|
|
772
|
+
a second (the ledger's resolution), a child came before its route, or one came
|
|
773
|
+
at or after the next route, where it could be either route's worker."""
|
|
774
|
+
kids = sorted(kids)
|
|
775
|
+
if len(kids) != len(routes) or len({ts for ts, _stem in kids}) != len(kids):
|
|
776
|
+
return None
|
|
777
|
+
for i, (ts, _stem) in enumerate(kids):
|
|
778
|
+
if ts < routes[i][0] or (i + 1 < len(routes) and ts >= routes[i + 1][0]):
|
|
779
|
+
return None
|
|
780
|
+
return [stem for _ts, stem in kids]
|
|
781
|
+
|
|
782
|
+
|
|
783
|
+
def _join(routes, kids, spawned_as):
|
|
784
|
+
"""[child stem or None] per route. A child's type is what its parent's task
|
|
785
|
+
call recorded for its name (`spawn` rows, omp), else its own `agent` (the
|
|
786
|
+
type itself on opencode). With every child typed, each route agent's routes
|
|
787
|
+
join that agent's children by `_in_order`, and a child of an unrouted type
|
|
788
|
+
is left out; with any child untyped, order over all of them is the only
|
|
789
|
+
evidence. Whatever is not proven stays None (`unjoined`)."""
|
|
790
|
+
typed = [(ts, stem, spawned_as.get(agent, agent)) for ts, stem, agent in kids]
|
|
791
|
+
if any(kind is None for _ts, _stem, kind in typed):
|
|
792
|
+
stems = _in_order(routes, [(ts, stem) for ts, stem, _k in typed])
|
|
793
|
+
return stems or [None] * len(routes)
|
|
794
|
+
out = [None] * len(routes)
|
|
795
|
+
for agent in {fields.get("agent") for _ts, fields in routes}:
|
|
796
|
+
mine = [i for i, (_ts, fields) in enumerate(routes) if fields.get("agent") == agent]
|
|
797
|
+
stems = _in_order([routes[i] for i in mine],
|
|
798
|
+
[(ts, stem) for ts, stem, kind in typed if kind == agent])
|
|
799
|
+
for i, stem in zip(mine, stems or []):
|
|
800
|
+
out[i] = stem
|
|
801
|
+
return out
|
|
802
|
+
|
|
803
|
+
|
|
804
|
+
def route_report(ledgers):
|
|
805
|
+
"""({(via, tier): counts}, counts for Jev routes below the static tier) over
|
|
806
|
+
{ledger stem: rows}.
|
|
807
|
+
|
|
808
|
+
A routed worker runs in its own session, so its checks are in its own ledger,
|
|
809
|
+
whose `spawned` row names the parent session the route row was written under.
|
|
810
|
+
A route joins the child `_join` can prove is its worker, and the outcome is
|
|
811
|
+
that child's first check (`pass`, `fail`, `ran`, `none`). A route it cannot
|
|
812
|
+
prove - an unrouted spawn, a tie, a host that writes no `spawned` row - is
|
|
813
|
+
`unjoined`: the parent's own next check is never taken for the worker's, and
|
|
814
|
+
neither is a guess. The second count is the V2-as-default question: Jev
|
|
815
|
+
picking under the static table's tier, and how often that first attempt
|
|
816
|
+
failed (docs/models.md)."""
|
|
817
|
+
def counts():
|
|
818
|
+
return {"routes": 0, "pass": 0, "fail": 0, "ran": 0, "none": 0, "unjoined": 0}
|
|
819
|
+
def spawn_rows(rows):
|
|
820
|
+
return [r for r in rows
|
|
821
|
+
if r.get("kind") == "spawn" and r.get("child") and r.get("agent")]
|
|
822
|
+
children = {}
|
|
823
|
+
for stem, rows in ledgers.items():
|
|
824
|
+
link = next((r for r in rows if r.get("kind") == "spawned" and r.get("parent")),
|
|
825
|
+
None)
|
|
826
|
+
if link:
|
|
827
|
+
children.setdefault(ti._slug(link["parent"]), []).append(
|
|
828
|
+
(link.get("ts") or 0, stem, link.get("agent")))
|
|
829
|
+
groups, below = {}, counts()
|
|
830
|
+
for stem, rows in ledgers.items():
|
|
831
|
+
routes = [(r.get("ts") or 0, f) for r, f in ((r, route_fields(r)) for r in rows) if f]
|
|
832
|
+
if not routes:
|
|
833
|
+
continue
|
|
834
|
+
# The task calls of this parent and of its own children only: a nested
|
|
835
|
+
# orchestrator shares the parent's TEZGAH_SESSION, so its worker names
|
|
836
|
+
# that parent while the row typing the worker is in the orchestrator's
|
|
837
|
+
# ledger. Another session's task names never type this one's children.
|
|
838
|
+
# A name two calls typed differently is untyped (None): order decides.
|
|
839
|
+
spawned_as = {}
|
|
840
|
+
for r in spawn_rows(rows) + [r for _ts, kid, _a in children.get(stem, [])
|
|
841
|
+
for r in spawn_rows(ledgers[kid])]:
|
|
842
|
+
if spawned_as.setdefault(r["child"], r["agent"]) != r["agent"]:
|
|
843
|
+
spawned_as[r["child"]] = None
|
|
844
|
+
for (_ts, fields), kid in zip(routes, _join(routes, children.get(stem, []),
|
|
845
|
+
spawned_as)):
|
|
846
|
+
outcome = _outcome(ledgers[kid]) if kid else "unjoined"
|
|
847
|
+
bins = [groups.setdefault((fields["via"], fields["tier"]), counts())]
|
|
848
|
+
static = fields.get("static")
|
|
849
|
+
if fields["via"] == "jev" and static in TIERS and \
|
|
850
|
+
TIERS.index(fields["tier"]) < TIERS.index(static):
|
|
851
|
+
bins.append(below)
|
|
852
|
+
for b in bins:
|
|
853
|
+
b["routes"] += 1
|
|
854
|
+
b[outcome] += 1
|
|
855
|
+
return groups, below
|