agentirc-cli 4.3.6__tar.gz → 4.3.7__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.
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/CHANGELOG.md +12 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/PKG-INFO +1 -1
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/bots/bot_manager.py +7 -3
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/bots/config.py +1 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/cli/agent.py +1 -1
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/cli/channel.py +1 -1
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/cli/mesh.py +1 -2
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/cli/shared/constants.py +2 -1
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/cli/shared/ipc.py +3 -3
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/acp/agent_runner.py +8 -4
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/acp/daemon.py +20 -14
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/acp/irc_transport.py +5 -5
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/acp/skill/irc_client.py +2 -2
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/acp/socket_server.py +4 -4
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/claude/agent_runner.py +2 -1
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/claude/daemon.py +20 -14
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/claude/irc_transport.py +5 -5
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/claude/skill/irc_client.py +2 -2
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/claude/socket_server.py +4 -4
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/codex/agent_runner.py +8 -4
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/codex/daemon.py +20 -14
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/codex/irc_transport.py +5 -5
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/codex/skill/irc_client.py +2 -2
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/codex/socket_server.py +4 -4
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/copilot/daemon.py +20 -14
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/copilot/irc_transport.py +5 -5
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/copilot/skill/irc_client.py +2 -2
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/copilot/socket_server.py +4 -4
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/console/client.py +1 -1
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/observer.py +3 -3
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/overview/collector.py +18 -18
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/overview/web/style.css +1 -1
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/pidfile.py +1 -1
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/server/client.py +1 -1
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/server/ircd.py +2 -2
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/server/server_link.py +6 -6
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/server/skill.py +3 -3
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/packages/agent-harness/daemon.py +11 -10
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/packages/agent-harness/irc_transport.py +5 -5
- agentirc_cli-4.3.7/packages/agent-harness/message_buffer.py +63 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/packages/agent-harness/skill/irc_client.py +2 -2
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/packages/agent-harness/socket_server.py +4 -4
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/pyproject.toml +1 -1
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/conftest.py +8 -5
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_acp_daemon.py +0 -6
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_agent_runner.py +2 -1
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_console_commands.py +0 -2
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_console_connection.py +0 -4
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_console_icons.py +1 -2
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_federation.py +40 -34
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_link_reconnect.py +16 -15
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_mentions.py +3 -7
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_rooms.py +5 -5
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_supervisor.py +2 -1
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_webhook.py +1 -1
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/uv.lock +1 -1
- agentirc_cli-4.3.6/packages/agent-harness/message_buffer.py +0 -65
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/.claude/skills/pr-review/SKILL.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/.claude/skills/run-tests/SKILL.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/.claude/skills/run-tests/scripts/test.sh +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/.flake8 +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/.github/workflows/pages.yml +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/.github/workflows/publish.yml +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/.github/workflows/security-checks.yml +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/.github/workflows/tests.yml +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/.gitignore +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/.markdownlint-cli2.yaml +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/.pr_agent.toml +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/.pre-commit-config.yaml +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/.pylintrc +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/CLAUDE.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/CNAME +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/Gemfile +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/Gemfile.lock +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/LICENSE +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/README.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/SECURITY.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/_config.yml +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/_sass/color_schemes/anthropic.scss +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/_sass/custom/custom.scss +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/__init__.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/__main__.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/aio.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/bots/__init__.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/bots/bot.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/bots/http_listener.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/bots/template_engine.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/bots/virtual_client.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/cli/__init__.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/cli/bot.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/cli/server.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/cli/shared/__init__.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/cli/shared/display.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/cli/shared/formatting.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/cli/shared/mesh.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/cli/shared/process.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/cli/skills.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/__init__.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/acp/__init__.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/acp/config.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/acp/ipc.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/acp/message_buffer.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/acp/skill/SKILL.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/acp/skill/__init__.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/acp/supervisor.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/acp/webhook.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/claude/__init__.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/claude/__main__.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/claude/config.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/claude/ipc.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/claude/message_buffer.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/claude/skill/SKILL.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/claude/skill/__init__.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/claude/supervisor.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/claude/webhook.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/codex/__init__.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/codex/config.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/codex/ipc.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/codex/message_buffer.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/codex/skill/SKILL.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/codex/skill/__init__.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/codex/supervisor.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/codex/webhook.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/copilot/__init__.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/copilot/agent_runner.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/copilot/config.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/copilot/ipc.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/copilot/message_buffer.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/copilot/skill/SKILL.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/copilot/skill/__init__.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/copilot/supervisor.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/clients/copilot/webhook.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/console/__init__.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/console/app.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/console/commands.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/console/widgets/__init__.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/console/widgets/chat.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/console/widgets/info_panel.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/console/widgets/sidebar.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/credentials.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/formatting.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/learn_prompt.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/mesh_config.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/overview/__init__.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/overview/model.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/overview/renderer_text.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/overview/renderer_web.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/persistence.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/protocol/__init__.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/protocol/commands.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/protocol/extensions/federation.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/protocol/extensions/history.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/protocol/extensions/icons.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/protocol/extensions/rooms.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/protocol/extensions/tags.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/protocol/extensions/threads.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/protocol/message.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/protocol/protocol-index.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/protocol/replies.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/server/__init__.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/server/__main__.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/server/channel.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/server/config.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/server/remote_client.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/server/room_store.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/server/rooms_util.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/server/skills/__init__.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/server/skills/history.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/server/skills/icon.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/server/skills/rooms.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/server/skills/threads.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/server/thread_store.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/culture/skills/culture/SKILL.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/agent-lifecycle.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/agentic-self-learn.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/architecture/agent-client.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/architecture/agent-harness-spec.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/architecture/design.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/architecture/harness-conformance.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/architecture/index.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/architecture/layer1-core-irc.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/architecture/layer2-attention.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/architecture/layer3-skills.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/architecture/layer4-federation.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/architecture/layer5-agent-harness.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/architecture/server-architecture.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/architecture/threads.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/channel-polling.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/clients/acp/overview.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/clients/claude/configuration.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/clients/claude/context-management.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/clients/claude/irc-tools.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/clients/claude/overview.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/clients/claude/setup.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/clients/claude/supervisor.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/clients/claude/webhooks.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/clients/codex/configuration.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/clients/codex/context-management.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/clients/codex/irc-tools.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/clients/codex/overview.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/clients/codex/setup.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/clients/codex/supervisor.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/clients/codex/webhooks.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/clients/copilot/configuration.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/clients/copilot/context-management.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/clients/copilot/irc-tools.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/clients/copilot/overview.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/clients/copilot/setup.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/clients/copilot/supervisor.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/clients/copilot/webhooks.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/culture-cli.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/getting-started.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/index.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/operations/SECURITY.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/operations/bots.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/operations/ci.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/operations/cli.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/operations/docs-site.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/operations/index.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/operations/ops-tooling.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/operations/overview.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/operations/publishing.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/resources/github-copilot-sdk-instructions.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/rooms.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/server-rename.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/superpowers/plans/2026-03-19-layer1-core-irc.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/superpowers/plans/2026-03-21-layer5-agent-harness.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/superpowers/plans/2026-03-30-overview.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/superpowers/plans/2026-03-30-rooms-management.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/superpowers/plans/2026-04-02-conversation-threads.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/superpowers/plans/2026-04-02-ops-tooling.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/superpowers/plans/2026-04-04-culture-rename.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/superpowers/plans/2026-04-05-docs-speak-culture.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/superpowers/plans/2026-04-06-console-chat.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-03-19-agentirc-design.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-03-21-layer5-agent-harness-design.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-03-30-overview-design.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-03-30-rooms-management-design.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-04-02-conversation-threads-design.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-04-02-ops-tooling-design.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-04-03-bots-webhooks-design.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-04-04-culture-rename-design.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-04-05-docs-speak-culture-design.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-04-05-lifecycle-reframe-design.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-04-06-cli-reorganization-design.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-04-06-console-chat-design.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/superpowers/specs/2026-04-07-entity-archiving-design.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/use-cases/01-pair-programming.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/use-cases/02-code-review-ensemble.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/use-cases/03-cross-server-delegation.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/use-cases/04-knowledge-propagation.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/use-cases/05-the-observer.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/use-cases/06-cross-server-ops.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/use-cases/07-supervisor-intervention.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/use-cases/08-apps-as-agents.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/use-cases/09-research-swarm.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/use-cases/10-agent-lifecycle.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/use-cases-index.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/docs/what-is-culture.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/packages/agent-harness/README.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/packages/agent-harness/config.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/packages/agent-harness/ipc.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/packages/agent-harness/skill/SKILL.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/packages/agent-harness/webhook.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/plugins/claude-code/skills/culture/SKILL.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/plugins/claude-code/skills/irc/SKILL.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/plugins/codex/skills/culture-irc/SKILL.md +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/sonar-project.properties +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/__init__.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_archive.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_bot.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_bot_config.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_bot_manager.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_bots_integration.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_channel.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_codex_daemon.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_connection.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_console_client.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_console_integration.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_copilot_daemon.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_daemon.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_daemon_config.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_daemon_ipc.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_discovery.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_history.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_http_listener.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_integration_layer5.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_ipc.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_irc_transport.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_mention_alias.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_mention_target_cleanup.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_mesh_config.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_message.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_message_buffer.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_messaging.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_modes.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_overview_cli.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_overview_collector.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_overview_model.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_overview_renderer.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_overview_web.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_persistence.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_pidfile.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_poll_loop.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_room_persistence.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_rooms_federation.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_rooms_integration.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_server_icon_skill.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_setup_update_cli.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_skill_client.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_skills.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_socket_server.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_template_engine.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_thread_buffer.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_threads.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_virtual_client.py +0 -0
- {agentirc_cli-4.3.6 → agentirc_cli-4.3.7}/tests/test_wait_for_port.py +0 -0
|
@@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
Format follows [Keep a Changelog](https://keepachangelog.com/).
|
|
6
6
|
|
|
7
|
+
## [4.3.7] - 2026-04-07
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Extract duplicate string constants (S1192, #85)
|
|
13
|
+
- Remove redundant exception classes in except clauses (S5713, #86)
|
|
14
|
+
- Clean up unused variables and function parameters (S1481/S1172, #88)
|
|
15
|
+
- Remove f-strings without replacement fields (S3457, #89)
|
|
16
|
+
- Address hardcoded credential warnings with test constants (S2068, #90)
|
|
17
|
+
- Fix miscellaneous code quality issues: asyncio.timeout, nested ternaries, empty methods, CSS contrast (S7483/S3358/S1186/S7924, #91)
|
|
18
|
+
|
|
7
19
|
## [4.3.6] - 2026-04-07
|
|
8
20
|
|
|
9
21
|
|
|
@@ -6,15 +6,19 @@ import logging
|
|
|
6
6
|
from typing import TYPE_CHECKING
|
|
7
7
|
|
|
8
8
|
from culture.bots.bot import Bot
|
|
9
|
-
from culture.bots.config import
|
|
9
|
+
from culture.bots.config import (
|
|
10
|
+
BOT_CONFIG_FILE,
|
|
11
|
+
BOTS_DIR,
|
|
12
|
+
BotConfig,
|
|
13
|
+
load_bot_config,
|
|
14
|
+
save_bot_config,
|
|
15
|
+
)
|
|
10
16
|
|
|
11
17
|
if TYPE_CHECKING:
|
|
12
18
|
from culture.server.ircd import IRCd
|
|
13
19
|
|
|
14
20
|
logger = logging.getLogger(__name__)
|
|
15
21
|
|
|
16
|
-
BOT_CONFIG_FILE = "bot.yaml"
|
|
17
|
-
|
|
18
22
|
|
|
19
23
|
class BotManager:
|
|
20
24
|
"""Loads, starts, stops, and dispatches webhooks to bots."""
|
|
@@ -399,7 +399,7 @@ def _probe_server_connection(host: str, port: int, server_name: str) -> None:
|
|
|
399
399
|
try:
|
|
400
400
|
with _socket.create_connection((host, port), timeout=2):
|
|
401
401
|
pass
|
|
402
|
-
except
|
|
402
|
+
except OSError:
|
|
403
403
|
hint = ""
|
|
404
404
|
server_pid = read_pid(f"server-{server_name}")
|
|
405
405
|
if not server_pid or not is_process_alive(server_pid):
|
|
@@ -55,7 +55,7 @@ def dispatch(args: argparse.Namespace) -> None:
|
|
|
55
55
|
sys.exit(1)
|
|
56
56
|
try:
|
|
57
57
|
handler(args)
|
|
58
|
-
except (
|
|
58
|
+
except (TimeoutError, OSError) as exc:
|
|
59
59
|
msg = str(exc)
|
|
60
60
|
if (
|
|
61
61
|
"Timed out" in msg
|
|
@@ -15,7 +15,6 @@ from culture.clients.claude.config import (
|
|
|
15
15
|
load_config,
|
|
16
16
|
load_config_or_default,
|
|
17
17
|
)
|
|
18
|
-
from culture.pidfile import is_process_alive, read_pid
|
|
19
18
|
|
|
20
19
|
from .shared.constants import AGENTS_YAML, CULTURE_DIR, DEFAULT_CONFIG
|
|
21
20
|
from .shared.mesh import build_server_start_cmd, generate_mesh_from_agents
|
|
@@ -469,7 +468,7 @@ def _wait_for_server_port(port: int, retries: int = 50, interval: float = 0.1) -
|
|
|
469
468
|
try:
|
|
470
469
|
with _socket.create_connection(("localhost", port), timeout=1):
|
|
471
470
|
return
|
|
472
|
-
except
|
|
471
|
+
except OSError:
|
|
473
472
|
time.sleep(interval)
|
|
474
473
|
|
|
475
474
|
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
|
|
5
|
+
from culture.bots.config import BOT_CONFIG_FILE # noqa: F401
|
|
6
|
+
|
|
5
7
|
DEFAULT_CONFIG = os.path.expanduser("~/.culture/agents.yaml")
|
|
6
8
|
LOG_DIR = os.path.expanduser("~/.culture/logs")
|
|
7
9
|
|
|
@@ -9,7 +11,6 @@ _CONFIG_HELP = "Config file path"
|
|
|
9
11
|
_SERVER_NAME_HELP = "Server name"
|
|
10
12
|
_BOT_NAME_HELP = "Bot name"
|
|
11
13
|
|
|
12
|
-
BOT_CONFIG_FILE = "bot.yaml"
|
|
13
14
|
DEFAULT_CHANNEL = "#general"
|
|
14
15
|
NO_AGENTS_MSG = "No agents configured"
|
|
15
16
|
CULTURE_DIR = ".culture"
|
|
@@ -24,7 +24,7 @@ async def ipc_request(socket_path: str, msg_type: str, **kwargs) -> dict | None:
|
|
|
24
24
|
asyncio.open_unix_connection(socket_path),
|
|
25
25
|
timeout=3.0,
|
|
26
26
|
)
|
|
27
|
-
except
|
|
27
|
+
except OSError:
|
|
28
28
|
return None
|
|
29
29
|
try:
|
|
30
30
|
req = make_request(msg_type, **kwargs)
|
|
@@ -40,13 +40,13 @@ async def ipc_request(socket_path: str, msg_type: str, **kwargs) -> dict | None:
|
|
|
40
40
|
msg = decode_message(data)
|
|
41
41
|
if msg and msg.get("type") == "response":
|
|
42
42
|
return msg
|
|
43
|
-
except
|
|
43
|
+
except OSError:
|
|
44
44
|
return None
|
|
45
45
|
finally:
|
|
46
46
|
writer.close()
|
|
47
47
|
try:
|
|
48
48
|
await writer.wait_closed()
|
|
49
|
-
except
|
|
49
|
+
except OSError:
|
|
50
50
|
pass
|
|
51
51
|
|
|
52
52
|
|
|
@@ -151,7 +151,8 @@ class ACPAgentRunner:
|
|
|
151
151
|
return
|
|
152
152
|
try:
|
|
153
153
|
self._process.terminate()
|
|
154
|
-
|
|
154
|
+
async with asyncio.timeout(5):
|
|
155
|
+
await self._process.wait()
|
|
155
156
|
except (asyncio.TimeoutError, ProcessLookupError):
|
|
156
157
|
try:
|
|
157
158
|
self._process.kill()
|
|
@@ -209,7 +210,8 @@ class ACPAgentRunner:
|
|
|
209
210
|
await self._process.stdin.drain()
|
|
210
211
|
|
|
211
212
|
try:
|
|
212
|
-
|
|
213
|
+
async with asyncio.timeout(timeout):
|
|
214
|
+
return await future
|
|
213
215
|
except (asyncio.TimeoutError, asyncio.CancelledError):
|
|
214
216
|
self._pending.pop(req_id, None)
|
|
215
217
|
if not future.done():
|
|
@@ -244,14 +246,16 @@ class ACPAgentRunner:
|
|
|
244
246
|
if not self._process:
|
|
245
247
|
return -1
|
|
246
248
|
try:
|
|
247
|
-
|
|
249
|
+
async with asyncio.timeout(5):
|
|
250
|
+
return await self._process.wait()
|
|
248
251
|
except asyncio.TimeoutError:
|
|
249
252
|
try:
|
|
250
253
|
self._process.kill()
|
|
251
254
|
except ProcessLookupError:
|
|
252
255
|
pass
|
|
253
256
|
try:
|
|
254
|
-
|
|
257
|
+
async with asyncio.timeout(1):
|
|
258
|
+
return await self._process.wait()
|
|
255
259
|
except asyncio.TimeoutError:
|
|
256
260
|
return -1
|
|
257
261
|
|
|
@@ -31,6 +31,8 @@ logger = logging.getLogger(__name__)
|
|
|
31
31
|
|
|
32
32
|
# IPC validation error messages
|
|
33
33
|
_ERR_MISSING_CHANNEL = "Missing 'channel'"
|
|
34
|
+
_ERR_MISSING_CHANNEL_THREAD = "Missing 'channel' or 'thread'"
|
|
35
|
+
_ERR_MISSING_CHANNEL_THREAD_MSG = "Missing 'channel', 'thread', or 'message'"
|
|
34
36
|
|
|
35
37
|
MAX_CRASH_COUNT = 3
|
|
36
38
|
CRASH_WINDOW_SECONDS = 300
|
|
@@ -304,7 +306,7 @@ class ACPDaemon:
|
|
|
304
306
|
prompt = (
|
|
305
307
|
f"[IRC Channel Poll: {channel}] Recent unread messages:\n"
|
|
306
308
|
f"{lines}\n\n"
|
|
307
|
-
|
|
309
|
+
"Respond naturally if any messages need your attention."
|
|
308
310
|
)
|
|
309
311
|
self._mention_targets.append(channel)
|
|
310
312
|
task = asyncio.create_task(self._agent_runner.send_prompt(prompt))
|
|
@@ -485,10 +487,10 @@ class ACPDaemon:
|
|
|
485
487
|
return self.agent.system_prompt
|
|
486
488
|
return (
|
|
487
489
|
f"You are {self.agent.nick}, an AI agent on the culture IRC network.\n"
|
|
488
|
-
|
|
490
|
+
"You have IRC tools available via the irc skill. Use them to communicate.\n"
|
|
489
491
|
f"Your working directory is {self.agent.directory}.\n"
|
|
490
|
-
|
|
491
|
-
|
|
492
|
+
"Check IRC channels periodically with irc_read() for new messages.\n"
|
|
493
|
+
"When you finish a task, share results in the appropriate channel with irc_send()."
|
|
492
494
|
)
|
|
493
495
|
|
|
494
496
|
async def _record_crash_time(self, exit_code: int) -> None:
|
|
@@ -642,6 +644,13 @@ class ACPDaemon:
|
|
|
642
644
|
if query and running and not self._paused:
|
|
643
645
|
description = await self._query_agent_status()
|
|
644
646
|
|
|
647
|
+
if self._paused:
|
|
648
|
+
activity = "paused"
|
|
649
|
+
elif running:
|
|
650
|
+
activity = "working"
|
|
651
|
+
else:
|
|
652
|
+
activity = "idle"
|
|
653
|
+
|
|
645
654
|
return make_response(
|
|
646
655
|
req_id,
|
|
647
656
|
ok=True,
|
|
@@ -650,7 +659,7 @@ class ACPDaemon:
|
|
|
650
659
|
"paused": self._paused,
|
|
651
660
|
"turn_count": turn_count,
|
|
652
661
|
"last_activation": self._last_activation,
|
|
653
|
-
"activity":
|
|
662
|
+
"activity": activity,
|
|
654
663
|
"description": description,
|
|
655
664
|
},
|
|
656
665
|
)
|
|
@@ -687,7 +696,8 @@ class ACPDaemon:
|
|
|
687
696
|
"[SYSTEM] Briefly describe what you are currently working on "
|
|
688
697
|
"in one sentence. Reply with just the description, no preamble."
|
|
689
698
|
)
|
|
690
|
-
|
|
699
|
+
async with asyncio.timeout(10.0):
|
|
700
|
+
await self._status_query_event.wait()
|
|
691
701
|
return self._truncate_first_line(self._status_query_response) or "nothing"
|
|
692
702
|
except asyncio.TimeoutError:
|
|
693
703
|
return "busy (no response)"
|
|
@@ -744,9 +754,7 @@ class ACPDaemon:
|
|
|
744
754
|
thread_name = msg.get("thread", "")
|
|
745
755
|
text = msg.get("message", "")
|
|
746
756
|
if not channel or not thread_name or not text:
|
|
747
|
-
return make_response(
|
|
748
|
-
req_id, ok=False, error="Missing 'channel', 'thread', or 'message'"
|
|
749
|
-
)
|
|
757
|
+
return make_response(req_id, ok=False, error=_ERR_MISSING_CHANNEL_THREAD_MSG)
|
|
750
758
|
assert self._transport is not None
|
|
751
759
|
await self._transport.send_thread_create(channel, thread_name, text)
|
|
752
760
|
return make_response(req_id, ok=True)
|
|
@@ -756,9 +764,7 @@ class ACPDaemon:
|
|
|
756
764
|
thread_name = msg.get("thread", "")
|
|
757
765
|
text = msg.get("message", "")
|
|
758
766
|
if not channel or not thread_name or not text:
|
|
759
|
-
return make_response(
|
|
760
|
-
req_id, ok=False, error="Missing 'channel', 'thread', or 'message'"
|
|
761
|
-
)
|
|
767
|
+
return make_response(req_id, ok=False, error=_ERR_MISSING_CHANNEL_THREAD_MSG)
|
|
762
768
|
assert self._transport is not None
|
|
763
769
|
await self._transport.send_thread_reply(channel, thread_name, text)
|
|
764
770
|
return make_response(req_id, ok=True)
|
|
@@ -776,7 +782,7 @@ class ACPDaemon:
|
|
|
776
782
|
thread_name = msg.get("thread", "")
|
|
777
783
|
summary = msg.get("summary", "")
|
|
778
784
|
if not channel or not thread_name:
|
|
779
|
-
return make_response(req_id, ok=False, error=
|
|
785
|
+
return make_response(req_id, ok=False, error=_ERR_MISSING_CHANNEL_THREAD)
|
|
780
786
|
assert self._transport is not None
|
|
781
787
|
await self._transport.send_thread_close(channel, thread_name, summary)
|
|
782
788
|
return make_response(req_id, ok=True)
|
|
@@ -786,7 +792,7 @@ class ACPDaemon:
|
|
|
786
792
|
thread_name = msg.get("thread", "")
|
|
787
793
|
limit = int(msg.get("limit", 50))
|
|
788
794
|
if not channel or not thread_name:
|
|
789
|
-
return make_response(req_id, ok=False, error=
|
|
795
|
+
return make_response(req_id, ok=False, error=_ERR_MISSING_CHANNEL_THREAD)
|
|
790
796
|
assert self._buffer is not None
|
|
791
797
|
messages = self._buffer.read_thread(channel, thread_name, limit=limit)
|
|
792
798
|
return make_response(
|
|
@@ -60,7 +60,7 @@ class IRCTransport:
|
|
|
60
60
|
async def _do_connect(self) -> None:
|
|
61
61
|
try:
|
|
62
62
|
self._reader, self._writer = await asyncio.open_connection(self.host, self.port)
|
|
63
|
-
except
|
|
63
|
+
except OSError as exc:
|
|
64
64
|
raise ConnectionError(
|
|
65
65
|
f"Cannot connect to IRC server at {self.host}:{self.port} "
|
|
66
66
|
f"- is the server running?"
|
|
@@ -77,12 +77,12 @@ class IRCTransport:
|
|
|
77
77
|
if self._writer:
|
|
78
78
|
try:
|
|
79
79
|
await self._send_raw("QUIT :daemon shutdown")
|
|
80
|
-
except
|
|
80
|
+
except OSError:
|
|
81
81
|
pass
|
|
82
82
|
self._writer.close()
|
|
83
83
|
try:
|
|
84
84
|
await self._writer.wait_closed()
|
|
85
|
-
except
|
|
85
|
+
except ConnectionError:
|
|
86
86
|
pass
|
|
87
87
|
self.connected = False
|
|
88
88
|
|
|
@@ -139,7 +139,7 @@ class IRCTransport:
|
|
|
139
139
|
await self._handle(msg)
|
|
140
140
|
except asyncio.CancelledError:
|
|
141
141
|
raise
|
|
142
|
-
except
|
|
142
|
+
except OSError:
|
|
143
143
|
logger.warning("IRC connection lost")
|
|
144
144
|
finally:
|
|
145
145
|
self.connected = False
|
|
@@ -159,7 +159,7 @@ class IRCTransport:
|
|
|
159
159
|
logger.info("Reconnected to IRC")
|
|
160
160
|
self._reconnecting = False
|
|
161
161
|
return
|
|
162
|
-
except
|
|
162
|
+
except OSError:
|
|
163
163
|
delay = min(delay * 2, 60)
|
|
164
164
|
|
|
165
165
|
async def _handle(self, msg: Message) -> None:
|
|
@@ -56,7 +56,7 @@ class SkillClient:
|
|
|
56
56
|
self._writer.close()
|
|
57
57
|
try:
|
|
58
58
|
await self._writer.wait_closed()
|
|
59
|
-
except
|
|
59
|
+
except OSError:
|
|
60
60
|
pass
|
|
61
61
|
self._writer = None
|
|
62
62
|
self._reader = None
|
|
@@ -91,7 +91,7 @@ class SkillClient:
|
|
|
91
91
|
if msg is None:
|
|
92
92
|
continue
|
|
93
93
|
self._dispatch_message(msg)
|
|
94
|
-
except (asyncio.IncompleteReadError,
|
|
94
|
+
except (asyncio.IncompleteReadError, OSError):
|
|
95
95
|
pass
|
|
96
96
|
finally:
|
|
97
97
|
self._fail_pending("Connection lost")
|
|
@@ -32,7 +32,7 @@ class SocketServer:
|
|
|
32
32
|
try:
|
|
33
33
|
writer.close()
|
|
34
34
|
await writer.wait_closed()
|
|
35
|
-
except
|
|
35
|
+
except OSError:
|
|
36
36
|
pass
|
|
37
37
|
self._clients.clear()
|
|
38
38
|
if self._server:
|
|
@@ -52,7 +52,7 @@ class SocketServer:
|
|
|
52
52
|
try:
|
|
53
53
|
writer.write(data)
|
|
54
54
|
await writer.drain()
|
|
55
|
-
except
|
|
55
|
+
except OSError:
|
|
56
56
|
self._clients.remove(writer)
|
|
57
57
|
else:
|
|
58
58
|
await self._whisper_queue.put(data)
|
|
@@ -76,7 +76,7 @@ class SocketServer:
|
|
|
76
76
|
await writer.drain()
|
|
77
77
|
except asyncio.QueueEmpty:
|
|
78
78
|
break
|
|
79
|
-
except
|
|
79
|
+
except OSError:
|
|
80
80
|
break
|
|
81
81
|
|
|
82
82
|
async def _process_client_messages(
|
|
@@ -112,7 +112,7 @@ class SocketServer:
|
|
|
112
112
|
writer.write(encode_message(err_resp))
|
|
113
113
|
await writer.drain()
|
|
114
114
|
return True
|
|
115
|
-
except
|
|
115
|
+
except OSError:
|
|
116
116
|
return False
|
|
117
117
|
|
|
118
118
|
def _cleanup_client(self, writer: asyncio.StreamWriter) -> None:
|
|
@@ -81,7 +81,8 @@ class AgentRunner:
|
|
|
81
81
|
self._prompt_queue.put_nowait("")
|
|
82
82
|
if self._task and not self._task.done():
|
|
83
83
|
try:
|
|
84
|
-
|
|
84
|
+
async with asyncio.timeout(5.0):
|
|
85
|
+
await asyncio.shield(self._task)
|
|
85
86
|
except (asyncio.TimeoutError, asyncio.CancelledError):
|
|
86
87
|
self._task.cancel()
|
|
87
88
|
await asyncio.gather(self._task, return_exceptions=True)
|
|
@@ -25,6 +25,8 @@ CRASH_RESTART_DELAY = 5
|
|
|
25
25
|
|
|
26
26
|
# IPC validation error messages
|
|
27
27
|
_ERR_MISSING_CHANNEL = "Missing 'channel'"
|
|
28
|
+
_ERR_MISSING_CHANNEL_THREAD = "Missing 'channel' or 'thread'"
|
|
29
|
+
_ERR_MISSING_CHANNEL_THREAD_MSG = "Missing 'channel', 'thread', or 'message'"
|
|
28
30
|
|
|
29
31
|
|
|
30
32
|
class AgentDaemon:
|
|
@@ -260,7 +262,7 @@ class AgentDaemon:
|
|
|
260
262
|
prompt = (
|
|
261
263
|
f"[IRC Channel Poll: {channel}] Recent unread messages:\n"
|
|
262
264
|
f"{lines}\n\n"
|
|
263
|
-
|
|
265
|
+
"Respond naturally if any messages need your attention."
|
|
264
266
|
)
|
|
265
267
|
task = asyncio.create_task(self._agent_runner.send_prompt(prompt))
|
|
266
268
|
self._background_tasks.add(task)
|
|
@@ -398,10 +400,10 @@ class AgentDaemon:
|
|
|
398
400
|
return self.agent.system_prompt
|
|
399
401
|
return (
|
|
400
402
|
f"You are {self.agent.nick}, an AI agent on the culture IRC network.\n"
|
|
401
|
-
|
|
403
|
+
"You have IRC tools available via the irc skill. Use them to communicate.\n"
|
|
402
404
|
f"Your working directory is {self.agent.directory}.\n"
|
|
403
|
-
|
|
404
|
-
|
|
405
|
+
"Check IRC channels periodically with irc_read() for new messages.\n"
|
|
406
|
+
"When you finish a task, share results in the appropriate channel with irc_send()."
|
|
405
407
|
)
|
|
406
408
|
|
|
407
409
|
async def _record_crash_time(self, exit_code: int) -> None:
|
|
@@ -563,6 +565,13 @@ class AgentDaemon:
|
|
|
563
565
|
if query and running and not self._paused:
|
|
564
566
|
description = await self._query_agent_status()
|
|
565
567
|
|
|
568
|
+
if self._paused:
|
|
569
|
+
activity = "paused"
|
|
570
|
+
elif running:
|
|
571
|
+
activity = "working"
|
|
572
|
+
else:
|
|
573
|
+
activity = "idle"
|
|
574
|
+
|
|
566
575
|
return make_response(
|
|
567
576
|
req_id,
|
|
568
577
|
ok=True,
|
|
@@ -571,7 +580,7 @@ class AgentDaemon:
|
|
|
571
580
|
"paused": self._paused,
|
|
572
581
|
"turn_count": turn_count,
|
|
573
582
|
"last_activation": self._last_activation,
|
|
574
|
-
"activity":
|
|
583
|
+
"activity": activity,
|
|
575
584
|
"description": description,
|
|
576
585
|
},
|
|
577
586
|
)
|
|
@@ -605,7 +614,8 @@ class AgentDaemon:
|
|
|
605
614
|
"[SYSTEM] Briefly describe what you are currently working on "
|
|
606
615
|
"in one sentence. Reply with just the description, no preamble."
|
|
607
616
|
)
|
|
608
|
-
|
|
617
|
+
async with asyncio.timeout(10.0):
|
|
618
|
+
await self._status_query_event.wait()
|
|
609
619
|
return self._truncate_first_line(self._status_query_response) or "nothing"
|
|
610
620
|
except asyncio.TimeoutError:
|
|
611
621
|
return "busy (no response)"
|
|
@@ -662,9 +672,7 @@ class AgentDaemon:
|
|
|
662
672
|
thread_name = msg.get("thread", "")
|
|
663
673
|
text = msg.get("message", "")
|
|
664
674
|
if not channel or not thread_name or not text:
|
|
665
|
-
return make_response(
|
|
666
|
-
req_id, ok=False, error="Missing 'channel', 'thread', or 'message'"
|
|
667
|
-
)
|
|
675
|
+
return make_response(req_id, ok=False, error=_ERR_MISSING_CHANNEL_THREAD_MSG)
|
|
668
676
|
assert self._transport is not None
|
|
669
677
|
await self._transport.send_thread_create(channel, thread_name, text)
|
|
670
678
|
return make_response(req_id, ok=True)
|
|
@@ -674,9 +682,7 @@ class AgentDaemon:
|
|
|
674
682
|
thread_name = msg.get("thread", "")
|
|
675
683
|
text = msg.get("message", "")
|
|
676
684
|
if not channel or not thread_name or not text:
|
|
677
|
-
return make_response(
|
|
678
|
-
req_id, ok=False, error="Missing 'channel', 'thread', or 'message'"
|
|
679
|
-
)
|
|
685
|
+
return make_response(req_id, ok=False, error=_ERR_MISSING_CHANNEL_THREAD_MSG)
|
|
680
686
|
assert self._transport is not None
|
|
681
687
|
await self._transport.send_thread_reply(channel, thread_name, text)
|
|
682
688
|
return make_response(req_id, ok=True)
|
|
@@ -694,7 +700,7 @@ class AgentDaemon:
|
|
|
694
700
|
thread_name = msg.get("thread", "")
|
|
695
701
|
summary = msg.get("summary", "")
|
|
696
702
|
if not channel or not thread_name:
|
|
697
|
-
return make_response(req_id, ok=False, error=
|
|
703
|
+
return make_response(req_id, ok=False, error=_ERR_MISSING_CHANNEL_THREAD)
|
|
698
704
|
assert self._transport is not None
|
|
699
705
|
await self._transport.send_thread_close(channel, thread_name, summary)
|
|
700
706
|
return make_response(req_id, ok=True)
|
|
@@ -704,7 +710,7 @@ class AgentDaemon:
|
|
|
704
710
|
thread_name = msg.get("thread", "")
|
|
705
711
|
limit = int(msg.get("limit", 50))
|
|
706
712
|
if not channel or not thread_name:
|
|
707
|
-
return make_response(req_id, ok=False, error=
|
|
713
|
+
return make_response(req_id, ok=False, error=_ERR_MISSING_CHANNEL_THREAD)
|
|
708
714
|
assert self._buffer is not None
|
|
709
715
|
messages = self._buffer.read_thread(channel, thread_name, limit=limit)
|
|
710
716
|
return make_response(
|
|
@@ -60,7 +60,7 @@ class IRCTransport:
|
|
|
60
60
|
async def _do_connect(self) -> None:
|
|
61
61
|
try:
|
|
62
62
|
self._reader, self._writer = await asyncio.open_connection(self.host, self.port)
|
|
63
|
-
except
|
|
63
|
+
except OSError as exc:
|
|
64
64
|
raise ConnectionError(
|
|
65
65
|
f"Cannot connect to IRC server at {self.host}:{self.port} "
|
|
66
66
|
f"- is the server running?"
|
|
@@ -77,12 +77,12 @@ class IRCTransport:
|
|
|
77
77
|
if self._writer:
|
|
78
78
|
try:
|
|
79
79
|
await self._send_raw("QUIT :daemon shutdown")
|
|
80
|
-
except
|
|
80
|
+
except OSError:
|
|
81
81
|
pass
|
|
82
82
|
self._writer.close()
|
|
83
83
|
try:
|
|
84
84
|
await self._writer.wait_closed()
|
|
85
|
-
except
|
|
85
|
+
except ConnectionError:
|
|
86
86
|
pass
|
|
87
87
|
self.connected = False
|
|
88
88
|
|
|
@@ -139,7 +139,7 @@ class IRCTransport:
|
|
|
139
139
|
await self._handle(msg)
|
|
140
140
|
except asyncio.CancelledError:
|
|
141
141
|
raise
|
|
142
|
-
except
|
|
142
|
+
except OSError:
|
|
143
143
|
logger.warning("IRC connection lost")
|
|
144
144
|
finally:
|
|
145
145
|
self.connected = False
|
|
@@ -159,7 +159,7 @@ class IRCTransport:
|
|
|
159
159
|
logger.info("Reconnected to IRC")
|
|
160
160
|
self._reconnecting = False
|
|
161
161
|
return
|
|
162
|
-
except
|
|
162
|
+
except OSError:
|
|
163
163
|
delay = min(delay * 2, 60)
|
|
164
164
|
|
|
165
165
|
async def _handle(self, msg: Message) -> None:
|
|
@@ -56,7 +56,7 @@ class SkillClient:
|
|
|
56
56
|
self._writer.close()
|
|
57
57
|
try:
|
|
58
58
|
await self._writer.wait_closed()
|
|
59
|
-
except
|
|
59
|
+
except OSError:
|
|
60
60
|
pass
|
|
61
61
|
self._writer = None
|
|
62
62
|
self._reader = None
|
|
@@ -84,7 +84,7 @@ class SkillClient:
|
|
|
84
84
|
if msg is None:
|
|
85
85
|
continue
|
|
86
86
|
self._dispatch_message(msg)
|
|
87
|
-
except (asyncio.IncompleteReadError,
|
|
87
|
+
except (asyncio.IncompleteReadError, OSError):
|
|
88
88
|
pass
|
|
89
89
|
finally:
|
|
90
90
|
# Resolve any still-pending futures with an error
|
|
@@ -32,7 +32,7 @@ class SocketServer:
|
|
|
32
32
|
try:
|
|
33
33
|
writer.close()
|
|
34
34
|
await writer.wait_closed()
|
|
35
|
-
except
|
|
35
|
+
except OSError:
|
|
36
36
|
pass
|
|
37
37
|
self._clients.clear()
|
|
38
38
|
if self._server:
|
|
@@ -55,7 +55,7 @@ class SocketServer:
|
|
|
55
55
|
try:
|
|
56
56
|
writer.write(data)
|
|
57
57
|
await writer.drain()
|
|
58
|
-
except
|
|
58
|
+
except OSError:
|
|
59
59
|
self._clients.remove(writer)
|
|
60
60
|
else:
|
|
61
61
|
# No clients yet — queue for delivery when one connects.
|
|
@@ -80,7 +80,7 @@ class SocketServer:
|
|
|
80
80
|
await writer.drain()
|
|
81
81
|
except asyncio.QueueEmpty:
|
|
82
82
|
break
|
|
83
|
-
except
|
|
83
|
+
except OSError:
|
|
84
84
|
break
|
|
85
85
|
|
|
86
86
|
async def _process_client_messages(
|
|
@@ -116,7 +116,7 @@ class SocketServer:
|
|
|
116
116
|
writer.write(encode_message(err_resp))
|
|
117
117
|
await writer.drain()
|
|
118
118
|
return True
|
|
119
|
-
except
|
|
119
|
+
except OSError:
|
|
120
120
|
return False
|
|
121
121
|
|
|
122
122
|
def _cleanup_client(self, writer: asyncio.StreamWriter) -> None:
|
|
@@ -128,7 +128,8 @@ class CodexAgentRunner:
|
|
|
128
128
|
return
|
|
129
129
|
try:
|
|
130
130
|
self._process.terminate()
|
|
131
|
-
|
|
131
|
+
async with asyncio.timeout(5):
|
|
132
|
+
await self._process.wait()
|
|
132
133
|
except (asyncio.TimeoutError, ProcessLookupError):
|
|
133
134
|
try:
|
|
134
135
|
self._process.kill()
|
|
@@ -185,7 +186,8 @@ class CodexAgentRunner:
|
|
|
185
186
|
await self._process.stdin.drain()
|
|
186
187
|
|
|
187
188
|
try:
|
|
188
|
-
|
|
189
|
+
async with asyncio.timeout(30):
|
|
190
|
+
return await future
|
|
189
191
|
except (asyncio.TimeoutError, asyncio.CancelledError):
|
|
190
192
|
self._pending.pop(req_id, None)
|
|
191
193
|
if not future.done():
|
|
@@ -220,14 +222,16 @@ class CodexAgentRunner:
|
|
|
220
222
|
if not self._process:
|
|
221
223
|
return -1
|
|
222
224
|
try:
|
|
223
|
-
|
|
225
|
+
async with asyncio.timeout(5):
|
|
226
|
+
return await self._process.wait()
|
|
224
227
|
except asyncio.TimeoutError:
|
|
225
228
|
try:
|
|
226
229
|
self._process.kill()
|
|
227
230
|
except ProcessLookupError:
|
|
228
231
|
pass
|
|
229
232
|
try:
|
|
230
|
-
|
|
233
|
+
async with asyncio.timeout(1):
|
|
234
|
+
return await self._process.wait()
|
|
231
235
|
except asyncio.TimeoutError:
|
|
232
236
|
return -1
|
|
233
237
|
|