Refactor Chat to ACP-Native Subpackage with Deep Agents Provider#10
Open
deeleeramone wants to merge 17 commits intomainfrom
Open
Refactor Chat to ACP-Native Subpackage with Deep Agents Provider#10deeleeramone wants to merge 17 commits intomainfrom
deeleeramone wants to merge 17 commits intomainfrom
Conversation
…SQLite state backend Restructures the chat system from 3 monolithic files into a `pywry/chat/` subpackage implementing the Agent Client Protocol (ACP). All provider adapters now conform to ACP's session lifecycle (initialize → new_session → prompt → cancel) and yield typed SessionUpdate notifications. Chat subpackage: - models.py: ACP content blocks, ACPToolCall, ChatMessage, ChatThread - session.py: SessionMode, SessionConfigOption, PlanEntry, PermissionRequest, Capabilities - updates.py: SessionUpdate discriminated union (11 types) - artifacts.py: 8 artifact types including TradingViewArtifact - manager.py: ChatManager accepting providers or legacy handlers - providers/: OpenAI, Anthropic, Magentic, Callback, Stdio, DeepAgent - permissions.py: RBAC permission mappings for ACP operations - html.py: build_chat_html() DeepAgent provider: - Wraps LangChain Deep Agents CompiledGraph - Maps LangGraph astream_events to ACP SessionUpdate types - Auto-configures checkpointer and memory store from PyWry state backend - Built-in system prompt onboarding the agent to the chat UI - Tool kind mapping for Deep Agents built-in tools - write_todos → PlanUpdate translation SQLite state backend: - Complete implementation of all 5 state ABCs (Widget, Session, Chat, EventBus, ConnectionRouter) - Encrypted at rest via SQLCipher with keyring-based key management - Full audit trail: tool calls, artifacts, token usage, resources, skills - Auto-created admin session with seeded role permissions - Same schema as Redis — fully interchangeable JS extraction: - 8 JS files extracted from scripts.py to frontend/src/ - WS bridge extracted from inline.py to frontend/src/ws-bridge.js - scripts.py rewritten to load from files Frontend: - TradingView artifact renderer in chat-handlers.js - ACP event handlers: permission-request, plan-update, mode-update, config-update, commands-update - PyWryChatWidget expanded with chat ESM and trait-based asset loading Documentation: - Rewrote chat guide and providers page with full ACP coverage - Created PyTauri, Anywidget, and IFrame+WebSocket transport protocol pages - Rewrote AG Grid and Plotly integration pages - Rewrote Why PyWry page reflecting current capabilities - Moved multi-widget to concepts, tauri-plugins under pytauri - Purged all print() statements from example code across all docs - Removed all section-banner comments and forbidden comment words Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Local settings file should not be in the repository. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- callback.py: remove redundant GenerationCancelledError import (used in _iter_result) - deepagent.py: add logger, log exceptions instead of bare pass, add on_chat_model_start and on_chain_start event handlers (StatusUpdate was unused) - base.py: add return statements to audit trail no-op methods (B027) - sqlite.py: restructure keyring try/except with else block (TRY300), log keyring fallback instead of bare pass (S110), add D102 per-file-ignore - test files: remove unused imports (F401), fix async sleep (ASYNC251), inline lambda (PLW0108), remove unused variable assignments (F841) - ruff.toml: add sqlite.py D102 ignore for ABC-documented methods Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- deepagent.py: fix E402 import order, extract _handle_tool_end to reduce prompt() complexity (C901/PLR0912) - ruff.toml: add S108 and PERF401 to test ignores - test_deepagent_provider.py: add test for on_chat_model_start → StatusUpdate (was imported but unused) - test_state_sqlite.py: remove unused time import Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- SqliteWidgetStore: implement all 10 abstract methods from WidgetStore ABC (register, get, get_html, get_token, exists, delete, list_active, update_html, update_token, count) - SqliteEventBus/SqliteConnectionRouter: alias to Memory implementations since SQLite is single-process (no custom pub/sub or routing needed) - DeepagentProvider: guard all langgraph imports with try/except so tests pass without langgraph installed, return None from _create_store and _create_checkpointer when unavailable - Tests: use correct ABC method names, skip langgraph-dependent test when not installed, remove cache_clear call on non-cached function, pass auto_store=False alongside auto_checkpointer=False in all tests Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- models.py: remove unused type:ignore comments - providers/__init__.py: annotate return from getattr to satisfy no-any-return - providers/stdio.py: annotate session_id as str - providers/deepagent.py: add type:ignore for optional dep imports, use alias names in ToolCallUpdate constructors for mypy pydantic plugin, type _map_todo_status return as Literal - state/sqlite.py: type:ignore pysqlcipher3 import, annotate conn and cost variables - state/_factory.py: use MemoryEventBus/MemoryConnectionRouter directly for SQLite backend (no db_path needed) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The previous type:ignore removal merged two statements onto one line, causing a SyntaxError that broke every test. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…it trail - chat-providers.md: add DeepagentProvider mkdocstrings entry - state.md: add ChatStore ABC, SqliteWidgetStore, SqliteSessionStore, SqliteChatStore mkdocstrings entries - reference/index.md: update state description to include SQLite - state-and-auth.md: add SQLite section with audit trail details, encryption, auto-admin setup, config table entry - deploy-mode.md: update backend value to include "sqlite" - configuration.md: document sqlite_path setting Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- manager.py: renamed _process_legacy_item to _process_handler_item, removed "legacy" from docstrings - test_chat_protocol.py: renamed TestLegacyHandlerWithNewUpdates - auth/deploy_routes.py: removed "legacy alias" comment - cli.py: removed "backwards compatibility" comment - inline.py, templates.py: removed "legacy template" from JS comments - tvchart/__init__.py: removed "backward compatibility" from docstring - tvchart/udf.py: removed "legacy" from docstring - mcp/skills/__init__.py: removed "backward compatibility" from docstring - test_mcp_unit.py: removed "legacy" from comment - test_plotly_theme_merge.py: renamed legacy -> single in test names, comments, and JS template strings - test_plotly_theme_merge_e2e.py: renamed storedLegacy -> storedSingle - test_tvchart.py: renamed test_symbol_info_legacy_alias, removed "backward compat" from docstrings Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Check for iterators (__next__) after coroutines and strings, not before. Using __iter__ matched strings; __next__ correctly identifies generators and iterators without matching strings. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Python 3.10's asyncio.iscoroutine() returns True for some generator objects. Use inspect.isgenerator() and inspect.isasyncgen() to detect generators first, then inspect.iscoroutine() for strict coroutine checking. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.
This PR restructures the chat system from 3 monolithic files into a
pywry/chat/subpackage implementing the Agent Client Protocol (ACP). All provider adapters now conform to ACP's session lifecycle (initialize → new_session → prompt → cancel) and yield typed SessionUpdate notifications.Chat subpackage:
DeepAgent provider:
SQLite state backend:
JS extraction:
Frontend:
Documentation: