release: v0.16.5 — design patterns, terminal actions, async observers#7
Merged
johnnichev merged 3 commits intomainfrom Mar 16, 2026
Merged
release: v0.16.5 — design patterns, terminal actions, async observers#7johnnichev merged 3 commits intomainfrom
johnnichev merged 3 commits intomainfrom
Conversation
Major structural refactoring to prevent the class of bugs found in v0.16.0-v0.16.4 and prepare a clean foundation for v0.17.0 multi-agent orchestration. Features: - Terminal action support: @tool(terminal=True) + stop_condition callback - AsyncAgentObserver: async lifecycle hooks with blocking/non-blocking modes - Gemini 3.x thought signature support (ToolCall.thought_signature) - StepType + ModelType converted to str Enums (backward compatible) - Namespace exports (from selectools.providers import OpenAIProvider) Refactoring: - Agent decomposed into 4 mixins (core.py 3128->1448 lines, -54%) - OpenAI/Ollama share _OpenAICompatibleBase (Template Method, -75% duplication) - Hooks deprecated via _HooksAdapter, single observer pipeline - Tool execution extracted into _execute_single_tool/_aexecute_single_tool - astream() non-streaming fallback delegates to _acall_provider() Quality: - 163 new tests (total: 1640), 53 architecture fitness tests - Shared test fixtures in conftest.py - 6 Architecture Decision Records in docs/decisions/ - Full documentation update across 15+ files
str(Enum) and format(Enum) behavior differs between Python versions: - 3.9-3.10: str() returns "StepType.LLM_CALL", format() returns "llm_call" - 3.11+: str() returns "llm_call", format() returns "StepType.LLM_CALL" Use .value consistently for string output in trace timeline and OTel spans. Fix test to assert on .value instead of str()/format().
- CI workflows: 3.11 -> 3.13 - mypy python_version: 3.9 -> 3.13 - CLAUDE.md: document Python 3.13+ target
johnnichev
added a commit
that referenced
this pull request
Mar 24, 2026
Security: - Path traversal in JsonFileSessionStore — validate session_id (#9) - Unicode homoglyph bypass in injection screening — NFKD + zero-width strip + homoglyph map (#13) Data integrity: - FileKnowledgeStore._save_all() atomic write via tmp + os.replace (#10) - JsonFileSessionStore.save() atomic write (#31) Agent core: - astream() uses self._effective_model (was self.config.model) (#1) - Sync _check_policy rejects async confirm_action with clear error (#2) - Sync _streaming_call isinstance(chunk, str) guard (#18) Providers: - FallbackProvider stream()/astream() record success after consumption, not before — circuit breaker now works for streaming (#3) - Gemini response.text ValueError catch for tool-call-only responses (#4) Tools: - aexecute() uses run_in_executor(None) shared executor (#5) - execute() awaits coroutines from async tools via asyncio.run (#6) RAG: - Hybrid search O(n²) → O(1) via text_to_key dict lookup (#7) - SQLiteVectorStore thread safety + WAL mode (#8) Evals: - OutputEvaluator catches re.error on invalid regex (#11) - JsonValidityEvaluator respects expect_json=False (#12) 16 new regression tests. Full suite: 2000 passed.
johnnichev
added a commit
that referenced
this pull request
Mar 29, 2026
Critical: - astream(): guard response_msg.content with `or ""` (pitfall #7) - FileCheckpointStore.save(): atomic write via temp file + os.replace() - llm_evaluators: fence all user-controlled content in judge prompts to prevent injection - evals/regression.py, snapshot.py: atomic baseline/snapshot writes; sanitise suite_name path - tools/base.py: shared module-level executor instead of per-call ThreadPoolExecutor - rag/stores/memory.py: threading.Lock() on InMemoryVectorStore add/search/delete/clear High: - fallback.py: threading.Lock() on circuit breaker _failures/_circuit_open_until dicts - memory.py: ConversationMemory.branch() deep-copies tool_calls to prevent shared mutation - evals/report.py: fix p95/p99 off-by-one (use math.ceil, not int) - tools/registry.py: warn on silent tool name collision instead of silently overwriting
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Major structural refactoring release — design patterns, code quality enforcement, and two community-requested features (FR-001 + FR-002).
New Features
@tool(terminal=True)+AgentConfig.stop_condition— stops the agent loop after specific tools fireAsyncAgentObserverwithblockingflag — async lifecycle hooks for DB writes, webhooksToolCall.thought_signaturefield for function call signature preservationstr, Enumfor type safety (backward compatible)from selectools.providers import OpenAIProvidernow worksRefactoring
core.py3128 → 1448 lines (-54%)_OpenAICompatibleBaseTemplate Method (-75% duplication)_HooksAdapter, single observer pipeline_execute_single_tool/_aexecute_single_toolreplace 540 lines of duplication_acall_provider()Quality
conftest.pydocs/decisions/Test plan
pytest tests/ -x -q— 1586 passed, 54 skippedblack --check— cleanflake8— cleanmypy— clean (mixin attr-defined suppressed via pyproject.toml)mkdocs build— clean🤖 Generated with Claude Code