heph 0.0.49__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- heph-0.0.49/LICENSE +21 -0
- heph-0.0.49/PKG-INFO +95 -0
- heph-0.0.49/README.md +61 -0
- heph-0.0.49/pyproject.toml +65 -0
- heph-0.0.49/setup.cfg +4 -0
- heph-0.0.49/src/ai/__init__.py +1 -0
- heph-0.0.49/src/ai/diagnostics/__init__.py +77 -0
- heph-0.0.49/src/ai/diagnostics/py.typed +1 -0
- heph-0.0.49/src/ai/logging/__init__.py +216 -0
- heph-0.0.49/src/ai/logging/py.typed +1 -0
- heph-0.0.49/src/ai/providers/__init__.py +24 -0
- heph-0.0.49/src/ai/providers/access.py +32 -0
- heph-0.0.49/src/ai/providers/api_profiles.py +127 -0
- heph-0.0.49/src/ai/providers/catalog.py +542 -0
- heph-0.0.49/src/ai/providers/config.py +358 -0
- heph-0.0.49/src/ai/providers/endpoints.py +21 -0
- heph-0.0.49/src/ai/providers/keyring_store.py +131 -0
- heph-0.0.49/src/ai/providers/llama_cpp.py +1464 -0
- heph-0.0.49/src/ai/providers/model_choices.py +175 -0
- heph-0.0.49/src/ai/providers/model_support.py +76 -0
- heph-0.0.49/src/ai/providers/oauth.py +554 -0
- heph-0.0.49/src/ai/providers/py.typed +1 -0
- heph-0.0.49/src/ai/providers/reasoning.py +33 -0
- heph-0.0.49/src/ai/providers/registry.py +441 -0
- heph-0.0.49/src/ai/providers/volatile_keys.py +17 -0
- heph-0.0.49/src/ai/py.typed +1 -0
- heph-0.0.49/src/ai/runtime/__init__.py +73 -0
- heph-0.0.49/src/ai/runtime/_api_types.py +40 -0
- heph-0.0.49/src/ai/runtime/codex_backend.py +475 -0
- heph-0.0.49/src/ai/runtime/config.py +71 -0
- heph-0.0.49/src/ai/runtime/conversation.py +37 -0
- heph-0.0.49/src/ai/runtime/delta.py +17 -0
- heph-0.0.49/src/ai/runtime/engine.py +1188 -0
- heph-0.0.49/src/ai/runtime/errors.py +56 -0
- heph-0.0.49/src/ai/runtime/events.py +129 -0
- heph-0.0.49/src/ai/runtime/messages.py +30 -0
- heph-0.0.49/src/ai/runtime/prompt_cache.py +134 -0
- heph-0.0.49/src/ai/runtime/py.typed +1 -0
- heph-0.0.49/src/ai/runtime/request_payload.py +51 -0
- heph-0.0.49/src/ai/runtime/resilience.py +131 -0
- heph-0.0.49/src/ai/runtime/thinking.py +39 -0
- heph-0.0.49/src/ai/runtime/tool_deltas.py +38 -0
- heph-0.0.49/src/ai/runtime/usage.py +232 -0
- heph-0.0.49/src/ai/runtime/usage_payload.py +64 -0
- heph-0.0.49/src/ai/types/__init__.py +46 -0
- heph-0.0.49/src/ai/types/py.typed +1 -0
- heph-0.0.49/src/extensions/__init__.py +1 -0
- heph-0.0.49/src/extensions/contracts.py +41 -0
- heph-0.0.49/src/extensions/py.typed +1 -0
- heph-0.0.49/src/heph/__init__.py +10 -0
- heph-0.0.49/src/heph/cli/__init__.py +7 -0
- heph-0.0.49/src/heph/cli/main.py +895 -0
- heph-0.0.49/src/heph/cli/py.typed +1 -0
- heph-0.0.49/src/heph/commands/__init__.py +145 -0
- heph-0.0.49/src/heph/commands/_base.py +72 -0
- heph-0.0.49/src/heph/commands/armory.py +166 -0
- heph-0.0.49/src/heph/commands/auth.py +246 -0
- heph-0.0.49/src/heph/commands/compact.py +36 -0
- heph-0.0.49/src/heph/commands/display.py +195 -0
- heph-0.0.49/src/heph/commands/help.py +81 -0
- heph-0.0.49/src/heph/commands/local.py +222 -0
- heph-0.0.49/src/heph/commands/memory.py +34 -0
- heph-0.0.49/src/heph/commands/model.py +124 -0
- heph-0.0.49/src/heph/commands/py.typed +1 -0
- heph-0.0.49/src/heph/commands/session.py +327 -0
- heph-0.0.49/src/heph/commands/settings.py +59 -0
- heph-0.0.49/src/heph/commands/study.py +341 -0
- heph-0.0.49/src/heph/commands/suggestions.py +12 -0
- heph-0.0.49/src/heph/commands/terminal_text.py +14 -0
- heph-0.0.49/src/heph/identity/README.md +6 -0
- heph-0.0.49/src/heph/local_llm.py +29 -0
- heph-0.0.49/src/heph/product/__init__.py +5 -0
- heph-0.0.49/src/heph/product/context.py +5 -0
- heph-0.0.49/src/heph/product/py.typed +1 -0
- heph-0.0.49/src/heph/prompts/README.md +6 -0
- heph-0.0.49/src/heph/py.typed +1 -0
- heph-0.0.49/src/heph/release_state.py +130 -0
- heph-0.0.49/src/heph/sdk/__init__.py +353 -0
- heph-0.0.49/src/heph/sdk/capabilities.py +1397 -0
- heph-0.0.49/src/heph/sdk/compatibility.py +449 -0
- heph-0.0.49/src/heph/sdk/config.py +170 -0
- heph-0.0.49/src/heph/sdk/events.py +351 -0
- heph-0.0.49/src/heph/sdk/factory.py +198 -0
- heph-0.0.49/src/heph/sdk/materials.py +123 -0
- heph-0.0.49/src/heph/sdk/method_validation.py +1175 -0
- heph-0.0.49/src/heph/sdk/methods.py +1610 -0
- heph-0.0.49/src/heph/sdk/models.py +90 -0
- heph-0.0.49/src/heph/sdk/operation_stream.py +64 -0
- heph-0.0.49/src/heph/sdk/providers.py +165 -0
- heph-0.0.49/src/heph/sdk/runtime.py +737 -0
- heph-0.0.49/src/heph/sdk/service.py +676 -0
- heph-0.0.49/src/heph/sdk/service_availability.py +237 -0
- heph-0.0.49/src/heph/sdk/service_contract.py +150 -0
- heph-0.0.49/src/heph/sdk/service_routes.py +445 -0
- heph-0.0.49/src/heph/sdk/settings.py +257 -0
- heph-0.0.49/src/heph/sdk/state.py +398 -0
- heph-0.0.49/src/heph/sdk/stdio.py +522 -0
- heph-0.0.49/src/heph/sdk/stdio_client.py +1403 -0
- heph-0.0.49/src/heph/sdk/stdio_contract.py +206 -0
- heph-0.0.49/src/heph/sdk/stdio_json.py +27 -0
- heph-0.0.49/src/heph/sdk/stdio_requests.py +122 -0
- heph-0.0.49/src/heph/sdk/stdio_routes.py +97 -0
- heph-0.0.49/src/heph/sdk/stdio_state.py +181 -0
- heph-0.0.49/src/heph/sdk/value_types.py +181 -0
- heph-0.0.49/src/heph/state/README.md +10 -0
- heph-0.0.49/src/heph/state/release.toml +13 -0
- heph-0.0.49/src/heph.egg-info/PKG-INFO +95 -0
- heph-0.0.49/src/heph.egg-info/SOURCES.txt +351 -0
- heph-0.0.49/src/heph.egg-info/dependency_links.txt +1 -0
- heph-0.0.49/src/heph.egg-info/entry_points.txt +3 -0
- heph-0.0.49/src/heph.egg-info/requires.txt +11 -0
- heph-0.0.49/src/heph.egg-info/top_level.txt +5 -0
- heph-0.0.49/src/hephaion/__init__.py +1 -0
- heph-0.0.49/src/hephaion/_types/__init__.py +19 -0
- heph-0.0.49/src/hephaion/_types/py.typed +1 -0
- heph-0.0.49/src/hephaion/agent/__init__.py +32 -0
- heph-0.0.49/src/hephaion/agent/armory_tools.py +441 -0
- heph-0.0.49/src/hephaion/agent/citation.py +164 -0
- heph-0.0.49/src/hephaion/agent/compact.py +365 -0
- heph-0.0.49/src/hephaion/agent/dispatch.py +467 -0
- heph-0.0.49/src/hephaion/agent/dispatch_support.py +294 -0
- heph-0.0.49/src/hephaion/agent/file_tools.py +375 -0
- heph-0.0.49/src/hephaion/agent/material_tools.py +181 -0
- heph-0.0.49/src/hephaion/agent/model_stream.py +269 -0
- heph-0.0.49/src/hephaion/agent/mutation_queue.py +97 -0
- heph-0.0.49/src/hephaion/agent/path_safety.py +73 -0
- heph-0.0.49/src/hephaion/agent/prompt.py +273 -0
- heph-0.0.49/src/hephaion/agent/py.typed +1 -0
- heph-0.0.49/src/hephaion/agent/runtime_notes.py +156 -0
- heph-0.0.49/src/hephaion/agent/shell_tools.py +239 -0
- heph-0.0.49/src/hephaion/agent/steering.py +42 -0
- heph-0.0.49/src/hephaion/agent/tool_execution.py +513 -0
- heph-0.0.49/src/hephaion/agent/tool_registry.py +129 -0
- heph-0.0.49/src/hephaion/agent/tool_schema.py +52 -0
- heph-0.0.49/src/hephaion/agent/tools.py +411 -0
- heph-0.0.49/src/hephaion/agent/web_tools.py +339 -0
- heph-0.0.49/src/hephaion/armory/__init__.py +37 -0
- heph-0.0.49/src/hephaion/armory/cli.py +105 -0
- heph-0.0.49/src/hephaion/armory/py.typed +1 -0
- heph-0.0.49/src/hephaion/armory/search.py +255 -0
- heph-0.0.49/src/hephaion/armory/state_files.py +218 -0
- heph-0.0.49/src/hephaion/armory/storage.py +130 -0
- heph-0.0.49/src/hephaion/armory/trust.py +35 -0
- heph-0.0.49/src/hephaion/chat/__init__.py +0 -0
- heph-0.0.49/src/hephaion/chat/agent_request.py +130 -0
- heph-0.0.49/src/hephaion/chat/armory_turn.py +222 -0
- heph-0.0.49/src/hephaion/chat/automation.py +37 -0
- heph-0.0.49/src/hephaion/chat/citation_patterns.py +22 -0
- heph-0.0.49/src/hephaion/chat/cli.py +51 -0
- heph-0.0.49/src/hephaion/chat/compaction.py +56 -0
- heph-0.0.49/src/hephaion/chat/conversation_context.py +70 -0
- heph-0.0.49/src/hephaion/chat/current_topic_planning.py +151 -0
- heph-0.0.49/src/hephaion/chat/events.py +61 -0
- heph-0.0.49/src/hephaion/chat/evidence.py +1012 -0
- heph-0.0.49/src/hephaion/chat/evidence_assessment.py +508 -0
- heph-0.0.49/src/hephaion/chat/evidence_format.py +21 -0
- heph-0.0.49/src/hephaion/chat/evidence_notices.py +120 -0
- heph-0.0.49/src/hephaion/chat/evidence_overview.py +172 -0
- heph-0.0.49/src/hephaion/chat/evidence_prompt.py +43 -0
- heph-0.0.49/src/hephaion/chat/evidence_text.py +100 -0
- heph-0.0.49/src/hephaion/chat/followup_intent_resolution.py +332 -0
- heph-0.0.49/src/hephaion/chat/followup_retrieval.py +706 -0
- heph-0.0.49/src/hephaion/chat/intent.py +143 -0
- heph-0.0.49/src/hephaion/chat/intent_resolution.py +373 -0
- heph-0.0.49/src/hephaion/chat/learning_reply.py +440 -0
- heph-0.0.49/src/hephaion/chat/learning_signals.py +256 -0
- heph-0.0.49/src/hephaion/chat/material_state.py +359 -0
- heph-0.0.49/src/hephaion/chat/message_delivery.py +84 -0
- heph-0.0.49/src/hephaion/chat/model_selection.py +86 -0
- heph-0.0.49/src/hephaion/chat/model_text.py +55 -0
- heph-0.0.49/src/hephaion/chat/orchestrator.py +46 -0
- heph-0.0.49/src/hephaion/chat/overview_cues.py +122 -0
- heph-0.0.49/src/hephaion/chat/overview_planning.py +89 -0
- heph-0.0.49/src/hephaion/chat/overview_reply.py +761 -0
- heph-0.0.49/src/hephaion/chat/overview_tables.py +121 -0
- heph-0.0.49/src/hephaion/chat/overview_topics.py +162 -0
- heph-0.0.49/src/hephaion/chat/overview_validation.py +295 -0
- heph-0.0.49/src/hephaion/chat/prior_answer.py +744 -0
- heph-0.0.49/src/hephaion/chat/priority_planning.py +63 -0
- heph-0.0.49/src/hephaion/chat/provider_selection.py +22 -0
- heph-0.0.49/src/hephaion/chat/py.typed +1 -0
- heph-0.0.49/src/hephaion/chat/replayability_planning.py +50 -0
- heph-0.0.49/src/hephaion/chat/reply_evidence.py +58 -0
- heph-0.0.49/src/hephaion/chat/reply_repair.py +549 -0
- heph-0.0.49/src/hephaion/chat/reply_text.py +232 -0
- heph-0.0.49/src/hephaion/chat/session.py +553 -0
- heph-0.0.49/src/hephaion/chat/session_persistence.py +78 -0
- heph-0.0.49/src/hephaion/chat/storage.py +224 -0
- heph-0.0.49/src/hephaion/chat/titles.py +49 -0
- heph-0.0.49/src/hephaion/chat/turn_contract.py +282 -0
- heph-0.0.49/src/hephaion/chat/turn_contract_checks.py +95 -0
- heph-0.0.49/src/hephaion/chat/turn_event_helpers.py +37 -0
- heph-0.0.49/src/hephaion/chat/turn_execution.py +700 -0
- heph-0.0.49/src/hephaion/chat/turn_finalization.py +945 -0
- heph-0.0.49/src/hephaion/chat/turn_history.py +160 -0
- heph-0.0.49/src/hephaion/chat/turn_lifecycle.py +319 -0
- heph-0.0.49/src/hephaion/chat/turn_orchestrator.py +36 -0
- heph-0.0.49/src/hephaion/chat/turn_outputs.py +61 -0
- heph-0.0.49/src/hephaion/chat/turn_planning.py +1020 -0
- heph-0.0.49/src/hephaion/chat/turn_predicates.py +86 -0
- heph-0.0.49/src/hephaion/chat/turn_query.py +257 -0
- heph-0.0.49/src/hephaion/chat/usage.py +146 -0
- heph-0.0.49/src/hephaion/diagnostics/__init__.py +0 -0
- heph-0.0.49/src/hephaion/diagnostics/crashes.py +328 -0
- heph-0.0.49/src/hephaion/diagnostics/events.py +143 -0
- heph-0.0.49/src/hephaion/diagnostics/py.typed +1 -0
- heph-0.0.49/src/hephaion/diagnostics/traces.py +102 -0
- heph-0.0.49/src/hephaion/learning/__init__.py +28 -0
- heph-0.0.49/src/hephaion/learning/actions.py +40 -0
- heph-0.0.49/src/hephaion/learning/automation.py +254 -0
- heph-0.0.49/src/hephaion/learning/cli.py +196 -0
- heph-0.0.49/src/hephaion/learning/constellation.py +231 -0
- heph-0.0.49/src/hephaion/learning/environment.py +131 -0
- heph-0.0.49/src/hephaion/learning/fixtures/__init__.py +3 -0
- heph-0.0.49/src/hephaion/learning/observation.py +392 -0
- heph-0.0.49/src/hephaion/learning/observation_audit.py +257 -0
- heph-0.0.49/src/hephaion/learning/policy.py +90 -0
- heph-0.0.49/src/hephaion/learning/policy_artifact.py +225 -0
- heph-0.0.49/src/hephaion/learning/puffer_backend.py +595 -0
- heph-0.0.49/src/hephaion/learning/reward.py +430 -0
- heph-0.0.49/src/hephaion/learning/storage.py +437 -0
- heph-0.0.49/src/hephaion/learning/training.py +726 -0
- heph-0.0.49/src/hephaion/matching/__init__.py +103 -0
- heph-0.0.49/src/hephaion/matching/py.typed +1 -0
- heph-0.0.49/src/hephaion/materials/__init__.py +426 -0
- heph-0.0.49/src/hephaion/materials/cli.py +97 -0
- heph-0.0.49/src/hephaion/materials/importing.py +168 -0
- heph-0.0.49/src/hephaion/materials/py.typed +1 -0
- heph-0.0.49/src/hephaion/memory/__init__.py +488 -0
- heph-0.0.49/src/hephaion/memory/extract.py +197 -0
- heph-0.0.49/src/hephaion/memory/py.typed +1 -0
- heph-0.0.49/src/hephaion/memory/workflow.py +48 -0
- heph-0.0.49/src/hephaion/parameters/__init__.py +0 -0
- heph-0.0.49/src/hephaion/parameters/cli.py +284 -0
- heph-0.0.49/src/hephaion/parameters/default.toml +14 -0
- heph-0.0.49/src/hephaion/parameters/py.typed +1 -0
- heph-0.0.49/src/hephaion/parameters/settings.py +337 -0
- heph-0.0.49/src/hephaion/privacy/__init__.py +0 -0
- heph-0.0.49/src/hephaion/privacy/consent.py +215 -0
- heph-0.0.49/src/hephaion/privacy/py.typed +1 -0
- heph-0.0.49/src/hephaion/privacy/release.py +9 -0
- heph-0.0.49/src/hephaion/py.typed +1 -0
- heph-0.0.49/src/hephaion/rag/__init__.py +111 -0
- heph-0.0.49/src/hephaion/rag/chunker.py +1191 -0
- heph-0.0.49/src/hephaion/rag/config.py +8 -0
- heph-0.0.49/src/hephaion/rag/context.py +263 -0
- heph-0.0.49/src/hephaion/rag/health.py +80 -0
- heph-0.0.49/src/hephaion/rag/hybrid.py +275 -0
- heph-0.0.49/src/hephaion/rag/index.py +1152 -0
- heph-0.0.49/src/hephaion/rag/index_state.py +36 -0
- heph-0.0.49/src/hephaion/rag/index_timeout.py +220 -0
- heph-0.0.49/src/hephaion/rag/optional_backends.py +168 -0
- heph-0.0.49/src/hephaion/rag/py.typed +1 -0
- heph-0.0.49/src/hephaion/rag/query_audit.py +99 -0
- heph-0.0.49/src/hephaion/rag/query_transform.py +398 -0
- heph-0.0.49/src/hephaion/rag/retrieval_types.py +69 -0
- heph-0.0.49/src/hephaion/rag/retrieve.py +832 -0
- heph-0.0.49/src/hephaion/rag/retrieve_compound.py +149 -0
- heph-0.0.49/src/hephaion/rag/scoring.py +251 -0
- heph-0.0.49/src/hephaion/rag/semantic.py +164 -0
- heph-0.0.49/src/hephaion/rag/source_mapping.py +123 -0
- heph-0.0.49/src/hephaion/rag/sparse.py +497 -0
- heph-0.0.49/src/hephaion/rag/vector.py +69 -0
- heph-0.0.49/src/hephaion/safety/__init__.py +36 -0
- heph-0.0.49/src/hephaion/safety/contracts.py +78 -0
- heph-0.0.49/src/hephaion/safety/local.py +41 -0
- heph-0.0.49/src/hephaion/safety/py.typed +1 -0
- heph-0.0.49/src/hephaion/study/__init__.py +135 -0
- heph-0.0.49/src/hephaion/study/artifacts.py +679 -0
- heph-0.0.49/src/hephaion/study/assessment.py +107 -0
- heph-0.0.49/src/hephaion/study/controller.py +842 -0
- heph-0.0.49/src/hephaion/study/exam.py +387 -0
- heph-0.0.49/src/hephaion/study/exam_bank.py +218 -0
- heph-0.0.49/src/hephaion/study/intent.py +1 -0
- heph-0.0.49/src/hephaion/study/knowledge.py +736 -0
- heph-0.0.49/src/hephaion/study/mastery.py +23 -0
- heph-0.0.49/src/hephaion/study/policy.py +882 -0
- heph-0.0.49/src/hephaion/study/priority.py +823 -0
- heph-0.0.49/src/hephaion/study/priority_analysis.py +92 -0
- heph-0.0.49/src/hephaion/study/priority_progress.py +77 -0
- heph-0.0.49/src/hephaion/study/priority_rendering.py +549 -0
- heph-0.0.49/src/hephaion/study/priority_report.py +731 -0
- heph-0.0.49/src/hephaion/study/priority_topics.py +24 -0
- heph-0.0.49/src/hephaion/study/priority_types.py +172 -0
- heph-0.0.49/src/hephaion/study/priority_web.py +116 -0
- heph-0.0.49/src/hephaion/study/prompt_plans.py +846 -0
- heph-0.0.49/src/hephaion/study/py.typed +1 -0
- heph-0.0.49/src/hephaion/study/schedule.py +744 -0
- heph-0.0.49/src/hephaion/study/state.py +208 -0
- heph-0.0.49/src/hephaion/version/__init__.py +5 -0
- heph-0.0.49/src/hephaion/version/py.typed +1 -0
- heph-0.0.49/src/hephaion/vocab/__init__.py +18 -0
- heph-0.0.49/src/hephaion/vocab/drill.py +261 -0
- heph-0.0.49/src/hephaion/vocab/parser.py +209 -0
- heph-0.0.49/src/hephaion/vocab/py.typed +1 -0
- heph-0.0.49/src/hephaion/vocab/scheduler.py +102 -0
- heph-0.0.49/src/hephaion/vocab/state.py +245 -0
- heph-0.0.49/src/interfaces/__init__.py +1 -0
- heph-0.0.49/src/interfaces/palette/__init__.py +94 -0
- heph-0.0.49/src/interfaces/palette/py.typed +1 -0
- heph-0.0.49/src/interfaces/py.typed +1 -0
- heph-0.0.49/src/interfaces/terminal/__init__.py +255 -0
- heph-0.0.49/src/interfaces/terminal/history.py +65 -0
- heph-0.0.49/src/interfaces/terminal/input.py +100 -0
- heph-0.0.49/src/interfaces/terminal/py.typed +1 -0
- heph-0.0.49/src/interfaces/terminal/source_open.py +60 -0
- heph-0.0.49/src/interfaces/terminal/theme_state.py +29 -0
- heph-0.0.49/src/interfaces/tui/__init__.py +382 -0
- heph-0.0.49/src/interfaces/tui/app_actions.py +622 -0
- heph-0.0.49/src/interfaces/tui/armory.py +841 -0
- heph-0.0.49/src/interfaces/tui/armory_browser.py +377 -0
- heph-0.0.49/src/interfaces/tui/auth_flows.py +318 -0
- heph-0.0.49/src/interfaces/tui/cell_text.py +39 -0
- heph-0.0.49/src/interfaces/tui/command_access.py +54 -0
- heph-0.0.49/src/interfaces/tui/command_output.py +63 -0
- heph-0.0.49/src/interfaces/tui/composer_controls.py +918 -0
- heph-0.0.49/src/interfaces/tui/dependencies.py +21 -0
- heph-0.0.49/src/interfaces/tui/display_text.py +558 -0
- heph-0.0.49/src/interfaces/tui/external_commands.py +320 -0
- heph-0.0.49/src/interfaces/tui/flow_state.py +19 -0
- heph-0.0.49/src/interfaces/tui/history.py +54 -0
- heph-0.0.49/src/interfaces/tui/ids.py +25 -0
- heph-0.0.49/src/interfaces/tui/inline_flows.py +1764 -0
- heph-0.0.49/src/interfaces/tui/inline_menu.py +819 -0
- heph-0.0.49/src/interfaces/tui/keybinds.py +109 -0
- heph-0.0.49/src/interfaces/tui/keyboard_protocol.py +111 -0
- heph-0.0.49/src/interfaces/tui/keymap.py +528 -0
- heph-0.0.49/src/interfaces/tui/local_flows.py +584 -0
- heph-0.0.49/src/interfaces/tui/materials.py +561 -0
- heph-0.0.49/src/interfaces/tui/model_flow.py +62 -0
- heph-0.0.49/src/interfaces/tui/model_flows.py +156 -0
- heph-0.0.49/src/interfaces/tui/option_list_layout.py +64 -0
- heph-0.0.49/src/interfaces/tui/py.typed +1 -0
- heph-0.0.49/src/interfaces/tui/render_state.py +37 -0
- heph-0.0.49/src/interfaces/tui/resize.py +517 -0
- heph-0.0.49/src/interfaces/tui/rich_transcript.py +380 -0
- heph-0.0.49/src/interfaces/tui/routing.py +128 -0
- heph-0.0.49/src/interfaces/tui/search_screen.py +320 -0
- heph-0.0.49/src/interfaces/tui/session_actions.py +211 -0
- heph-0.0.49/src/interfaces/tui/session_flows.py +381 -0
- heph-0.0.49/src/interfaces/tui/session_state.py +90 -0
- heph-0.0.49/src/interfaces/tui/shortcut_hints.py +27 -0
- heph-0.0.49/src/interfaces/tui/slash_command.py +82 -0
- heph-0.0.49/src/interfaces/tui/slash_completion.py +311 -0
- heph-0.0.49/src/interfaces/tui/startup_discovery.py +48 -0
- heph-0.0.49/src/interfaces/tui/status.py +199 -0
- heph-0.0.49/src/interfaces/tui/streaming.py +640 -0
- heph-0.0.49/src/interfaces/tui/style.py +446 -0
- heph-0.0.49/src/interfaces/tui/textual_compat.py +59 -0
- heph-0.0.49/src/interfaces/tui/transcript.py +807 -0
- heph-0.0.49/src/interfaces/tui/transparent.py +454 -0
- heph-0.0.49/src/interfaces/tui/turns.py +223 -0
- heph-0.0.49/src/interfaces/tui/widgets.py +430 -0
heph-0.0.49/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Gil
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
heph-0.0.49/PKG-INFO
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: heph
|
|
3
|
+
Version: 0.0.49
|
|
4
|
+
Summary: Local-first document workspace for grounded answers, citations, memory, and recall practice with any LLM
|
|
5
|
+
Author-email: Gil <hi@gildrb.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/gildrb/heph
|
|
8
|
+
Project-URL: Repository, https://github.com/gildrb/heph
|
|
9
|
+
Project-URL: Issues, https://github.com/gildrb/heph/issues
|
|
10
|
+
Keywords: cli,documents,llm,rag,retrieval,learning
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Utilities
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Python: >=3.13
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: certifi==2026.2.25
|
|
23
|
+
Requires-Dist: keyring==25.7.0
|
|
24
|
+
Requires-Dist: openai==2.24.0
|
|
25
|
+
Requires-Dist: docling==2.94.0
|
|
26
|
+
Requires-Dist: gymnasium==0.29.1
|
|
27
|
+
Requires-Dist: numpy==1.26.4
|
|
28
|
+
Requires-Dist: pufferlib==3.0.0
|
|
29
|
+
Requires-Dist: torch==2.11.0
|
|
30
|
+
Requires-Dist: unicodeit==0.7.5
|
|
31
|
+
Requires-Dist: rich==14.3.3
|
|
32
|
+
Requires-Dist: textual==8.2.4
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
<p align="center">
|
|
36
|
+
<img alt="Hephaion" src="https://gildrb.github.io/heph/logo-auto.svg" width="128">
|
|
37
|
+
</p>
|
|
38
|
+
|
|
39
|
+
# Heph
|
|
40
|
+
|
|
41
|
+
Heph is the agent brain the user talks to.
|
|
42
|
+
|
|
43
|
+
It owns the user-facing agent identity, research/talking orchestration, the
|
|
44
|
+
command entrypoint, slash-command coordination, and the composition needed to
|
|
45
|
+
connect the harness, AI runtime, interfaces, and extension contracts.
|
|
46
|
+
|
|
47
|
+
Heph is not the validation harness. That is Hephaion.
|
|
48
|
+
|
|
49
|
+
## Source Layout
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
src/
|
|
53
|
+
heph/
|
|
54
|
+
cli/ Console entrypoint and top-level command routing
|
|
55
|
+
commands/ Slash-command registry and command coordinators
|
|
56
|
+
sdk/ Programmatic runtime/session surface for native apps and automation
|
|
57
|
+
product/ Temporary bridge for Heph self-knowledge context
|
|
58
|
+
identity/ Stable agent identity target
|
|
59
|
+
prompts/ Prompt-program target for Heph-facing behavior
|
|
60
|
+
state/ Declarative state contract target
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The `product/` bridge exists for current self-knowledge routing. It should stay
|
|
64
|
+
thin and should not become a second harness or a place for domain behavior.
|
|
65
|
+
|
|
66
|
+
## Boundaries
|
|
67
|
+
|
|
68
|
+
Heph is protected as the brain and composition layer. Lower packages must not
|
|
69
|
+
import it, and optional behavior should extend Heph through contracts or
|
|
70
|
+
composition instead of modifying harness or AI internals:
|
|
71
|
+
|
|
72
|
+
- Heph calls Hephaion for grounded answering, validation, citations, retrieval,
|
|
73
|
+
memory, and armory workflows.
|
|
74
|
+
- Heph calls AI for provider/model runtime.
|
|
75
|
+
- Heph calls Interfaces for terminal and TUI presentation.
|
|
76
|
+
- Heph calls Extensions for stable extension contracts.
|
|
77
|
+
- Heph exposes SDK wrappers for non-terminal clients; those wrappers must stay
|
|
78
|
+
UI-neutral and must not import `interfaces.*`.
|
|
79
|
+
|
|
80
|
+
Reusable validation behavior should move to Hephaion. Provider/API behavior
|
|
81
|
+
should move to AI. Conversational strategy, research orchestration, and
|
|
82
|
+
Heph-facing identity should stay here or move here as the migration continues.
|
|
83
|
+
|
|
84
|
+
## Development
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
uv run pytest --no-cov packages/heph/test
|
|
88
|
+
uv run heph --help
|
|
89
|
+
uv run python -m scripts.check_repo_policies
|
|
90
|
+
uv run lint-imports
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Related Docs
|
|
94
|
+
|
|
95
|
+
- [Root architecture guide](../../docs/architecture.md)
|
heph-0.0.49/README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img alt="Hephaion" src="https://gildrb.github.io/heph/logo-auto.svg" width="128">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# Heph
|
|
6
|
+
|
|
7
|
+
Heph is the agent brain the user talks to.
|
|
8
|
+
|
|
9
|
+
It owns the user-facing agent identity, research/talking orchestration, the
|
|
10
|
+
command entrypoint, slash-command coordination, and the composition needed to
|
|
11
|
+
connect the harness, AI runtime, interfaces, and extension contracts.
|
|
12
|
+
|
|
13
|
+
Heph is not the validation harness. That is Hephaion.
|
|
14
|
+
|
|
15
|
+
## Source Layout
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
src/
|
|
19
|
+
heph/
|
|
20
|
+
cli/ Console entrypoint and top-level command routing
|
|
21
|
+
commands/ Slash-command registry and command coordinators
|
|
22
|
+
sdk/ Programmatic runtime/session surface for native apps and automation
|
|
23
|
+
product/ Temporary bridge for Heph self-knowledge context
|
|
24
|
+
identity/ Stable agent identity target
|
|
25
|
+
prompts/ Prompt-program target for Heph-facing behavior
|
|
26
|
+
state/ Declarative state contract target
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The `product/` bridge exists for current self-knowledge routing. It should stay
|
|
30
|
+
thin and should not become a second harness or a place for domain behavior.
|
|
31
|
+
|
|
32
|
+
## Boundaries
|
|
33
|
+
|
|
34
|
+
Heph is protected as the brain and composition layer. Lower packages must not
|
|
35
|
+
import it, and optional behavior should extend Heph through contracts or
|
|
36
|
+
composition instead of modifying harness or AI internals:
|
|
37
|
+
|
|
38
|
+
- Heph calls Hephaion for grounded answering, validation, citations, retrieval,
|
|
39
|
+
memory, and armory workflows.
|
|
40
|
+
- Heph calls AI for provider/model runtime.
|
|
41
|
+
- Heph calls Interfaces for terminal and TUI presentation.
|
|
42
|
+
- Heph calls Extensions for stable extension contracts.
|
|
43
|
+
- Heph exposes SDK wrappers for non-terminal clients; those wrappers must stay
|
|
44
|
+
UI-neutral and must not import `interfaces.*`.
|
|
45
|
+
|
|
46
|
+
Reusable validation behavior should move to Hephaion. Provider/API behavior
|
|
47
|
+
should move to AI. Conversational strategy, research orchestration, and
|
|
48
|
+
Heph-facing identity should stay here or move here as the migration continues.
|
|
49
|
+
|
|
50
|
+
## Development
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
uv run pytest --no-cov packages/heph/test
|
|
54
|
+
uv run heph --help
|
|
55
|
+
uv run python -m scripts.check_repo_policies
|
|
56
|
+
uv run lint-imports
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Related Docs
|
|
60
|
+
|
|
61
|
+
- [Root architecture guide](../../docs/architecture.md)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "heph"
|
|
3
|
+
version = "0.0.49"
|
|
4
|
+
description = "Local-first document workspace for grounded answers, citations, memory, and recall practice with any LLM"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
authors = [
|
|
8
|
+
{ name = "Gil", email = "hi@gildrb.com" },
|
|
9
|
+
]
|
|
10
|
+
requires-python = ">=3.13"
|
|
11
|
+
keywords = [
|
|
12
|
+
"cli",
|
|
13
|
+
"documents",
|
|
14
|
+
"llm",
|
|
15
|
+
"rag",
|
|
16
|
+
"retrieval",
|
|
17
|
+
"learning",
|
|
18
|
+
]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 3 - Alpha",
|
|
21
|
+
"Environment :: Console",
|
|
22
|
+
"Operating System :: OS Independent",
|
|
23
|
+
"Programming Language :: Python",
|
|
24
|
+
"Programming Language :: Python :: 3",
|
|
25
|
+
"Programming Language :: Python :: 3.13",
|
|
26
|
+
"Topic :: Utilities",
|
|
27
|
+
"Typing :: Typed",
|
|
28
|
+
]
|
|
29
|
+
dependencies = [
|
|
30
|
+
"certifi==2026.2.25",
|
|
31
|
+
"keyring==25.7.0",
|
|
32
|
+
"openai==2.24.0",
|
|
33
|
+
"docling==2.94.0",
|
|
34
|
+
"gymnasium==0.29.1",
|
|
35
|
+
"numpy==1.26.4",
|
|
36
|
+
"pufferlib==3.0.0",
|
|
37
|
+
"torch==2.11.0",
|
|
38
|
+
"unicodeit==0.7.5",
|
|
39
|
+
"rich==14.3.3",
|
|
40
|
+
"textual==8.2.4",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
[project.urls]
|
|
44
|
+
Homepage = "https://github.com/gildrb/heph"
|
|
45
|
+
Repository = "https://github.com/gildrb/heph"
|
|
46
|
+
Issues = "https://github.com/gildrb/heph/issues"
|
|
47
|
+
|
|
48
|
+
[project.scripts]
|
|
49
|
+
heph = "heph.cli.main:main"
|
|
50
|
+
hephaion = "heph.cli.main:main"
|
|
51
|
+
|
|
52
|
+
[build-system]
|
|
53
|
+
requires = ["setuptools==81.0.0"]
|
|
54
|
+
build-backend = "setuptools.build_meta"
|
|
55
|
+
|
|
56
|
+
[tool.setuptools]
|
|
57
|
+
package-dir = {"" = "src"}
|
|
58
|
+
include-package-data = true
|
|
59
|
+
|
|
60
|
+
[tool.setuptools.packages.find]
|
|
61
|
+
where = ["src"]
|
|
62
|
+
include = ["ai*", "extensions*", "heph*", "hephaion*", "interfaces*"]
|
|
63
|
+
|
|
64
|
+
[tool.setuptools.package-data]
|
|
65
|
+
"*" = ["*.md", "*.toml", "py.typed"]
|
heph-0.0.49/setup.cfg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Self
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class NoopSpan:
|
|
7
|
+
__slots__ = ()
|
|
8
|
+
|
|
9
|
+
def set_attribute(self, key: str, value: object) -> object:
|
|
10
|
+
del key, value
|
|
11
|
+
return self
|
|
12
|
+
|
|
13
|
+
def end(self, end_time: float | None = None) -> None:
|
|
14
|
+
del end_time
|
|
15
|
+
|
|
16
|
+
def __enter__(self) -> Self:
|
|
17
|
+
return self
|
|
18
|
+
|
|
19
|
+
def __exit__(self, *args: object) -> None:
|
|
20
|
+
self.end()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class NoopTracer:
|
|
24
|
+
__slots__ = ()
|
|
25
|
+
|
|
26
|
+
def start_span(self, name: str, **kwargs: object) -> NoopSpan:
|
|
27
|
+
del name, kwargs
|
|
28
|
+
return NoopSpan()
|
|
29
|
+
|
|
30
|
+
def start_as_current_span(self, name: str, **kwargs: object) -> NoopSpan:
|
|
31
|
+
del name, kwargs
|
|
32
|
+
return NoopSpan()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class NoopInstrument:
|
|
36
|
+
__slots__ = ()
|
|
37
|
+
|
|
38
|
+
def record(self, value: float, _attributes: dict[str, str] | None = None) -> None:
|
|
39
|
+
del value, _attributes
|
|
40
|
+
|
|
41
|
+
def add(self, value: float, _attributes: dict[str, str] | None = None) -> None:
|
|
42
|
+
del value, _attributes
|
|
43
|
+
|
|
44
|
+
def set(self, value: float, _attributes: dict[str, str] | None = None) -> None:
|
|
45
|
+
del value, _attributes
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class NoopMeter:
|
|
49
|
+
__slots__ = ()
|
|
50
|
+
|
|
51
|
+
def create_histogram(self, name: str, **kwargs: object) -> NoopInstrument:
|
|
52
|
+
del name, kwargs
|
|
53
|
+
return NoopInstrument()
|
|
54
|
+
|
|
55
|
+
def create_counter(self, name: str, **kwargs: object) -> NoopInstrument:
|
|
56
|
+
del name, kwargs
|
|
57
|
+
return NoopInstrument()
|
|
58
|
+
|
|
59
|
+
create_up_down_counter = create_counter
|
|
60
|
+
|
|
61
|
+
def create_gauge(self, name: str, **kwargs: object) -> NoopInstrument:
|
|
62
|
+
del name, kwargs
|
|
63
|
+
return NoopInstrument()
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
_NOOP_TRACER = NoopTracer()
|
|
67
|
+
_NOOP_METER = NoopMeter()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def get_tracer(name: str) -> NoopTracer:
|
|
71
|
+
del name
|
|
72
|
+
return _NOOP_TRACER
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def get_meter(name: str) -> NoopMeter:
|
|
76
|
+
del name
|
|
77
|
+
return _NOOP_METER
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"""Structured logging, redaction, and timers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import logging
|
|
7
|
+
import os
|
|
8
|
+
import re as _re
|
|
9
|
+
import sys
|
|
10
|
+
import time
|
|
11
|
+
from collections.abc import Mapping
|
|
12
|
+
from datetime import UTC, datetime
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import ClassVar, Self
|
|
15
|
+
|
|
16
|
+
from ai.types import is_object_list, is_string_mapping
|
|
17
|
+
|
|
18
|
+
_LOG_TEXT_MUTED = "#6F6F6F"
|
|
19
|
+
_LOG_ACCENT = "#D06A4A"
|
|
20
|
+
_LOG_ERROR = "#FF6B5A"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _ansi_fg(hex_color: str) -> str:
|
|
24
|
+
color = hex_color.lstrip("#")
|
|
25
|
+
red = int(color[0:2], 16)
|
|
26
|
+
green = int(color[2:4], 16)
|
|
27
|
+
blue = int(color[4:6], 16)
|
|
28
|
+
return f"\033[38;2;{red};{green};{blue}m"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# -- Redaction / scrubbing ---------------------------------------------------
|
|
32
|
+
|
|
33
|
+
# Patterns for dict keys whose values should always be redacted
|
|
34
|
+
_SENSITIVE_KEY_PATTERNS: list[_re.Pattern[str]] = [
|
|
35
|
+
_re.compile(r"(?i)(api.?key|secret|token(?!s)|password|auth(orization|entication))"),
|
|
36
|
+
_re.compile(r"(?i)(bearer|credential|private.?key)"),
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
# Unanchored versions — find secrets embedded within longer text
|
|
40
|
+
_SENSITIVE_TEXT_PATTERNS: list[_re.Pattern[str]] = [
|
|
41
|
+
_re.compile(r"sk-or-v1-[a-zA-Z0-9\-_]{20,}"), # OpenRouter API keys
|
|
42
|
+
_re.compile(r"sk-proj-[a-zA-Z0-9\-_]{20,}"), # OpenAI project API keys
|
|
43
|
+
_re.compile(r"sk-[a-zA-Z0-9]{20,}"), # OpenAI-style API keys
|
|
44
|
+
_re.compile(r"sk-ant-[a-zA-Z0-9\-]{20,}"), # Provider API keys
|
|
45
|
+
_re.compile(r"\b(?:AKIA|ASIA)[0-9A-Z]{16}\b"), # AWS access keys
|
|
46
|
+
_re.compile(r"AIza[0-9A-Za-z\-_]{35}"), # Google API keys
|
|
47
|
+
_re.compile(r"ya29\.[0-9A-Za-z\-_]+"), # Google OAuth tokens
|
|
48
|
+
_re.compile(r"Bearer\s+\S+", _re.IGNORECASE), # Bearer tokens
|
|
49
|
+
_re.compile(r"\b[a-f0-9]{32,}\b"), # Long hex strings (potential tokens)
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
_REDACTED = "***REDACTED***"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def redact_text(text: str) -> str:
|
|
56
|
+
if not text:
|
|
57
|
+
return text
|
|
58
|
+
for pattern in _SENSITIVE_TEXT_PATTERNS:
|
|
59
|
+
text = pattern.sub(_REDACTED, text)
|
|
60
|
+
return text
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _redact_dict(data: Mapping[str, object]) -> dict[str, object]:
|
|
64
|
+
return {key: _redact_value(key, value) for key, value in data.items()}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def redact_mapping(data: Mapping[str, object]) -> dict[str, object]:
|
|
68
|
+
return _redact_dict(data)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _redact_value(key: str, value: object) -> object:
|
|
72
|
+
if any(pattern.search(key) for pattern in _SENSITIVE_KEY_PATTERNS):
|
|
73
|
+
return _REDACTED
|
|
74
|
+
return _redact_unkeyed_value(value)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _redact_unkeyed_value(value: object) -> object:
|
|
78
|
+
if is_string_mapping(value):
|
|
79
|
+
return _redact_dict(value)
|
|
80
|
+
if is_object_list(value):
|
|
81
|
+
return [_redact_unkeyed_value(item) for item in value]
|
|
82
|
+
if isinstance(value, str):
|
|
83
|
+
return redact_text(value)
|
|
84
|
+
return value
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class _JsonFormatter(logging.Formatter):
|
|
88
|
+
def format(self, record: logging.LogRecord) -> str:
|
|
89
|
+
entry: dict[str, object] = {
|
|
90
|
+
"ts": datetime.fromtimestamp(record.created, tz=UTC).isoformat(),
|
|
91
|
+
"level": record.levelname,
|
|
92
|
+
"logger": record.name,
|
|
93
|
+
"msg": record.getMessage(),
|
|
94
|
+
}
|
|
95
|
+
fields = getattr(record, "fields", None)
|
|
96
|
+
if is_string_mapping(fields):
|
|
97
|
+
entry.update(fields)
|
|
98
|
+
if record.exc_info and record.exc_info[1] is not None:
|
|
99
|
+
entry["exc"] = self.formatException(record.exc_info)
|
|
100
|
+
return json.dumps(_redact_dict(entry), default=str, ensure_ascii=False)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class _TextFormatter(logging.Formatter):
|
|
104
|
+
_LEVEL_COLOURS: ClassVar[dict[str, str]] = {
|
|
105
|
+
"DEBUG": _ansi_fg(_LOG_TEXT_MUTED),
|
|
106
|
+
"INFO": _ansi_fg(_LOG_ACCENT),
|
|
107
|
+
"WARNING": _ansi_fg(_LOG_ACCENT),
|
|
108
|
+
"ERROR": _ansi_fg(_LOG_ERROR),
|
|
109
|
+
"CRITICAL": f"\033[1m{_ansi_fg(_LOG_ERROR)}",
|
|
110
|
+
}
|
|
111
|
+
_RESET = "\033[0m"
|
|
112
|
+
_DIM = f"\033[2m{_ansi_fg(_LOG_TEXT_MUTED)}"
|
|
113
|
+
|
|
114
|
+
def format(self, record: logging.LogRecord) -> str:
|
|
115
|
+
ts = datetime.fromtimestamp(record.created, tz=UTC).strftime("%H:%M:%S")
|
|
116
|
+
colour = self._LEVEL_COLOURS.get(record.levelname, "")
|
|
117
|
+
level = f"{colour}{record.levelname:<8}{self._RESET}"
|
|
118
|
+
parts = [f"{self._DIM}{ts}{self._RESET} {level} {record.name}: {record.getMessage()}"]
|
|
119
|
+
parts.extend(self._field_lines(record))
|
|
120
|
+
parts.extend(self._exception_lines(record))
|
|
121
|
+
return "\n".join(parts)
|
|
122
|
+
|
|
123
|
+
def _field_lines(self, record: logging.LogRecord) -> list[str]:
|
|
124
|
+
fields = getattr(record, "fields", None)
|
|
125
|
+
if not is_string_mapping(fields):
|
|
126
|
+
return []
|
|
127
|
+
return [
|
|
128
|
+
f" {self._DIM}{key}={value}{self._RESET}"
|
|
129
|
+
for key, value in _redact_dict(fields).items()
|
|
130
|
+
]
|
|
131
|
+
|
|
132
|
+
def _exception_lines(self, record: logging.LogRecord) -> list[str]:
|
|
133
|
+
if record.exc_info and record.exc_info[1] is not None:
|
|
134
|
+
return [self.formatException(record.exc_info)]
|
|
135
|
+
return []
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
LOG_LEVEL_ENV = "HEPHAION_LOG_LEVEL"
|
|
139
|
+
LOG_FILE_ENV = "HEPHAION_LOG_FILE"
|
|
140
|
+
LOG_FORMAT_ENV = "HEPHAION_LOG_FORMAT"
|
|
141
|
+
|
|
142
|
+
_hephaion_logger_initialised = False
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def get_logger(name: str) -> logging.Logger:
|
|
146
|
+
_ensure_hephaion_logger()
|
|
147
|
+
if not name.startswith("hephaion"):
|
|
148
|
+
name = f"hephaion.{name}"
|
|
149
|
+
return logging.getLogger(name)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _ensure_hephaion_logger() -> None:
|
|
153
|
+
global _hephaion_logger_initialised # noqa: PLW0603
|
|
154
|
+
if _hephaion_logger_initialised:
|
|
155
|
+
return
|
|
156
|
+
_hephaion_logger_initialised = True
|
|
157
|
+
|
|
158
|
+
level, fmt = _logging_config()
|
|
159
|
+
logger = logging.getLogger("hephaion")
|
|
160
|
+
logger.setLevel(level)
|
|
161
|
+
logger.propagate = False
|
|
162
|
+
if not logger.handlers:
|
|
163
|
+
logger.addHandler(_stderr_handler(level, fmt))
|
|
164
|
+
if log_file := os.environ.get(LOG_FILE_ENV):
|
|
165
|
+
logger.addHandler(_file_handler(Path(log_file), level))
|
|
166
|
+
_quiet_noisy_loggers()
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _logging_config() -> tuple[int, str]:
|
|
170
|
+
is_tty = sys.stderr.isatty()
|
|
171
|
+
default_level_name = "ERROR" if is_tty else "WARNING"
|
|
172
|
+
default_format = "text" if is_tty else "json"
|
|
173
|
+
level_name = os.environ.get(LOG_LEVEL_ENV, default_level_name).upper()
|
|
174
|
+
return getattr(logging, level_name, logging.WARNING), os.environ.get(
|
|
175
|
+
LOG_FORMAT_ENV,
|
|
176
|
+
default_format,
|
|
177
|
+
).lower()
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _stderr_handler(level: int, fmt: str) -> logging.Handler:
|
|
181
|
+
handler = logging.StreamHandler(sys.stderr)
|
|
182
|
+
handler.setLevel(level)
|
|
183
|
+
handler.setFormatter(_JsonFormatter() if fmt == "json" else _TextFormatter())
|
|
184
|
+
return handler
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _file_handler(path: Path, level: int) -> logging.Handler:
|
|
188
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
189
|
+
handler = logging.FileHandler(path, encoding="utf-8")
|
|
190
|
+
handler.setLevel(level)
|
|
191
|
+
handler.setFormatter(_JsonFormatter())
|
|
192
|
+
return handler
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _quiet_noisy_loggers() -> None:
|
|
196
|
+
for noisy in ("openai", "httpx", "httpcore", "urllib3", "sentence_transformers"):
|
|
197
|
+
logging.getLogger(noisy).setLevel(logging.WARNING)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class Timer:
|
|
201
|
+
__slots__ = ("_end", "_start")
|
|
202
|
+
|
|
203
|
+
def __init__(self) -> None:
|
|
204
|
+
self._start: float = 0.0
|
|
205
|
+
self._end: float = 0.0
|
|
206
|
+
|
|
207
|
+
def __enter__(self) -> Self:
|
|
208
|
+
self._start = time.perf_counter()
|
|
209
|
+
return self
|
|
210
|
+
|
|
211
|
+
def __exit__(self, *args: object) -> None:
|
|
212
|
+
self._end = time.perf_counter()
|
|
213
|
+
|
|
214
|
+
@property
|
|
215
|
+
def ms(self) -> float:
|
|
216
|
+
return (self._end - self._start) * 1000
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Multi-provider LLM configuration."""
|
|
2
|
+
|
|
3
|
+
from ai.providers.catalog import (
|
|
4
|
+
LiveProviderCatalog,
|
|
5
|
+
hydrate_provider_models,
|
|
6
|
+
prefetch_provider_model_catalogs,
|
|
7
|
+
)
|
|
8
|
+
from ai.providers.config import Provider, ProviderConfig, default_config, providers_dir
|
|
9
|
+
from ai.providers.keyring_store import mask_key, resolve_key
|
|
10
|
+
from ai.providers.registry import ModelInfo, get_registry
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"LiveProviderCatalog",
|
|
14
|
+
"ModelInfo",
|
|
15
|
+
"Provider",
|
|
16
|
+
"ProviderConfig",
|
|
17
|
+
"default_config",
|
|
18
|
+
"get_registry",
|
|
19
|
+
"hydrate_provider_models",
|
|
20
|
+
"mask_key",
|
|
21
|
+
"prefetch_provider_model_catalogs",
|
|
22
|
+
"providers_dir",
|
|
23
|
+
"resolve_key",
|
|
24
|
+
]
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Provider access decisions independent of UI adapters."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ai.providers.catalog import hydrate_provider_models
|
|
6
|
+
from ai.providers.config import Provider, ProviderConfig
|
|
7
|
+
from ai.providers.endpoints import provider_uses_keyless_access
|
|
8
|
+
from ai.providers.keyring_store import resolve_key
|
|
9
|
+
from ai.providers.oauth import resolve_oauth_key
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def provider_is_accessible(provider: Provider, *, refresh_oauth: bool = True) -> bool:
|
|
13
|
+
if provider.slug == "openai-codex":
|
|
14
|
+
return bool(resolve_oauth_key(provider.slug, refresh_expired=refresh_oauth))
|
|
15
|
+
if provider_uses_keyless_access(provider.slug, provider.endpoint):
|
|
16
|
+
return True
|
|
17
|
+
return bool(
|
|
18
|
+
resolve_key(
|
|
19
|
+
provider.slug,
|
|
20
|
+
provider.api_key_env,
|
|
21
|
+
refresh_oauth=refresh_oauth,
|
|
22
|
+
)
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def activate_provider_config(pc: ProviderConfig, slug: str) -> Provider:
|
|
27
|
+
pc.set_active(slug)
|
|
28
|
+
hydrate_provider_models(pc, provider_slugs={slug})
|
|
29
|
+
provider = pc.providers[slug]
|
|
30
|
+
if not provider.current_model and provider.models:
|
|
31
|
+
provider.current_model = provider.models[0]
|
|
32
|
+
return provider
|