The Claude Code adapter previously passed --json-schema alone. On Claude
CLI 2.1.160 that combination still emits the model's conversational
preamble on stdout while the schema-enforced structured payload ships on
a sidecar channel the adapter cannot read. Result: callers requesting
structured output got prose that fails JSON parsing downstream — exactly
the failure mode the activity-core CUST-WP-0045 daily triage canary hit
on 2026-06-01 ("Triage report generated and returned via structured
output. Key signals:..." → json.loads error at column 1).
Fix: when --json-schema is set, also pass --output-format json. The CLI
then writes a JSON envelope on stdout. The adapter unwraps it by
probing a small allowlist of known text-bearing fields (result,
result_text, content, text, output). Unknown envelope shapes fall
through to raw stdout so the operator can introspect the structure and
extend the allowlist.
The unwrap path is only triggered when --json-schema was set, so non-
schema callers keep the existing raw-stdout behavior.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Drafted workplan to move two consumer-side concerns into llm-connect:
- ModelRateRegistry: per-model USD-per-1k rates with provenance, a
property of the base model, not the application.
- ProblemClass token estimators: generic shapes (chunk-summarization,
entity-extraction, relation-extraction, judge-eval, report-synthesis)
with base dimensions + tunable params; consumer supplies the shape
of its problem and gets a TokenEstimate before any call.
Demand signal: the 2026-05-18 infospace-bench Lefevre Chapter-I smoke
ran 32 calls / 28k tokens / 0.009 USD actual against a planned 8.40
USD — the 1000x variance was entirely consumer-side because there is
no rate table in llm-connect to delegate to.
Three new modules (rates.py, costs.py, problem_classes.py), eight
tasks, registered as workstream 869196c5-551b-4eef-b8d8-cca6f770a9b0
under the custodian topic. A follow-on consumer workplan in
infospace-bench will migrate plan_generation_summary to delegate once
T01-T04 land here.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Draft the workplan that extends the static RoutingPolicy (WP-0003) with
a quality observation ledger, a BaselineGrader (ClaudeCodeAdapter as the
default oracle), an AdaptiveRoutingPolicy that picks the cheapest
adapter clearing a per-task quality floor, and a sampled
ShadowingAdapter for production observation collection.
Scope is explicit: ship primitives only. Task-type taxonomy, quality
thresholds, baseline choice, and re-grading cadence stay with the
consumer. infospace-bench is the named first consumer; consumer wiring
deferred until T01-T03 land.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Remove redundant async_execute_prompt overrides from OpenAI/Gemini/OpenRouter
adapters (identical to base class default — asyncio import also removed)
- Cache prompt.split() result in MockLLMAdapter to avoid double evaluation
- Promote deferred LLMBudgetExceededError imports to module level in
models.py and adapter.py (no circular dependency)
- Auto-populate context dict in LLMBudgetExceededError.__init__ so callers
need not pass redundant context= kwarg
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Registers llm-connect with the Custodian agent system:
- CLAUDE.md: thin @-import index pointing to modular rules
- .claude/rules/session-protocol.md: orient with get_domain_summary("custodian")
- .claude/rules/repo-identity.md: domain=custodian, slug=llm-connect
- .claude/rules/first-session.md, workplan-convention.md, stack-and-commands.md,
architecture.md, repo-boundary.md, agents.md, scope.md (stubs to fill in)
- session-protocol notes both local (:8000) and CoulombCore bridge (:18000) URLs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds uv lockfile and .venv. Only runtime dep is toml; pytest added as dev dep.
Service-level dependencies (OpenAI, Gemini, Anthropic, OpenRouter APIs) are
tracked separately via the state-hub capability/service dependency system.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Copy markitect.llm module into standalone llm_connect package.
All markitect.* imports replaced with llm_connect.* equivalents.
LLMError base class inlined (no markitect.exceptions dependency).
Verified: from llm_connect import create_adapter works.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>