Repository navigation
v1.0.50
Changes
Driver registration was copy-pasted across five files and three modalities deep -- the kind of sprawl that makes adding a new provider feel like filing taxes. This PR consolidates all provider definitions into a single ProviderDescriptor dataclass, replaces ~800 lines of scattered register_*() calls with one register_all_builtin_drivers() loop, and reworks the streaming layer to surface thinking deltas alongside text deltas.
Highlights
- Streaming now emits thinking/reasoning chunks from Claude models in real time, not just the final text
- New
extract_with_models()function tries multiple models in priority order with full cost and attempt tracking ExtractResultis now a proper class with attribute access instead of an anonymoustype()hack created at every call site
Technical changes
Driver registration overhaul
- New
ProviderDescriptordataclass inprompture/drivers/provider_descriptors.pyis the single source of truth for all 17 providers and 9 aliases across LLM, STT, TTS, image-gen, and embedding modalities register_all_builtin_drivers()iterates descriptors and registers factories for every modality, replacing ~200 lines of individualregister_driver()/register_async_driver()calls previously in__init__.py,async_registry.py,audio_registry.py,embedding_registry.py, andimg_gen_registry.pyPROVIDER_DRIVER_MAPandASYNC_PROVIDER_DRIVER_MAPare now derived from descriptors viabuild_provider_driver_map(), replacing ~120 lines of hardcoded dicts- New
DriverRegistryclass inprompture/drivers/driver_registry.pyencapsulates registry dict + entry-point loading, replacing 10 bare dicts and 4_ensure_*_loaded()global-flag patterns inregistry.py registry.pydelegates all operations toDriverRegistryinstances; backwards-compat_SYNC_REGISTRY/_ASYNC_REGISTRYaliases point to the underlying dicts
Streaming architecture
Conversation._ask_stream_raw()andAsyncConversation._ask_stream_raw()yield typed dicts ({"type": "delta", "text": ...}/{"type": "thinking_delta", "text": ...}) instead of plain strings- Public
ask_stream()remains unchanged (yieldsstr) by filtering_ask_stream_raw()output StreamEventType.thinking_deltaadded to the agent event enumAgentandAsyncAgentpropagatethinking_deltaevents from_ask_stream_raw()during no-tool streamingClaudeDriverandAsyncClaudeDrivernow yield{"type": "thinking_delta", ...}chunks during extended thinking- Accumulated
reasoning_contentfromdonechunks is stored on_last_reasoning
Extraction
ExtractResultclass inprompture/extraction/core.pyreplaces 14 inlinetype("ExtractResult", (dict,), {...})constructions across sync/async core and conversation modules_build_usage()and_merge_usage()helpers deduplicate usage-dict construction (was copy-pasted 6 times)extract_with_models()(sync) and async variant auto-selectstepwisevssinglestrategy per model based onsupports_json_mode/supports_json_schemadriver capabilitiesmanual_extract_and_jsonify()deprecated in favor ofextract_and_jsonify(text, schema, driver=driver)extract_and_jsonify()gains an explicitdriver=kwarg; old positionalDriverfirst-arg pattern emitsDeprecationWarningnormalize_field_value()delegates type coercion toconvert_value()/get_type_default()fromtools.py, simplifying the function bodyclean_json_text()now strips code fences even when they don't appear at position 0
Module reorganization
prompture/extraction/tukuy_bridge.pycreated, consolidating the tukuy bridge fromprompture/integrations/tukuy_bridge.pyprompture/bridges/__init__.pydeprecated with re-exports pointing toprompture.infra.tukuy_backend- Tukuy imports throughout (
TukuyLLMBackend,create_tukuy_backend,TukuyTransformer) made lazy withImportErrorguards so the library works without tukuy installed prompture/infra/__init__.pyexportsTukuyLLMBackend,create_tukuy_backend, anddisplay_available_models
Discovery
discovery.pyrefactored to derive provider configuration checks andlist_modelskwargs fromProviderDescriptormetadata instead of hardcoded per-provider blocksdisplay_available_models()added for formatted terminal output of discovered models
Other
dev.ps1renameswatch-lintmode tovalidateVERSIONfile removed (versioning handled entirely bysetuptools_scm).gitignoreexcludes.claude/settings.local.jsonrouting.pygains expanded model-to-provider mapping and fallback logicextract_with_modelsexported fromprompture.aioandprompture.extraction