All notable changes to this project will be documented in this file.
- Codex System Prompt Survives Compaction (
memory_mode="codex_thread"): The agent system prompt is now passed as thread-level instructions on everythread_startandthread_resume, instead of being text-injected into the first user turn. Codex keeps these in the compaction-preserved prefix (outside the compactable conversation body), so the persona no longer degrades as the thread grows, and it is re-applied on every turn (also covering thread recovery after a lost thread). - New
instructions_modeoption (client_config_override):"developer"(default) layers the system prompt on top of Codex's native coding-agent/tool harness;"base"replaces that harness for full persona control. Both were verified to keep runtime MCP tool calls working and to honor the persona;"developer"is the default as the non-destructive choice.
- SDKs that do not accept the instructions kwarg on
thread_start/thread_resumefall back to the previous first-turn text injection automatically (a warning is logged).
AgentConvenience Class: Newfrom agentify import Agentone-liner with batteries-included defaults. Onlymodelis required; an in-process store and a default conversation address are created automatically whenmemory/memory_addressare omitted, and extra keyword arguments are forwarded toAgentConfig. The explicitBaseAgent/AgentConfig/MemoryServiceAPI is unchanged.- Top-Level Exports:
AgentandInMemoryStoreare now exported fromagentify, so the common case no longer needs deep imports. - Richer Tool Schemas: The
@tooldecorator now emitsitemsfor typed lists (list[str]), andenumforLiteral[...]andEnumparameters, improving tool-calling accuracy.
- Concurrent Streaming Isolation: Streaming tool-call/reasoning state is no longer stored on the agent instance (
_last_stream_*); it flows through a per-call sink, so concurrent streamingarun()calls on a shared agent instance no longer clobber each other. The legacyself._last_stream_*attributes remain populated for direct callers.
- Logging Is No Longer Configured at Import Time:
agentify.memory.serviceattaches aNullHandleron import; the human-readable colored stream output is wired up lazily only when aMemoryServiceis created withlog_enabled=True, so importing Agentify no longer hijacks the host application's logging configuration.
- System Prompt Seeding for Codex Thread Memory: In
memory_mode="codex_thread", the agent's system prompt is now sent once on the first turn of each new Codex thread (prepend_system_prompt/extract_system_promptincodex_inputs.py), so the agent identity reaches Codex even though only the latest user message is sent per turn. Subsequent turns on the persistent thread do not re-send it. CodexThreadBackend.drop_session(session_id): Forget the Codex thread mapped to a session (and remove it from the persistedthread_map_path), so a memory reset starts a fresh thread instead of resuming the old one. The Codex thread itself remains on disk under~/.codex/.
- Concurrent Thread-Map Saves No Longer Clobber:
_save_thread_mapnow merges with the on-disk map before writing, so two backends sharing onethread_map_path(e.g. a CLI and a Telegram bridge) don't overwrite each other's session → thread mappings.
- Per-Session Runtime MCP Bridge: Tools, timeouts, and memory-bound executors are now registered on the runtime MCP bridge per session (
register_session), so concurrent turns for different Agentify sessions on the same Codex backend are fully isolated. The legacy single-session bridge API keeps working. - Durable Codex Thread Mapping: New
client_config_override={"thread_map_path": ...}persists the session → Codex thread ID mapping as a JSON file, somemory_mode="codex_thread"sessions survive process restarts (Codex threads themselves are persisted by the CLI under~/.codex/). - Codex Thread Recovery: If a mapped Codex thread no longer exists, Agentify logs a warning and transparently starts a new thread for that session; transient resume errors are still raised so context is never silently discarded.
- Native Thread Introspection:
CodexThreadBackend.get_thread_id(session_id)andawait CodexThreadBackend.read_session_history(session_id)expose the native Codex thread state (ThreadReadResponse). - Typed Codex Errors: New actionable exception hierarchy (
CodexAuthError,CodexCLINotFoundError,CodexModelNotSupportedError,CodexUsageLimitError,CodexMCPStartupError,CodexToolNotFoundError,CodexEmptyTurnError,CodexStreamTimeoutError), all carrying retry metadata honored byBaseAgent. - MCP Startup Diagnostics: When a Codex turn completes without reconstructible text, the error now reports whether the runtime MCP bridge ever received a connection and (best effort) which MCP servers/tools Codex can see via
mcpServerStatus/list. - Real-Codex Test Suite & Benchmark: Env-gated E2E tests against real ChatGPT OAuth (
AGENTIFY_CODEX_E2E=1, plusAGENTIFY_CODEX_E2E_SLOW=1for a >30s tool regression test) andscripts/benchmark_codex_memory_modes.pyto compare memory modes.
- Codex Memory Mode Guidance: Documentation now explains how Codex thread memory works (storage under
~/.codex/, persistence, auto-compaction) and recommendsmemory_mode="codex_thread"for interactive assistants (~1.5–1.7x faster per turn in benchmarks; the gap grows with history length). - Agentify Memory Preamble: Hardened the prompt preamble used by
memory_mode="agentify"so the model no longer leaks the memory instructions into its replies. - Stable Session Keys: Native backends now receive
MemoryAddress.key_str()as the session key instead of an unstable fallback.
- Transient Codex Errors No Longer Abort Turns: Codex
errorevents are parsed from their real payload (ErrorNotification.error/willRetry); errors Codex retries internally are recorded as warnings instead of failing turns that complete successfully. - Slow Tools Over MCP: The runtime MCP proxy socket timeout is now derived from
tool_timeout(--call-timeout), so tools slower than 30 seconds return their structured result instead of killing the proxy connection. Validated against real Codex with a 35s tool. - MCP Tool Config Never Silently Dropped: The
thread_startcompatibility fallback no longer discards MCP tool configuration on older SDKs; it raises an actionable upgrade error instead. - Error Classification:
codex_error_inforoot models are unwrapped;unauthorized(OAuth missing/expired → runcodex login) andcontextWindowExceededare now classified; a missingcodexbinary raises an installation hint instead of a rawFileNotFoundError.
- Codex Provider Parity:
provider="codex"now behaves much closer to standard Agentify providers while using native Codex threads internally. - Agentify-managed Codex Memory: Codex uses Agentify memory stores (
SQLite, in-memory, Redis, Elasticsearch) as the source of truth by default withmemory_mode="agentify". Native Codex thread memory remains available viamemory_mode="codex_thread". - Runtime MCP Tool Adapter: Normal
BaseAgent(tools=[...])tools are automatically exposed to Codex through a runtime MCP bridge. Users no longer need to manually wrap tools for common Codex usage. - Persisted MCP Tool History: Codex MCP tool calls are logged and stored in Agentify memory as assistant tool intents plus
toolresult messages withmetadata.source="codex_mcp". - Codex Multimodal Input:
image_path=...is converted to Codex SDK image input when supported, while preserving the Agentify multimodal memory message. - Codex Structured Output: Added support for Codex
output_schemathroughmodel_kwargs={"output_schema": ...}and OpenAI-styleresponse_format={"type": "json_schema", ...}. - Codex Streaming Events:
stream=Truenow emits text chunks reconstructed from Codexthread.turn(...).stream()events. - Codex Tool Iteration Limits: Runtime MCP tool calls now respect
AgentConfig.max_tool_iterinside a Codex turn. - Provider Lifecycle Cleanup: Added
BaseAgent.close(),BaseAgent.aclose(), andCodexThreadBackend.close()to release provider resources such as runtime MCP bridges. - Codex Diagnostics Script: Added
scripts/manual_codex_feature_diagnostics.pyfor manual validation of structured output, image input, streaming, and MCP tool limits. - Typed Package Marker: Added
agentify/py.typedto match package-data configuration.
- Codex Tool Architecture: Moved provider-specific Codex MCP adaptation out of
BaseAgentintoagentify.llm.tool_adapters. - Codex Backend Structure: Split Codex input building and retry-aware error classification into dedicated modules (
codex_inputs.py,codex_errors.py) for maintainability. - Package Extras:
agentify-core[all]now includes the optional Codex dependency. - Project Metadata: Updated package license metadata to modern SPDX-style
license = "MIT". - Documentation: README, PyPI README, API reference, and core concepts now document native Codex usage, login, runtime MCP tools, structured output, multimodal input, streaming, and lifecycle cleanup.
- Codex Retry Behavior: Non-retryable Codex errors such as usage limits, unsupported models, MCP startup failures, and unknown MCP tools now stop retries immediately.
- Codex Tool Observability: MCP tool usage is now visible in callbacks/logs and persisted memory history.
- Codex Packaging Hygiene: Removed reliance on private Codex SDK input imports and verified package build contents.
- Tool Hooks System: New
tool_pre_hooksandtool_post_hooksinBaseAgentfor executing custom logic before and after tool execution. - SpawnAgentTool Enhancements: Support for passing
tools,pre_hooks,post_hooks,tool_pre_hooks, andtool_post_hooksto spawned sub-agents. - MCP Tool Name Validation: New
_safe_function_name()function to safely convert MCP tool names into valid Python identifiers. - Experimental Codex Native Provider with MCP-backed Tools: Agentify now supports Codex as a native experimental provider using ChatGPT OAuth and Codex threads. Unlike OpenAI providers, Codex does not use
tool_calls; Agentify exposes tools through an MCP stdio server and reconstructs Codex responses from thread event streams.
- MCP Adapter:
convert_mcp_tools_to_agentify()is now synchronous (no longer async) with improved error handling and null-coalescing forinputSchema. - Shell Safe Tool: Removed restrictive allowlist; now accepts any shell command with configurable timeout (increased from 60s to 1800s max).
- System Message Integrity: Enhanced
_aensure_system_initialized()to verify system message position and eliminate duplicates in conversation history. - Type Hints Modernization: Updated type aliases to use modern
TypeAliassyntax and PEP 604 union operator (|) instead ofUnion. - LLM Client Factory: Added support for new provider "llama" alongside existing providers.
- Event Loop Detection: Simplified
has_running_loop()to useasyncio.get_running_loop(), eliminating DeprecationWarning on Python 3.10+. - MCP Tests: Fixed async/await mismatch in test cases for
convert_mcp_tools_to_agentify(). - Tool Execution Rollback: New
_arollback_last_tool_turn()method to recover from interrupted tool execution sequences.
- Local Provider Support: Official support for local LLM servers (LM Studio, Ollama, etc.) via the
"local"provider.- Automatically configured for LM Studio's default port (
http://localhost:1234/v1). - Supports custom tools, streaming, and vision on local models.
- New configuration environment variables:
LOCAL_API_BASEandLOCAL_API_KEY.
- Automatically configured for LM Studio's default port (
- Dual execution bridge via
run()(sync) andarun()(async) across agents and multi-agent runtimes. agentify/core/sync_bridge.pywith loop-safety checks, sync coroutine execution, and async-to-sync streaming bridge.- Delegation recovery controls in
AgentConfig:delegation_recovery_enableddelegation_recovery_modedelegation_max_retriesdelegation_retry_backoff_ms
tool_timeoutinAgentConfigto control tool execution timeout independently from model timeout.agentify/core/multimodal.pyto centralize image encoding and multimodal content building.
- Lazy Client Loading: Improved performance by making the synchronous client instantiation lazy in
BaseAgent. The client is only created when first accessed, reducing overhead for async-first workflows. - Refactored
BaseAgentto usearun()as the execution source of truth;run()now bridges to async runtime. - Increased default
timeoutfrom60to300seconds for long-running reasoning scenarios. - Set default
tool_timeoutto300seconds. - Improved delegated tool-call recovery for consistency errors to reduce user-facing failures in concurrent multi-agent flows.
- Reduced verbosity/noise for recoverable consistency errors in callback logging.
- Updated docs and examples to consistently document dual API usage (
run()/arun()).
- Removed legacy internal sync execution paths in
BaseAgentthat were no longer part of the active runtime.