zettcode 0.1.11__tar.gz → 0.1.12__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.
- {zettcode-0.1.11 → zettcode-0.1.12}/PKG-INFO +1 -1
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/__init__.py +1 -1
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/conversation/tips.py +1 -1
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/commands.py +20 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/app.py +27 -10
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/messaging.py +9 -89
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/shell.py +4 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/config.py +2 -2
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/mentions.py +11 -10
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/relay.py +3 -3
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/sdk/client.py +1 -1
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/server/app.py +1 -1
- {zettcode-0.1.11 → zettcode-0.1.12}/.gitignore +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/README.md +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/pyproject.toml +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/_compat.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/agent/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/agent/commands.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/agent/settings.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/conversation/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/conversation/changes.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/conversation/effort_gauge.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/conversation/entries.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/conversation/presenters.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/conversation/projection.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/conversation/pulse.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/conversation/rendering.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/conversation/replay.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/conversation/shimmer.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/conversation/stops.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/conversation/text.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/conversation/transcript/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/conversation/transcript/fold.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/conversation/transcript/log.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/conversation/transcript/oneoff.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/conversation/transcript/stream.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/conversation/transcript/turn.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/brand.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/commandline/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/commandline/arguments.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/commandline/completion.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/commandline/history.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/commandline/runner.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/pets/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/pets/cat.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/pets/chibi.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/pets/dog.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/pets/kangaroo.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/pets/model.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/pets/penguin.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/pets/polarbear.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/pets/scarfy.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/pets/seagull.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/pets/slime.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/pets/snowbear.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/pets/sprout.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/pets/tiger.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/pets/whale.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/plugins/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/plugins/builtin_commands.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/plugins/builtins.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/plugins/container.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/plugins/host.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/plugins/loader.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/plugins/mixins.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/plugins/plugin.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/plugins/state.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/bars.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/boot.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/clipboard.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/commands.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/config_form.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/demo.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/followups.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/gc_policy.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/keys.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/labels.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/notices.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/providers.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/sessions.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/settings.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/turns.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/updating.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/approval_page.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/ask_page.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/bash_page.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/completer.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/composer.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/context_charts.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/context_page.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/effort_page.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/follow_up.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/form_page.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/input_page.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/model_page.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/model_settings_page.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/panel.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/pet.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/pet_page.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/root.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/self_compact_page.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/send_kind_page.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/sessions_page.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/statusline_page.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/steering.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/transcript.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/update_page.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/usage_charts.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/usage_page.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/ui/widgets/welcome.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/broker/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/broker/__main__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/broker/client.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/broker/files.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/broker/finder.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/broker/hub.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/broker/log.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/broker/models.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/broker/process.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/broker/protocol.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/broker/roster.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/broker/runner.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/broker/server.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/broker/text.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/broker/web.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/budget.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/cli.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/collector.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/config_edit.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/daemon/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/daemon/__main__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/daemon/cli.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/daemon/process.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/daemon/run.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/daemon/state.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/doctor.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/agent/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/agent/base.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/agent/context.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/agent/exports.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/agent/interaction.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/agent/sessions.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/agent/settings.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/agent/turns.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/core.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/dialogue/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/dialogue/ask.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/dialogue/side.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/dialogue/title.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/export/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/export/trace/script.js +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/export/trace/style.css +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/export/trace/template.html +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/extensions/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/extensions/capabilities.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/extensions/compaction.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/extensions/context.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/extensions/files.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/extensions/harness.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/extensions/harness_switch.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/extensions/mcp.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/extensions/mcp_notice.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/extensions/messaging.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/extensions/relay.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/extensions/subagents.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/extensions/tool_output.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/extensions/usage.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/messenger.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/permission/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/permission/approval.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/permission/readonly.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/permission/sandbox.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/pipeline.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/plugins/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/plugins/builtin_agent.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/plugins/container.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/plugins/extension.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/plugins/loader.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/plugins/mixins.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/plugins/plugin.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/plugins/services.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/plugins/state.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/server_tools.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/storage/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/storage/layout.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/storage/ledger.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/storage/locks.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/storage/metadata.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/storage/records.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/storage/store.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/tools/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/tools/boundary.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/tools/files.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/tools/images.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/tools/output.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/tools/shell.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/engine/tools/workspace.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/error_text.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/filelock.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/oneshot.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/paths.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/prompt.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/providers.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/py.typed +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/registry.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/sdk/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/sdk/errors.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/sdk/events.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/sdk/handlers.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/sdk/models.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/sdk/session.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/sdk/translation.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/sdk/types.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/server/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/server/cli.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/server/runner.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/server/schemas.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/server/serialize.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/server/settings.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/statusline.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/capabilities.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/clipboard.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/console.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/core/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/core/app.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/core/events.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/core/focus.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/core/geometry.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/core/host.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/core/keymap.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/core/scheduler.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/core/screen.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/core/theme.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/core/widget.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/gallery.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/glyphs.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/input/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/input/bridge.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/input/decoder.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/input/events.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/input/keys.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/input/reader.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/layout/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/layout/box.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/layout/overlay.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/layout/scroll.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/layout/solver.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/layout/spacing.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/render/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/render/ansi.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/render/canvas.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/render/code.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/render/color.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/render/renderer.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/render/rich_text.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/render/style.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/render/sweep.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/render/text.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/runner.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/terminal.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/testing/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/testing/harness.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/testing/snapshot.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/theme_file.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/themes/ayu-mirage.toml +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/themes/catppuccin-latte.toml +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/themes/catppuccin-mocha.toml +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/themes/dracula.toml +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/themes/github-dimmed.toml +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/themes/github-light.toml +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/themes/gruvbox-dark.toml +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/themes/gruvbox-light.toml +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/themes/kanagawa.toml +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/themes/nord.toml +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/themes/one-dark.toml +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/themes/rose-pine-dawn.toml +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/themes/rose-pine.toml +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/themes/solarized-dark.toml +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/themes/solarized-light.toml +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/themes/tokyo-night.toml +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/widgets/__init__.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/widgets/collapsible.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/widgets/completion.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/widgets/console.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/widgets/dialog.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/widgets/diff.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/widgets/list.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/widgets/list_page.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/widgets/markdown.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/widgets/progress.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/widgets/rich_text.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/widgets/status.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/widgets/table.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/widgets/tasks.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/widgets/text.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/widgets/textarea.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/tui/widgets/toast.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/update.py +0 -0
- {zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/wording.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: zettcode
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.12
|
|
4
4
|
Summary: A focused terminal coding agent powered by zett-agent
|
|
5
5
|
Project-URL: Repository, https://github.com/Chang-LeHung/zettcode
|
|
6
6
|
Project-URL: Issues, https://github.com/Chang-LeHung/zettcode/issues
|
|
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING
|
|
|
7
7
|
|
|
8
8
|
#: The one place the version is written. ``pyproject.toml`` reads it from here
|
|
9
9
|
#: and the release workflow checks the tag against it, so a bump is one edit.
|
|
10
|
-
__version__ = "0.1.
|
|
10
|
+
__version__ = "0.1.12"
|
|
11
11
|
|
|
12
12
|
#: Where each public name lives; read by :func:`__getattr__` on first use.
|
|
13
13
|
_EXPORTS = {
|
|
@@ -22,7 +22,7 @@ TIPS: tuple[str, ...] = (
|
|
|
22
22
|
"Type while it works: your message can steer this request, or wait and follow it.",
|
|
23
23
|
"Press Shift-Enter (or Alt-Enter) to add a line to your message instead of sending it.",
|
|
24
24
|
"Type @ to mention a file or a skill. A file is read when the message is sent.",
|
|
25
|
-
"
|
|
25
|
+
"Type @ to mention another running ZettCode session; the model can pass your message to it.",
|
|
26
26
|
"/btw <question> is answered on the side and never joins the conversation.",
|
|
27
27
|
"/bash opens a full-screen command line: your shell's history, Tab completion, and coloured output.",
|
|
28
28
|
"In /bash, Tab completes git subcommands and branches, and Ctrl-C stops a running command.",
|
|
@@ -101,6 +101,26 @@ class CommandHost(Protocol):
|
|
|
101
101
|
async def run_side_question(self, question: str) -> None:
|
|
102
102
|
"""Answer a question that is kept out of the conversation."""
|
|
103
103
|
|
|
104
|
+
async def prompt(self, text: str) -> bool:
|
|
105
|
+
"""Run ``text`` as one turn of this conversation, exactly as if the reader had typed it.
|
|
106
|
+
|
|
107
|
+
The text reaches the model the way a draft does: echoed in the transcript as the reader's own message,
|
|
108
|
+
stored in the session, streamed as it is answered, and settled by the same row. ``@`` references are
|
|
109
|
+
resolved; pictures the text cannot carry are not part of it.
|
|
110
|
+
|
|
111
|
+
The turn is awaited, so the command that asked for it holds the request slot until it has been answered,
|
|
112
|
+
and the row the shell shows is the command's own.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
text: What to ask. Its own text is what the reader sees, so a command that builds the text should
|
|
116
|
+
write it as a reader would have.
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
Whether a turn was started and has ended. A request already running, a blank text and a session held
|
|
120
|
+
by another process answer ``False``, and nothing is started. A command that means to be usable
|
|
121
|
+
mid-request says ``when_busy="queue"``, and this then runs when the request in flight has ended.
|
|
122
|
+
"""
|
|
123
|
+
|
|
104
124
|
def change_model(self, name: ModelInfo | str) -> ModelInfo:
|
|
105
125
|
"""Switch models and announce the change in the transcript."""
|
|
106
126
|
|
|
@@ -135,8 +135,8 @@ class ZettCodeApp(
|
|
|
135
135
|
# The plugins' commands reach the shell through the context they are run with, and the words their menus
|
|
136
136
|
# offer through this link; the shell is built enough by now that either may follow it.
|
|
137
137
|
agent.attach_host(self)
|
|
138
|
-
#: The line to the other sessions, when the configuration has one;
|
|
139
|
-
#:
|
|
138
|
+
#: The line to the other sessions, when the configuration has one; a session name it offers for ``@``
|
|
139
|
+
#: comes first, so it wins over a file or plugin resource of the same name.
|
|
140
140
|
self.messenger: SessionLink | None = agent.messenger
|
|
141
141
|
self.mentions = MentionRegistry(
|
|
142
142
|
agent.plugin_mentions
|
|
@@ -254,7 +254,6 @@ class ZettCodeApp(
|
|
|
254
254
|
self._follow_ups_held = False
|
|
255
255
|
self._turn_running = False
|
|
256
256
|
self._inbox: list[Relayed] = []
|
|
257
|
-
self._sends: set[asyncio.Task[None]] = set()
|
|
258
257
|
self._lock_watch: asyncio.Task[None] | None = None
|
|
259
258
|
self._lock_said: str | None = None
|
|
260
259
|
self._messaging_live = False
|
|
@@ -660,6 +659,26 @@ class ZettCodeApp(
|
|
|
660
659
|
if outcome:
|
|
661
660
|
self._settle_wait(outcome)
|
|
662
661
|
|
|
662
|
+
async def prompt(self, text: str) -> bool:
|
|
663
|
+
"""Run ``text`` as one turn of this conversation, as if the reader had typed it.
|
|
664
|
+
|
|
665
|
+
The draft path is taken whole — the echo, ``@`` references, the transcript, the session, the row the
|
|
666
|
+
request ends on — rather than a run of its own, so a command that asks the model something produces a turn
|
|
667
|
+
a reader could have produced. What the command decides is the text; everything after that is the ordinary
|
|
668
|
+
one.
|
|
669
|
+
|
|
670
|
+
The turn is awaited, so the request slot stays the command's until the answer is in: a second draft cannot
|
|
671
|
+
start behind it, and the command reports what it did once it is done.
|
|
672
|
+
"""
|
|
673
|
+
if not text.strip():
|
|
674
|
+
return False
|
|
675
|
+
if self.client.session.locked:
|
|
676
|
+
self.flash("this session is open in another ZettCode process; it is read-only here", level="error")
|
|
677
|
+
return False
|
|
678
|
+
parts = mention_parts((text,), self.mentions)
|
|
679
|
+
await self._run_prompt(text, parts, mention_hint(parts, self.mentions), advance=False)
|
|
680
|
+
return True
|
|
681
|
+
|
|
663
682
|
async def run_continue(self) -> None:
|
|
664
683
|
"""Pick up the request that was interrupted, where it stopped, as a turn of the conversation.
|
|
665
684
|
|
|
@@ -821,12 +840,6 @@ class ZettCodeApp(
|
|
|
821
840
|
# typed, and this is for what arrives some other way (a draft that was there already, a recall).
|
|
822
841
|
self.flash("this session is open in another ZettCode process; it is read-only here", level="error")
|
|
823
842
|
return False
|
|
824
|
-
if not command:
|
|
825
|
-
# A draft that begins with the name of an active session is a message to it: sent whatever this
|
|
826
|
-
# session is doing, because it is not a request to this session's model.
|
|
827
|
-
sent = self._send_session_message(self.composer.parts())
|
|
828
|
-
if sent is not None:
|
|
829
|
-
return sent
|
|
830
843
|
if self._busy:
|
|
831
844
|
if command:
|
|
832
845
|
# Which commands are taken mid-request is the command's own
|
|
@@ -971,6 +984,7 @@ class ZettCodeApp(
|
|
|
971
984
|
hint: str | None = None,
|
|
972
985
|
*,
|
|
973
986
|
relayed: Relayed | None = None,
|
|
987
|
+
advance: bool = True,
|
|
974
988
|
) -> None:
|
|
975
989
|
"""Stream one agent turn, keeping the task panel and transcript current.
|
|
976
990
|
|
|
@@ -1056,7 +1070,10 @@ class ZettCodeApp(
|
|
|
1056
1070
|
self._note = None
|
|
1057
1071
|
self._refresh_tasks()
|
|
1058
1072
|
self.app.invalidate()
|
|
1059
|
-
|
|
1073
|
+
if advance:
|
|
1074
|
+
# A turn a command asked for leaves this to the command: it is still running, and what was queued
|
|
1075
|
+
# waits for it to end, not for the turn inside it.
|
|
1076
|
+
self._start_next_command()
|
|
1060
1077
|
|
|
1061
1078
|
def _set_busy(self, busy: bool) -> None:
|
|
1062
1079
|
"""Track in-flight work and keep the frame loop alive while it runs.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
"""Messages between sessions:
|
|
1
|
+
"""Messages between sessions: receiving one as a turn, and what the broker knows about this one.
|
|
2
2
|
|
|
3
3
|
Another ZettCode session reaches this one through the broker (:mod:`zettcode.broker`), and this
|
|
4
|
-
one reaches it. The shell's part is small, because a
|
|
5
|
-
reader typed:
|
|
4
|
+
one reaches it through the model. The shell's receiving part is small, because a message is meant to
|
|
5
|
+
behave like one the reader typed:
|
|
6
6
|
|
|
7
7
|
* **Idle** — it starts a turn at once, drawn as a message from that session and not as the reader's
|
|
8
8
|
own, and everything after is an ordinary turn: the wait row, the answer, the summary of what
|
|
@@ -10,9 +10,10 @@ reader typed:
|
|
|
10
10
|
* **Busy** — it waits, and starts when the request in flight ends, after what the reader queued. It
|
|
11
11
|
never steers the request: it came from somebody else, and "change what you are doing" is the
|
|
12
12
|
reader's to say.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
|
|
14
|
+
The shell sends nothing itself. ``@name`` in a draft is resolved like any other reference
|
|
15
|
+
(:mod:`zettcode.mentions`): the model reads which session it means and how to reach it, and calls
|
|
16
|
+
``send_message`` itself when the request calls for one.
|
|
16
17
|
|
|
17
18
|
The session also tells the broker what it is — its id, title, and whether it is busy — whenever one
|
|
18
19
|
of them changes, so the others see a current list. None of this can fail the shell: with no broker the
|
|
@@ -22,29 +23,20 @@ shell is exactly what it was.
|
|
|
22
23
|
from __future__ import annotations
|
|
23
24
|
|
|
24
25
|
import asyncio
|
|
25
|
-
from collections.abc import Sequence
|
|
26
26
|
from typing import TYPE_CHECKING
|
|
27
27
|
|
|
28
|
-
from zettcode.broker.client import Receipt
|
|
29
|
-
from zettcode.broker.protocol import MAX_TEXT, VIA_USER
|
|
30
|
-
from zettcode.mentions import MENTION
|
|
31
|
-
from zettcode.prompt import PromptPart, carries_image, plain_text
|
|
28
|
+
from zettcode.broker.client import Receipt
|
|
32
29
|
from zettcode.relay import Relayed
|
|
33
30
|
|
|
34
31
|
from .shell import ShellState
|
|
35
32
|
|
|
36
33
|
if TYPE_CHECKING: # pragma: no cover - annotations only
|
|
37
|
-
from zettcode.broker.client import RosterEntry
|
|
38
|
-
|
|
39
34
|
from ..agent.agent import SessionLink
|
|
40
35
|
|
|
41
36
|
#: Messages from other sessions that may wait for a request to end. A session that is flooded refuses
|
|
42
37
|
#: the rest, and the sender is told why, instead of this shell holding an unbounded list.
|
|
43
38
|
MAX_INBOX = 16
|
|
44
39
|
|
|
45
|
-
#: Characters that may separate ``@name`` from the message it addresses: ``@bob: hi`` and ``@bob, hi``.
|
|
46
|
-
_SEPARATORS = " \t\r\n,:;"
|
|
47
|
-
|
|
48
40
|
#: Characters of a waiting message that the notice repeats, so the reader can tell which one it is.
|
|
49
41
|
_PREVIEW = 60
|
|
50
42
|
|
|
@@ -56,8 +48,6 @@ class MessagingMixin(ShellState):
|
|
|
56
48
|
messenger: SessionLink | None
|
|
57
49
|
#: Messages from other sessions waiting for the request in flight to end, oldest first.
|
|
58
50
|
_inbox: list[Relayed]
|
|
59
|
-
#: Sends in flight, held so they are not collected and can be cancelled on exit.
|
|
60
|
-
_sends: set[asyncio.Task[None]]
|
|
61
51
|
#: Whether the connection has been started; before that there is no loop to tell it anything on.
|
|
62
52
|
_messaging_live: bool
|
|
63
53
|
#: The session id the broker was last told about, to notice a switch.
|
|
@@ -82,14 +72,9 @@ class MessagingMixin(ShellState):
|
|
|
82
72
|
self._messaging_start = asyncio.ensure_future(messenger.start())
|
|
83
73
|
|
|
84
74
|
async def _stop_messaging(self) -> None:
|
|
85
|
-
"""Leave the broker
|
|
75
|
+
"""Leave the broker. Nothing here may delay leaving."""
|
|
86
76
|
messenger = self.messenger
|
|
87
77
|
self._messaging_live = False
|
|
88
|
-
sends = tuple(self._sends)
|
|
89
|
-
for send in sends:
|
|
90
|
-
send.cancel()
|
|
91
|
-
if sends:
|
|
92
|
-
await asyncio.gather(*sends, return_exceptions=True)
|
|
93
78
|
start = self._messaging_start
|
|
94
79
|
if start is not None:
|
|
95
80
|
await asyncio.gather(start, return_exceptions=True)
|
|
@@ -179,68 +164,3 @@ class MessagingMixin(ShellState):
|
|
|
179
164
|
return False
|
|
180
165
|
self._start_relayed(self._inbox.pop(0))
|
|
181
166
|
return True
|
|
182
|
-
|
|
183
|
-
# -- sending ----------------------------------------------------------------------------------
|
|
184
|
-
def _session_message(self, parts: Sequence[PromptPart]) -> tuple[str, str] | None:
|
|
185
|
-
"""Return ``(name, text)`` when a draft is addressed to an active session, else ``None``.
|
|
186
|
-
|
|
187
|
-
A draft is addressed when its first word is ``@name`` and ``name`` is the handle of a session
|
|
188
|
-
that is active now. Anything else — a name nobody has, a name in the middle, a file path — is an
|
|
189
|
-
ordinary draft for the model.
|
|
190
|
-
"""
|
|
191
|
-
messenger = self.messenger
|
|
192
|
-
if messenger is None:
|
|
193
|
-
return None
|
|
194
|
-
text = plain_text(parts).lstrip()
|
|
195
|
-
match = MENTION.match(text)
|
|
196
|
-
if match is None:
|
|
197
|
-
return None
|
|
198
|
-
peer = messenger.find(match.group(1))
|
|
199
|
-
if peer is None:
|
|
200
|
-
return None
|
|
201
|
-
return peer.handle, text[match.end() :].lstrip(_SEPARATORS).rstrip()
|
|
202
|
-
|
|
203
|
-
def _send_session_message(self, parts: Sequence[PromptPart]) -> bool | None:
|
|
204
|
-
"""Send a draft addressed to a session, or say why it cannot be.
|
|
205
|
-
|
|
206
|
-
Returns:
|
|
207
|
-
``None`` when the draft is not addressed to a session and the caller should treat it as any
|
|
208
|
-
other; otherwise what :meth:`submit` returns — ``True`` when the draft was taken and the
|
|
209
|
-
composer should clear, ``False`` when it was not and the draft stays to be fixed.
|
|
210
|
-
"""
|
|
211
|
-
found = self._session_message(parts)
|
|
212
|
-
if found is None:
|
|
213
|
-
return None
|
|
214
|
-
name, text = found
|
|
215
|
-
if carries_image(parts):
|
|
216
|
-
self.flash(f"a message to @{name} is text only", level="error")
|
|
217
|
-
return False
|
|
218
|
-
if not text:
|
|
219
|
-
self.flash(f"write the message after @{name}", level="error")
|
|
220
|
-
return False
|
|
221
|
-
if len(text) > MAX_TEXT:
|
|
222
|
-
self.flash(f"a message is limited to {MAX_TEXT} characters; this is {len(text)}", level="error")
|
|
223
|
-
return False
|
|
224
|
-
peer = self.messenger.find(name) if self.messenger is not None else None
|
|
225
|
-
if peer is None: # went away between the two lookups: nothing was addressed
|
|
226
|
-
return None
|
|
227
|
-
task = asyncio.create_task(self._deliver(peer, text))
|
|
228
|
-
self._sends.add(task)
|
|
229
|
-
task.add_done_callback(self._sends.discard)
|
|
230
|
-
return True
|
|
231
|
-
|
|
232
|
-
async def _deliver(self, peer: RosterEntry, text: str) -> None:
|
|
233
|
-
"""Send one message and put the outcome in the conversation: the message, or why it was not taken."""
|
|
234
|
-
messenger = self.messenger
|
|
235
|
-
if messenger is None:
|
|
236
|
-
return
|
|
237
|
-
try:
|
|
238
|
-
delivered = await messenger.send(peer.session_id, text, via=VIA_USER)
|
|
239
|
-
except SendError as error:
|
|
240
|
-
self.transcript.error(f"not sent to @{peer.handle}: {error}")
|
|
241
|
-
except Exception as error: # noqa: BLE001 - a bug here must not be silent, and must not end the shell
|
|
242
|
-
self.transcript.error(f"not sent to @{peer.handle}: {type(error).__name__}")
|
|
243
|
-
else:
|
|
244
|
-
note = "queued" if delivered.disposition == "queued" else "delivered"
|
|
245
|
-
self.transcript.sent_message(delivered.to.handle, text, note)
|
|
246
|
-
self.app.invalidate()
|
|
@@ -246,6 +246,10 @@ class ShellState:
|
|
|
246
246
|
def submit(self, value: str, *, command: bool | None = None) -> bool | None:
|
|
247
247
|
"""Start a turn, steer the running one, or run a slash command (``command``: whether the draft is one)."""
|
|
248
248
|
|
|
249
|
+
async def prompt(self, text: str) -> bool:
|
|
250
|
+
"""Run ``text`` as one turn, as if the reader had typed it; whether one was started and has ended."""
|
|
251
|
+
return False
|
|
252
|
+
|
|
249
253
|
def flash(self, message: str, *, seconds: float = FLASH_SECONDS, level: str = "info") -> None:
|
|
250
254
|
"""Say something in the row above the composer, for a few seconds."""
|
|
251
255
|
|
|
@@ -461,8 +461,8 @@ class ZettCodeConfig:
|
|
|
461
461
|
shell_network: Let a command that runs in the ``safe`` sandbox use the network. Off by default; ``[shell]
|
|
462
462
|
network = true`` turns it on. ``full`` always has the network, and so does a machine with no sandbox.
|
|
463
463
|
sessions_enabled: Register with the background session broker, so this session can be
|
|
464
|
-
messaged by the others and message them: ``@name`` in the composer
|
|
465
|
-
``send_message`` and ``list_sessions`` tools.
|
|
464
|
+
messaged by the others and message them: ``@name`` in the composer names a
|
|
465
|
+
session for the model, and the ``send_message`` and ``list_sessions`` tools reach it.
|
|
466
466
|
update_enabled: Ask PyPI, in the background, whether a newer release
|
|
467
467
|
exists, and offer it on a later start.
|
|
468
468
|
update_file: Where that check leaves what it found; one small JSON file.
|
|
@@ -173,9 +173,9 @@ class SkillMentions(MentionProvider):
|
|
|
173
173
|
class SessionMentions(MentionProvider):
|
|
174
174
|
"""The other ZettCode sessions that are running, addressed by the name they are listed under.
|
|
175
175
|
|
|
176
|
-
A
|
|
177
|
-
|
|
178
|
-
|
|
176
|
+
A session named anywhere in a draft is a reference like any other: the model reads ``session "name"``
|
|
177
|
+
and is told how to reach that session, and decides for itself whether the request calls for a message.
|
|
178
|
+
The shell sends nothing itself (see :mod:`zettcode.app.ui.messaging`).
|
|
179
179
|
|
|
180
180
|
Candidates are read from what the connection last reported — a list in memory — and never from
|
|
181
181
|
the broker: completion runs on every keystroke after an ``@``.
|
|
@@ -240,11 +240,11 @@ class SessionMentions(MentionProvider):
|
|
|
240
240
|
return next((peer for peer in self._peers() if peer.handle == name), None)
|
|
241
241
|
|
|
242
242
|
def expand(self, name: str) -> str | None:
|
|
243
|
-
"""Tell the model what the reader's ``@`` meant
|
|
243
|
+
"""Tell the model what the reader's ``@`` meant and how to reach that session.
|
|
244
244
|
|
|
245
245
|
Nothing is sent from here: the model is told which session the words mean and how to reach it, and
|
|
246
|
-
decides for itself whether the request calls for a message. A draft that
|
|
247
|
-
|
|
246
|
+
decides for itself whether the request calls for a message. A draft that begins with the name is no
|
|
247
|
+
different from one that names the session inside a sentence.
|
|
248
248
|
"""
|
|
249
249
|
peer = self._find(name)
|
|
250
250
|
if peer is None:
|
|
@@ -254,10 +254,11 @@ class SessionMentions(MentionProvider):
|
|
|
254
254
|
return (
|
|
255
255
|
f'In the message above, `session "{name}"` is what the user wrote as @{name}. In ZettCode an @ before a '
|
|
256
256
|
f"name means another ZettCode session that is running right now, not a file or a skill. This one works{where}.{about}\n"
|
|
257
|
-
f"
|
|
258
|
-
f
|
|
259
|
-
f
|
|
260
|
-
f"
|
|
257
|
+
f"When the user's message is addressed to that session — the @ begins the message — what follows the name "
|
|
258
|
+
f"is the message to pass on. When the session is only mentioned, decide whether the request is for it. "
|
|
259
|
+
f'To send, call the send_message tool: send_message(to="{peer.session_id}", message=...). Write the '
|
|
260
|
+
f"message so the other session can act on it without having seen this conversation. If the request is only "
|
|
261
|
+
f"about the session (what it is doing, where it is), list_sessions answers that. Do not send anything the "
|
|
261
262
|
f"user did not ask you to pass on."
|
|
262
263
|
)
|
|
263
264
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""A message from another session: who sent it, what the model reads, and how it is stored.
|
|
2
2
|
|
|
3
|
-
Another ZettCode session on the same machine can send this one a message
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Another ZettCode session on the same machine can send this one a message because its agent used the
|
|
4
|
+
``send_message`` tool. In *this* session the message is handled like one the reader typed — it is a
|
|
5
|
+
turn, it is stored, it is restored with the
|
|
6
6
|
session — with three differences, all of them here:
|
|
7
7
|
|
|
8
8
|
* the model is told where it came from, so it does not mistake a colleague's request for its own
|
|
@@ -628,7 +628,7 @@ class Client:
|
|
|
628
628
|
)
|
|
629
629
|
|
|
630
630
|
async def send(self, to: str, text: str) -> Delivered:
|
|
631
|
-
"""Send a message to another ZettCode session
|
|
631
|
+
"""Send a message to another ZettCode session without going through this session's model.
|
|
632
632
|
|
|
633
633
|
Args:
|
|
634
634
|
to: The session's handle, or its id.
|
|
@@ -570,7 +570,7 @@ def create_app(settings: Settings, *, client_factory: ClientFactory | None = Non
|
|
|
570
570
|
|
|
571
571
|
@protected.post("/sessions/current/send", response_model=SentOut, tags=["sessions"])
|
|
572
572
|
async def send_message(body: SendIn, runner: RunnerDep) -> SentOut:
|
|
573
|
-
"""Send a message to another ZettCode session,
|
|
573
|
+
"""Send a message to another ZettCode session explicitly, without a model turn."""
|
|
574
574
|
to, disposition = await runner.send(body.to, body.text)
|
|
575
575
|
return SentOut(to=to, disposition=disposition)
|
|
576
576
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/conversation/transcript/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/conversation/transcript/oneoff.py
RENAMED
|
File without changes
|
{zettcode-0.1.11 → zettcode-0.1.12}/src/zettcode/app/agent/conversation/transcript/stream.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|