zettcode 0.1.9__tar.gz → 0.1.11__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.9 → zettcode-0.1.11}/PKG-INFO +6 -3
- {zettcode-0.1.9 → zettcode-0.1.11}/pyproject.toml +8 -2
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/__init__.py +6 -6
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/__init__.py +5 -5
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/agent/__init__.py +6 -5
- zettcode-0.1.11/src/zettcode/app/agent/agent/__init__.py +69 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/agent/agent/commands.py +32 -19
- zettcode-0.1.11/src/zettcode/app/agent/agent/settings.py +132 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/agent/conversation/entries.py +3 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/agent/conversation/presenters.py +22 -8
- zettcode-0.1.11/src/zettcode/app/agent/conversation/projection.py +216 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/agent/conversation/rendering.py +59 -3
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/agent/conversation/replay.py +42 -18
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/agent/conversation/text.py +63 -1
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/agent/conversation/tips.py +4 -1
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/agent/conversation/transcript/stream.py +18 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/agent/conversation/transcript/turn.py +5 -2
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/commands.py +17 -8
- zettcode-0.1.11/src/zettcode/app/plugins/__init__.py +111 -0
- {zettcode-0.1.9/src/zettcode → zettcode-0.1.11/src/zettcode/app}/plugins/builtin_commands.py +101 -51
- {zettcode-0.1.9/src/zettcode → zettcode-0.1.11/src/zettcode/app}/plugins/builtins.py +57 -63
- {zettcode-0.1.9/src/zettcode → zettcode-0.1.11/src/zettcode/app}/plugins/container.py +43 -209
- zettcode-0.1.11/src/zettcode/app/plugins/host.py +36 -0
- zettcode-0.1.11/src/zettcode/app/plugins/loader.py +152 -0
- zettcode-0.1.11/src/zettcode/app/plugins/mixins.py +67 -0
- zettcode-0.1.11/src/zettcode/app/plugins/plugin.py +64 -0
- {zettcode-0.1.9/src/zettcode → zettcode-0.1.11/src/zettcode/app}/plugins/state.py +46 -61
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/app.py +137 -74
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/bars.py +15 -15
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/commands.py +24 -11
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/config_form.py +65 -10
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/followups.py +16 -10
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/keys.py +31 -3
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/labels.py +19 -2
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/messaging.py +8 -8
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/notices.py +25 -32
- zettcode-0.1.11/src/zettcode/app/ui/providers.py +615 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/sessions.py +71 -50
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/settings.py +17 -15
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/shell.py +17 -16
- zettcode-0.1.11/src/zettcode/app/ui/turns.py +101 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/__init__.py +14 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/approval_page.py +9 -9
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/ask_page.py +2 -2
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/completer.py +4 -5
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/composer.py +2 -2
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/context_charts.py +2 -1
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/context_page.py +1 -1
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/follow_up.py +4 -6
- zettcode-0.1.11/src/zettcode/app/ui/widgets/form_page.py +380 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/model_page.py +9 -9
- zettcode-0.1.11/src/zettcode/app/ui/widgets/model_settings_page.py +654 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/pet.py +44 -19
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/sessions_page.py +9 -9
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/statusline_page.py +59 -38
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/transcript.py +47 -1
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/usage_charts.py +43 -33
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/usage_page.py +27 -9
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/broker/finder.py +33 -11
- zettcode-0.1.11/src/zettcode/budget.py +24 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/cli.py +193 -30
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/config.py +196 -14
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/config_edit.py +27 -1
- zettcode-0.1.11/src/zettcode/daemon/__init__.py +14 -0
- zettcode-0.1.11/src/zettcode/daemon/__main__.py +10 -0
- zettcode-0.1.11/src/zettcode/daemon/cli.py +314 -0
- zettcode-0.1.11/src/zettcode/daemon/process.py +270 -0
- zettcode-0.1.11/src/zettcode/daemon/run.py +321 -0
- zettcode-0.1.11/src/zettcode/daemon/state.py +302 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/doctor.py +1 -1
- zettcode-0.1.11/src/zettcode/engine/__init__.py +42 -0
- zettcode-0.1.11/src/zettcode/engine/agent/__init__.py +75 -0
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/agent/base.py +9 -3
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/agent/context.py +5 -4
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/agent/exports.py +3 -2
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/agent/interaction.py +2 -1
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/agent/sessions.py +23 -41
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/agent/settings.py +13 -90
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/agent/turns.py +5 -4
- zettcode-0.1.9/src/zettcode/app/agent/runtime.py → zettcode-0.1.11/src/zettcode/engine/core.py +139 -51
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/dialogue/ask.py +17 -0
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/dialogue/side.py +11 -2
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/export/__init__.py +3 -2
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/extensions/__init__.py +1 -1
- zettcode-0.1.11/src/zettcode/engine/extensions/capabilities.py +68 -0
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/extensions/compaction.py +1 -1
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/extensions/context.py +2 -18
- zettcode-0.1.11/src/zettcode/engine/extensions/files.py +101 -0
- zettcode-0.1.11/src/zettcode/engine/extensions/harness.py +89 -0
- zettcode-0.1.11/src/zettcode/engine/extensions/harness_switch.py +18 -0
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/extensions/mcp.py +2 -1
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/extensions/messaging.py +2 -3
- zettcode-0.1.11/src/zettcode/engine/extensions/relay.py +93 -0
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/extensions/subagents.py +96 -22
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/extensions/tool_output.py +8 -7
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/extensions/usage.py +12 -58
- {zettcode-0.1.9/src/zettcode/app/agent/extensions → zettcode-0.1.11/src/zettcode/engine}/messenger.py +1 -2
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/permission/__init__.py +47 -15
- zettcode-0.1.11/src/zettcode/engine/permission/sandbox.py +124 -0
- zettcode-0.1.11/src/zettcode/engine/plugins/__init__.py +64 -0
- {zettcode-0.1.9/src/zettcode → zettcode-0.1.11/src/zettcode/engine}/plugins/builtin_agent.py +164 -39
- zettcode-0.1.11/src/zettcode/engine/plugins/container.py +223 -0
- {zettcode-0.1.9/src/zettcode → zettcode-0.1.11/src/zettcode/engine}/plugins/extension.py +2 -2
- {zettcode-0.1.9/src/zettcode → zettcode-0.1.11/src/zettcode/engine}/plugins/loader.py +88 -111
- {zettcode-0.1.9/src/zettcode → zettcode-0.1.11/src/zettcode/engine}/plugins/mixins.py +1 -59
- {zettcode-0.1.9/src/zettcode → zettcode-0.1.11/src/zettcode/engine}/plugins/plugin.py +29 -51
- {zettcode-0.1.9/src/zettcode → zettcode-0.1.11/src/zettcode/engine}/plugins/services.py +1 -30
- zettcode-0.1.11/src/zettcode/engine/plugins/state.py +64 -0
- zettcode-0.1.11/src/zettcode/engine/server_tools.py +157 -0
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/storage/ledger.py +1 -1
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/storage/metadata.py +7 -2
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/storage/records.py +3 -1
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/storage/store.py +49 -2
- zettcode-0.1.11/src/zettcode/engine/tools/__init__.py +7 -0
- zettcode-0.1.11/src/zettcode/engine/tools/boundary.py +51 -0
- zettcode-0.1.11/src/zettcode/engine/tools/files.py +267 -0
- zettcode-0.1.11/src/zettcode/engine/tools/images.py +32 -0
- zettcode-0.1.11/src/zettcode/engine/tools/output.py +74 -0
- zettcode-0.1.11/src/zettcode/engine/tools/shell.py +171 -0
- zettcode-0.1.11/src/zettcode/engine/tools/workspace.py +268 -0
- zettcode-0.1.9/src/zettcode/app/agent/errors.py → zettcode-0.1.11/src/zettcode/error_text.py +3 -3
- {zettcode-0.1.9/src/zettcode/app/agent/dialogue → zettcode-0.1.11/src/zettcode}/mentions.py +2 -3
- zettcode-0.1.11/src/zettcode/oneshot.py +200 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/paths.py +5 -1
- {zettcode-0.1.9/src/zettcode/app/agent/agent → zettcode-0.1.11/src/zettcode}/prompt.py +1 -1
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/providers.py +6 -3
- {zettcode-0.1.9/src/zettcode/app → zettcode-0.1.11/src/zettcode}/registry.py +2 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/sdk/__init__.py +16 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/sdk/client.py +542 -70
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/sdk/errors.py +15 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/sdk/events.py +92 -14
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/sdk/handlers.py +3 -1
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/sdk/models.py +36 -19
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/sdk/session.py +162 -27
- zettcode-0.1.9/src/zettcode/sdk/_translate.py → zettcode-0.1.11/src/zettcode/sdk/translation.py +105 -8
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/sdk/types.py +135 -1
- zettcode-0.1.11/src/zettcode/server/__init__.py +33 -0
- zettcode-0.1.11/src/zettcode/server/app.py +654 -0
- zettcode-0.1.11/src/zettcode/server/cli.py +119 -0
- zettcode-0.1.11/src/zettcode/server/runner.py +724 -0
- zettcode-0.1.11/src/zettcode/server/schemas.py +628 -0
- zettcode-0.1.11/src/zettcode/server/serialize.py +334 -0
- zettcode-0.1.11/src/zettcode/server/settings.py +61 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/statusline.py +88 -3
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/__init__.py +3 -1
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/capabilities.py +6 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/core/theme.py +8 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/render/renderer.py +45 -7
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/theme_file.py +17 -7
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/widgets/textarea.py +1 -1
- zettcode-0.1.11/src/zettcode/wording.py +11 -0
- zettcode-0.1.9/src/zettcode/app/agent/agent/__init__.py +0 -75
- zettcode-0.1.9/src/zettcode/app/agent/conversation/projection.py +0 -230
- zettcode-0.1.9/src/zettcode/app/agent/extensions/capabilities.py +0 -50
- zettcode-0.1.9/src/zettcode/app/ui/providers.py +0 -567
- zettcode-0.1.9/src/zettcode/plugins/__init__.py +0 -112
- {zettcode-0.1.9 → zettcode-0.1.11}/.gitignore +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/README.md +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/_compat.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/agent/conversation/__init__.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/agent/conversation/changes.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/agent/conversation/effort_gauge.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/agent/conversation/pulse.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/agent/conversation/shimmer.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/agent/conversation/stops.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/agent/conversation/transcript/__init__.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/agent/conversation/transcript/fold.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/agent/conversation/transcript/log.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/agent/conversation/transcript/oneoff.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/brand.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/commandline/__init__.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/commandline/arguments.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/commandline/completion.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/commandline/history.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/commandline/runner.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/pets/__init__.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/pets/cat.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/pets/chibi.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/pets/dog.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/pets/kangaroo.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/pets/model.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/pets/penguin.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/pets/polarbear.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/pets/scarfy.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/pets/seagull.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/pets/slime.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/pets/snowbear.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/pets/sprout.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/pets/tiger.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/pets/whale.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/__init__.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/boot.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/clipboard.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/demo.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/gc_policy.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/updating.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/bash_page.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/effort_page.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/input_page.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/panel.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/pet_page.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/root.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/self_compact_page.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/send_kind_page.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/steering.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/update_page.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/app/ui/widgets/welcome.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/broker/__init__.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/broker/__main__.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/broker/client.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/broker/files.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/broker/hub.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/broker/log.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/broker/models.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/broker/process.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/broker/protocol.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/broker/roster.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/broker/runner.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/broker/server.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/broker/text.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/broker/web.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/collector.py +0 -0
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/dialogue/__init__.py +0 -0
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/dialogue/title.py +0 -0
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/export/trace/script.js +0 -0
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/export/trace/style.css +0 -0
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/export/trace/template.html +0 -0
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/extensions/mcp_notice.py +0 -0
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/permission/approval.py +0 -0
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/permission/readonly.py +0 -0
- {zettcode-0.1.9/src/zettcode/app → zettcode-0.1.11/src/zettcode/engine}/pipeline.py +0 -0
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/storage/__init__.py +0 -0
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/storage/layout.py +0 -0
- {zettcode-0.1.9/src/zettcode/app/agent → zettcode-0.1.11/src/zettcode/engine}/storage/locks.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/filelock.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/py.typed +0 -0
- {zettcode-0.1.9/src/zettcode/app/agent/dialogue → zettcode-0.1.11/src/zettcode}/relay.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/clipboard.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/console.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/core/__init__.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/core/app.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/core/events.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/core/focus.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/core/geometry.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/core/host.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/core/keymap.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/core/scheduler.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/core/screen.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/core/widget.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/gallery.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/glyphs.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/input/__init__.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/input/bridge.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/input/decoder.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/input/events.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/input/keys.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/input/reader.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/layout/__init__.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/layout/box.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/layout/overlay.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/layout/scroll.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/layout/solver.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/layout/spacing.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/render/__init__.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/render/ansi.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/render/canvas.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/render/code.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/render/color.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/render/rich_text.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/render/style.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/render/sweep.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/render/text.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/runner.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/terminal.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/testing/__init__.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/testing/harness.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/testing/snapshot.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/themes/ayu-mirage.toml +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/themes/catppuccin-latte.toml +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/themes/catppuccin-mocha.toml +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/themes/dracula.toml +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/themes/github-dimmed.toml +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/themes/github-light.toml +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/themes/gruvbox-dark.toml +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/themes/gruvbox-light.toml +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/themes/kanagawa.toml +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/themes/nord.toml +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/themes/one-dark.toml +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/themes/rose-pine-dawn.toml +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/themes/rose-pine.toml +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/themes/solarized-dark.toml +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/themes/solarized-light.toml +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/themes/tokyo-night.toml +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/widgets/__init__.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/widgets/collapsible.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/widgets/completion.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/widgets/console.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/widgets/dialog.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/widgets/diff.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/widgets/list.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/widgets/list_page.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/widgets/markdown.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/widgets/progress.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/widgets/rich_text.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/widgets/status.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/widgets/table.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/widgets/tasks.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/widgets/text.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/tui/widgets/toast.py +0 -0
- {zettcode-0.1.9 → zettcode-0.1.11}/src/zettcode/update.py +0 -0
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: zettcode
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.11
|
|
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
|
Author: Chang-LeHung
|
|
8
8
|
License-Expression: MIT
|
|
9
9
|
Keywords: agent,coding-agent,llm,terminal,tui
|
|
10
|
-
Classifier: Development Status ::
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
11
|
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Environment :: Web Environment
|
|
13
|
+
Classifier: Framework :: FastAPI
|
|
12
14
|
Classifier: Operating System :: MacOS
|
|
13
15
|
Classifier: Operating System :: Microsoft :: Windows :: Windows 10
|
|
14
16
|
Classifier: Operating System :: POSIX :: Linux
|
|
@@ -21,6 +23,7 @@ Classifier: Programming Language :: Python :: 3.15
|
|
|
21
23
|
Classifier: Typing :: Typed
|
|
22
24
|
Requires-Python: >=3.10
|
|
23
25
|
Requires-Dist: exceptiongroup<2,>=1.2; python_version < '3.11'
|
|
26
|
+
Requires-Dist: fastapi<1,>=0.115
|
|
24
27
|
Requires-Dist: httpx<1,>=0.27
|
|
25
28
|
Requires-Dist: pydantic<3,>=2
|
|
26
29
|
Requires-Dist: pyperclip<2,>=1.9
|
|
@@ -32,7 +35,7 @@ Requires-Dist: truststore<1,>=0.10
|
|
|
32
35
|
Requires-Dist: uvicorn<1,>=0.35
|
|
33
36
|
Requires-Dist: wcwidth<1,>=0.2
|
|
34
37
|
Requires-Dist: websockets<17,>=15
|
|
35
|
-
Requires-Dist: zett-agent<0.
|
|
38
|
+
Requires-Dist: zett-agent<0.3,>=0.2.0
|
|
36
39
|
Description-Content-Type: text/markdown
|
|
37
40
|
|
|
38
41
|
# ZettCode
|
|
@@ -8,8 +8,10 @@ license = "MIT"
|
|
|
8
8
|
authors = [{name = "Chang-LeHung"}]
|
|
9
9
|
keywords = ["agent", "llm", "tui", "terminal", "coding-agent"]
|
|
10
10
|
classifiers = [
|
|
11
|
-
"Development Status ::
|
|
11
|
+
"Development Status :: 5 - Production/Stable",
|
|
12
12
|
"Environment :: Console",
|
|
13
|
+
"Environment :: Web Environment",
|
|
14
|
+
"Framework :: FastAPI",
|
|
13
15
|
"Operating System :: MacOS",
|
|
14
16
|
"Operating System :: Microsoft :: Windows :: Windows 10",
|
|
15
17
|
"Operating System :: POSIX :: Linux",
|
|
@@ -36,6 +38,9 @@ dependencies = [
|
|
|
36
38
|
"uvicorn>=0.35,<1",
|
|
37
39
|
"httpx>=0.27,<1",
|
|
38
40
|
"websockets>=15,<17",
|
|
41
|
+
# The HTTP server is part of this package and always installed: `pip install zettcode` writes both console
|
|
42
|
+
# scripts, so `zettcode-server` may not be a command whose dependencies are an optional extra.
|
|
43
|
+
"fastapi>=0.115,<1",
|
|
39
44
|
# The counter behind ``/context`` measures a request with it, and imports it
|
|
40
45
|
# itself: the floor matches the runtime's, so neither resolver has to fight.
|
|
41
46
|
"tiktoken>=0.12,<1",
|
|
@@ -53,11 +58,12 @@ dependencies = [
|
|
|
53
58
|
# than it did. An exact pin would make zettcode fight every other tool that
|
|
54
59
|
# shares the dependency — including an upgrade of zett-agent itself, which pip
|
|
55
60
|
# would downgrade to satisfy it.
|
|
56
|
-
"zett-agent>=0.
|
|
61
|
+
"zett-agent>=0.2.0,<0.3",
|
|
57
62
|
]
|
|
58
63
|
|
|
59
64
|
[project.scripts]
|
|
60
65
|
zettcode = "zettcode.cli:main"
|
|
66
|
+
zettcode-server = "zettcode.server.cli:main"
|
|
61
67
|
|
|
62
68
|
[project.urls]
|
|
63
69
|
Repository = "https://github.com/Chang-LeHung/zettcode"
|
|
@@ -7,21 +7,21 @@ 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.11"
|
|
11
11
|
|
|
12
12
|
#: Where each public name lives; read by :func:`__getattr__` on first use.
|
|
13
13
|
_EXPORTS = {
|
|
14
14
|
"ModelConfig": ".config",
|
|
15
|
-
"ZettCodeAgent": ".
|
|
15
|
+
"ZettCodeAgent": ".engine.agent",
|
|
16
16
|
"ZettCodeConfig": ".config",
|
|
17
|
-
"
|
|
17
|
+
"ZettCodeEngine": ".engine.core",
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
if TYPE_CHECKING: # pragma: no cover - for type checkers, not the runtime
|
|
22
|
-
from .app.agent.agent import ZettCodeAgent
|
|
23
|
-
from .app.agent.runtime import ZettCodeRuntime
|
|
24
22
|
from .config import ModelConfig, ZettCodeConfig
|
|
23
|
+
from .engine.agent import ZettCodeAgent
|
|
24
|
+
from .engine.core import ZettCodeEngine
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
def __getattr__(name: str) -> object:
|
|
@@ -44,4 +44,4 @@ def __dir__() -> list[str]:
|
|
|
44
44
|
return sorted(__all__)
|
|
45
45
|
|
|
46
46
|
|
|
47
|
-
__all__ = ["ModelConfig", "ZettCodeAgent", "ZettCodeConfig", "
|
|
47
|
+
__all__ = ["ModelConfig", "ZettCodeAgent", "ZettCodeConfig", "ZettCodeEngine"]
|
|
@@ -18,15 +18,15 @@ _EXPORTS = {
|
|
|
18
18
|
"TranscriptProjector": ".agent",
|
|
19
19
|
"TranscriptSource": ".ui",
|
|
20
20
|
"TranscriptView": ".ui",
|
|
21
|
-
"
|
|
21
|
+
"TerminalAgent": ".agent",
|
|
22
22
|
"ZettCodeApp": ".ui",
|
|
23
23
|
"ZettCodeRoot": ".ui",
|
|
24
|
-
"
|
|
24
|
+
"ZettCodeEngine": ".agent",
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
if TYPE_CHECKING: # pragma: no cover - for type checkers, not the runtime
|
|
29
|
-
from .agent import Entry, Transcript, TranscriptProjector,
|
|
29
|
+
from .agent import Entry, TerminalAgent, Transcript, TranscriptProjector, ZettCodeEngine
|
|
30
30
|
from .ui import TranscriptSource, TranscriptView, ZettCodeApp, ZettCodeRoot
|
|
31
31
|
|
|
32
32
|
|
|
@@ -57,7 +57,7 @@ __all__ = [
|
|
|
57
57
|
"TranscriptSource",
|
|
58
58
|
"TranscriptView",
|
|
59
59
|
"ZettCodeApp",
|
|
60
|
-
"
|
|
60
|
+
"TerminalAgent",
|
|
61
61
|
"ZettCodeRoot",
|
|
62
|
-
"
|
|
62
|
+
"ZettCodeEngine",
|
|
63
63
|
]
|
|
@@ -10,17 +10,18 @@ _EXPORTS = {
|
|
|
10
10
|
"Entry": ".conversation.entries",
|
|
11
11
|
"Transcript": ".conversation.transcript",
|
|
12
12
|
"TranscriptProjector": ".conversation.projection",
|
|
13
|
-
"
|
|
14
|
-
"
|
|
13
|
+
"TerminalAgent": ".agent",
|
|
14
|
+
"ZettCodeEngine": "zettcode.engine.core",
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
if TYPE_CHECKING: # pragma: no cover - for type checkers, not the runtime
|
|
19
|
-
from .
|
|
19
|
+
from zettcode.engine.core import ZettCodeEngine
|
|
20
|
+
|
|
21
|
+
from .agent import TerminalAgent
|
|
20
22
|
from .conversation.entries import Entry
|
|
21
23
|
from .conversation.projection import TranscriptProjector
|
|
22
24
|
from .conversation.transcript import Transcript
|
|
23
|
-
from .runtime import ZettCodeRuntime
|
|
24
25
|
|
|
25
26
|
|
|
26
27
|
def __getattr__(name: str) -> object:
|
|
@@ -43,4 +44,4 @@ def __dir__() -> list[str]:
|
|
|
43
44
|
return sorted(__all__)
|
|
44
45
|
|
|
45
46
|
|
|
46
|
-
__all__ = ["Entry", "Transcript", "TranscriptProjector", "
|
|
47
|
+
__all__ = ["Entry", "Transcript", "TranscriptProjector", "TerminalAgent", "ZettCodeEngine"]
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""The terminal's agent: the engine's agent, plus the commands and preferences only a terminal has.
|
|
2
|
+
|
|
3
|
+
The engine's agent (:class:`zettcode.engine.agent.ZettCodeAgent`) does the work. This subclass adds what the shell
|
|
4
|
+
asks of it that is not work: the slash commands and what plugins contributed (``commands``), and the theme, the pet
|
|
5
|
+
and the status line the reader can change (``settings``). Its engine is built with the terminal's plugin loader, so
|
|
6
|
+
the commands, palettes, pets, presenters and rows of the plugins are there to be read.
|
|
7
|
+
|
|
8
|
+
This package is also where the terminal is put together from the engine's parts, so it is what names, for the views, the
|
|
9
|
+
engine objects they hold: ``SessionLink`` (the line to the other sessions) and ``StoredSession`` (a session read from
|
|
10
|
+
the store). The views import those names from here and not from the engine.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from typing import TYPE_CHECKING
|
|
16
|
+
|
|
17
|
+
from zettcode.engine.agent import ZettCodeAgent
|
|
18
|
+
from zettcode.engine.agent.sessions import StoredSession
|
|
19
|
+
from zettcode.engine.core import PluginLoader, ZettCodeEngine
|
|
20
|
+
from zettcode.engine.messenger import Messenger as SessionLink
|
|
21
|
+
|
|
22
|
+
from .commands import CommandsMixin
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING: # pragma: no cover - annotations only
|
|
25
|
+
from zettcode.config import ZettCodeConfig
|
|
26
|
+
from zettcode.sdk.client import Client
|
|
27
|
+
|
|
28
|
+
__all__ = ["SessionLink", "StoredSession", "TerminalAgent"]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _terminal_loader() -> PluginLoader:
|
|
32
|
+
"""Return the terminal's plugin loader, imported when an agent is built and not before."""
|
|
33
|
+
from zettcode.app.plugins.loader import terminal_plugins
|
|
34
|
+
|
|
35
|
+
return terminal_plugins
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class TerminalAgent(CommandsMixin, ZettCodeAgent):
|
|
39
|
+
"""The agent the terminal application drives."""
|
|
40
|
+
|
|
41
|
+
_client: Client | None = None
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def messenger(self) -> SessionLink | None:
|
|
45
|
+
"""Return the line to the other sessions, or ``None`` when the configuration switches messaging off."""
|
|
46
|
+
return self.runtime.messenger
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def client(self) -> Client:
|
|
50
|
+
"""Return the SDK client over this agent, which is how the shell reaches everything the SDK offers.
|
|
51
|
+
|
|
52
|
+
Made on first use and then kept, so the shell and the commands it runs read the same client. The agent still
|
|
53
|
+
owns closing: the client is a view of it.
|
|
54
|
+
"""
|
|
55
|
+
if self._client is None:
|
|
56
|
+
from zettcode.sdk.client import Client
|
|
57
|
+
|
|
58
|
+
self._client = Client._around(self)
|
|
59
|
+
return self._client
|
|
60
|
+
|
|
61
|
+
@classmethod
|
|
62
|
+
async def create(cls, config: ZettCodeConfig) -> TerminalAgent:
|
|
63
|
+
"""Build the engine with the terminal's plugins and start it."""
|
|
64
|
+
return cls(await ZettCodeEngine.create(config, _terminal_loader()))
|
|
65
|
+
|
|
66
|
+
@classmethod
|
|
67
|
+
def preview(cls, config: ZettCodeConfig) -> TerminalAgent:
|
|
68
|
+
"""Wrap an engine that still has to start, built with the terminal's plugins, so the shell can paint first."""
|
|
69
|
+
return cls(ZettCodeEngine.preview(config, _terminal_loader()))
|
|
@@ -9,23 +9,32 @@ from __future__ import annotations
|
|
|
9
9
|
|
|
10
10
|
from zettcode.app.commands import Command, CommandContext, CommandHost, CommandResult
|
|
11
11
|
from zettcode.app.pets import PetCatalog, bundled_pets
|
|
12
|
-
from zettcode.plugins import
|
|
13
|
-
from zettcode.plugins.
|
|
12
|
+
from zettcode.app.plugins.host import HOST_LINK, HostLink
|
|
13
|
+
from zettcode.app.plugins.plugin import TerminalPlugins
|
|
14
|
+
from zettcode.app.plugins.state import TurnSegment, UiRow
|
|
15
|
+
from zettcode.engine.agent.exports import ExportsMixin
|
|
14
16
|
from zettcode.providers import BUILTIN_PROVIDERS, Provider, merge_providers
|
|
15
17
|
from zettcode.statusline import NAMES, unknown
|
|
16
18
|
from zettcode.tui import ThemeCatalog
|
|
17
19
|
|
|
18
20
|
from ..conversation.presenters import Presenters
|
|
19
|
-
from
|
|
20
|
-
from .exports import ExportsMixin
|
|
21
|
+
from .settings import AppearanceMixin
|
|
21
22
|
|
|
22
23
|
#: The words ``/self-compact`` takes after it, or after ``global``.
|
|
23
24
|
_SELF_COMPACT_WORDS = frozenset({"on", "off", "default"})
|
|
24
25
|
|
|
25
26
|
|
|
26
|
-
class CommandsMixin(ExportsMixin):
|
|
27
|
+
class CommandsMixin(AppearanceMixin, ExportsMixin):
|
|
27
28
|
"""The ``/new``, ``/compact``, and ``/export`` commands, and the plugins' commands, mentions, and rows."""
|
|
28
29
|
|
|
30
|
+
@property
|
|
31
|
+
def terminal_plugins(self) -> TerminalPlugins:
|
|
32
|
+
"""Return what the plugins contributed to the terminal; the engine was built with the terminal's loader."""
|
|
33
|
+
plugins = self.runtime.plugins
|
|
34
|
+
if not isinstance(plugins, TerminalPlugins):
|
|
35
|
+
raise TypeError("This agent's engine was not built with the terminal's plugin loader")
|
|
36
|
+
return plugins
|
|
37
|
+
|
|
29
38
|
@property
|
|
30
39
|
def commands(self) -> tuple[Command, ...]:
|
|
31
40
|
"""Return the conversation commands the agent owns.
|
|
@@ -52,17 +61,12 @@ class CommandsMixin(ExportsMixin):
|
|
|
52
61
|
The shell keeps them after everything built in, so a plugin cannot take over a built-in name;
|
|
53
62
|
plugin-versus-plugin duplicates are rejected when the plugins load.
|
|
54
63
|
"""
|
|
55
|
-
return self.
|
|
64
|
+
return self.terminal_plugins.installed_commands
|
|
56
65
|
|
|
57
66
|
@property
|
|
58
67
|
def builtin_plugin_commands(self) -> tuple[Command, ...]:
|
|
59
68
|
"""Return the commands the program's own plugins registered: ``/resume``, ``/model``, ``/usage`` and the rest."""
|
|
60
|
-
return self.
|
|
61
|
-
|
|
62
|
-
@property
|
|
63
|
-
def plugin_mentions(self) -> tuple[MentionProvider, ...]:
|
|
64
|
-
"""Return the ``@`` resource providers the installed plugins registered."""
|
|
65
|
-
return self.runtime.plugins.mentions
|
|
69
|
+
return self.terminal_plugins.builtin_commands
|
|
66
70
|
|
|
67
71
|
@property
|
|
68
72
|
def providers(self) -> tuple[Provider, ...]:
|
|
@@ -76,7 +80,7 @@ class CommandsMixin(ExportsMixin):
|
|
|
76
80
|
Built fresh each time it is asked: it lists names and builds nothing, and the reader's directory may have
|
|
77
81
|
gained a file since the last look.
|
|
78
82
|
"""
|
|
79
|
-
return ThemeCatalog(self.
|
|
83
|
+
return ThemeCatalog(self.terminal_plugins.themes, self.runtime.config.themes_dir)
|
|
80
84
|
|
|
81
85
|
@property
|
|
82
86
|
def pets(self) -> PetCatalog:
|
|
@@ -84,13 +88,18 @@ class CommandsMixin(ExportsMixin):
|
|
|
84
88
|
|
|
85
89
|
A plugin bundle that offers none (one built by hand, without the built-in plugin) gets the program's own.
|
|
86
90
|
"""
|
|
87
|
-
sources = self.
|
|
91
|
+
sources = self.terminal_plugins.pets
|
|
88
92
|
return PetCatalog(sources or bundled_pets())
|
|
89
93
|
|
|
94
|
+
@property
|
|
95
|
+
def turn_segments(self) -> tuple[TurnSegment, ...]:
|
|
96
|
+
"""Return the items of the line a request ends on, the program's own first, then the plugins'."""
|
|
97
|
+
return self.terminal_plugins.turn_segments
|
|
98
|
+
|
|
90
99
|
@property
|
|
91
100
|
def plugin_failures(self) -> tuple[str, ...]:
|
|
92
101
|
"""Return one message per plugin that could not be loaded or activated."""
|
|
93
|
-
return self.
|
|
102
|
+
return self.terminal_plugins.failures
|
|
94
103
|
|
|
95
104
|
@property
|
|
96
105
|
def presenters(self) -> Presenters:
|
|
@@ -100,12 +109,12 @@ class CommandsMixin(ExportsMixin):
|
|
|
100
109
|
program's own rows are registered through the plugin route, so a plugin that draws a kind or a family of
|
|
101
110
|
rows reaches the transcript without a second path only plugins could not take.
|
|
102
111
|
"""
|
|
103
|
-
return Presenters(self.
|
|
112
|
+
return Presenters(self.terminal_plugins.presenters)
|
|
104
113
|
|
|
105
114
|
@property
|
|
106
115
|
def plugin_rows(self) -> tuple[UiRow, ...]:
|
|
107
116
|
"""Return the header and status rows plugins asked the shell to draw."""
|
|
108
|
-
return self.
|
|
117
|
+
return self.terminal_plugins.rows
|
|
109
118
|
|
|
110
119
|
async def _command_new(self, context: CommandContext) -> CommandResult:
|
|
111
120
|
"""Start a fresh session."""
|
|
@@ -174,10 +183,14 @@ class CommandsMixin(ExportsMixin):
|
|
|
174
183
|
|
|
175
184
|
def statusline_summary(self) -> str:
|
|
176
185
|
"""Say in one line which parts of the header and the status line are hidden."""
|
|
177
|
-
hidden = [
|
|
186
|
+
hidden = [
|
|
187
|
+
*(name for name in NAMES if name in self.statusline_hidden),
|
|
188
|
+
*sorted(self.statusline_hidden - set(NAMES)),
|
|
189
|
+
]
|
|
178
190
|
if not hidden:
|
|
179
191
|
return "Status line: every part is shown"
|
|
180
|
-
|
|
192
|
+
total = len(NAMES) + len({item.name for item in self.turn_segments} - set(NAMES))
|
|
193
|
+
return f"Status line: {len(hidden)} of {total} parts hidden ({', '.join(hidden)})"
|
|
181
194
|
|
|
182
195
|
def change_statusline(self, argument: str) -> str:
|
|
183
196
|
"""Hide or show parts of the header and status line from the words ``/statusline`` takes.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""What the reader can change about how the terminal looks: theme, pet, which parts of the status line are shown.
|
|
2
|
+
|
|
3
|
+
These are the terminal's own preferences. They are kept in the same config file as the engine's settings, and are
|
|
4
|
+
written the same way, which is why this reads the file through the engine's helpers.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from collections.abc import Mapping
|
|
10
|
+
from dataclasses import replace
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
from zettcode.config_edit import (
|
|
14
|
+
ConfigEditError,
|
|
15
|
+
set_pet,
|
|
16
|
+
set_pet_position,
|
|
17
|
+
set_statusline,
|
|
18
|
+
set_theme,
|
|
19
|
+
write_text_atomically,
|
|
20
|
+
)
|
|
21
|
+
from zettcode.engine.agent.settings import SettingsMixin
|
|
22
|
+
from zettcode.statusline import NAMES
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class AppearanceMixin(SettingsMixin):
|
|
26
|
+
"""Read and remember the terminal's theme, pet and status line."""
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def reduced_motion(self) -> bool:
|
|
30
|
+
"""Return whether decorative animation is disabled."""
|
|
31
|
+
return self.runtime.config.reduced_motion
|
|
32
|
+
|
|
33
|
+
def remember_theme(self, name: str) -> Path:
|
|
34
|
+
"""Write ``[ui] theme = name`` into the config file, so the next start opens in that palette.
|
|
35
|
+
|
|
36
|
+
Only that line changes. A config file that does not exist is not created for it: a file with nothing but
|
|
37
|
+
``[ui]`` in it would stand where a reader's environment-variable setup is, and say nothing about models.
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
The file written.
|
|
41
|
+
|
|
42
|
+
Raises:
|
|
43
|
+
ConfigEditError: When there is no config file, it cannot be read or edited safely, or it cannot be
|
|
44
|
+
written. Nothing is written then.
|
|
45
|
+
"""
|
|
46
|
+
text = set_theme(self._read_config_file(), name, where=self.config_file)
|
|
47
|
+
try:
|
|
48
|
+
write_text_atomically(self.config_file, text)
|
|
49
|
+
except OSError as error:
|
|
50
|
+
raise ConfigEditError(f"{self.config_file} could not be written: {error}") from error
|
|
51
|
+
return self.config_file
|
|
52
|
+
|
|
53
|
+
def remember_pet(self, name: str) -> Path:
|
|
54
|
+
"""Write ``[ui] pet = name`` into the config file, so the next start opens with that pet.
|
|
55
|
+
|
|
56
|
+
Only that line changes, and a config file that does not exist is not created for it. The pet in force
|
|
57
|
+
for this run is the shell's to switch; what this keeps up to date is the setting the shell reads back.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
The file written.
|
|
61
|
+
|
|
62
|
+
Raises:
|
|
63
|
+
ConfigEditError: When there is no config file, it cannot be read or edited safely, or it cannot be
|
|
64
|
+
written. Nothing is written then.
|
|
65
|
+
"""
|
|
66
|
+
text = set_pet(self._read_config_file(), name, where=self.config_file)
|
|
67
|
+
try:
|
|
68
|
+
write_text_atomically(self.config_file, text)
|
|
69
|
+
except OSError as error:
|
|
70
|
+
raise ConfigEditError(f"{self.config_file} could not be written: {error}") from error
|
|
71
|
+
self.runtime.config = replace(self.runtime.config, pet=name)
|
|
72
|
+
return self.config_file
|
|
73
|
+
|
|
74
|
+
def remember_pet_position(self, across: float, down: float) -> Path:
|
|
75
|
+
"""Write ``[ui] pet_position`` into the config file, so the next start puts the pet back where it was left.
|
|
76
|
+
|
|
77
|
+
The file is global to the reader (``~/.zettcode/config.toml``), not to a project: a pet is the reader's
|
|
78
|
+
companion, and it does not move house when they open another folder. Only that line changes, and a
|
|
79
|
+
config file that does not exist is not created for it.
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
The file written.
|
|
83
|
+
|
|
84
|
+
Raises:
|
|
85
|
+
ConfigEditError: When there is no config file, it cannot be read or edited safely, or it cannot be
|
|
86
|
+
written. Nothing is written then.
|
|
87
|
+
"""
|
|
88
|
+
text = set_pet_position(self._read_config_file(), across, down, where=self.config_file)
|
|
89
|
+
try:
|
|
90
|
+
write_text_atomically(self.config_file, text)
|
|
91
|
+
except OSError as error:
|
|
92
|
+
raise ConfigEditError(f"{self.config_file} could not be written: {error}") from error
|
|
93
|
+
position = (round(min(1.0, max(0.0, across)), 3), round(min(1.0, max(0.0, down)), 3))
|
|
94
|
+
self.runtime.config = replace(self.runtime.config, pet_position=position)
|
|
95
|
+
return self.config_file
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def statusline_hidden(self) -> frozenset[str]:
|
|
99
|
+
"""Return the names of the header and status-line parts the reader switched off."""
|
|
100
|
+
return frozenset(self.runtime.config.statusline_hidden)
|
|
101
|
+
|
|
102
|
+
def remember_statusline(self, shown: Mapping[str, bool]) -> Path:
|
|
103
|
+
"""Write which parts of the header and status line are shown into ``[statusline]``.
|
|
104
|
+
|
|
105
|
+
Only the parts that differ from what is in force are written. The file is written first and the
|
|
106
|
+
running configuration changed second, so a write that fails leaves both as they were; the rows
|
|
107
|
+
follow at the next paint. A config file that does not exist is not created for it, as for the theme.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
shown: Part name to whether it is shown. A part left out keeps what it has.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
The file written.
|
|
114
|
+
|
|
115
|
+
Raises:
|
|
116
|
+
ConfigEditError: When there is no config file, it cannot be read or edited safely, or it cannot
|
|
117
|
+
be written.
|
|
118
|
+
"""
|
|
119
|
+
hidden = set(self.statusline_hidden)
|
|
120
|
+
changes = {name: visible for name, visible in shown.items() if (name not in hidden) != visible}
|
|
121
|
+
if not changes:
|
|
122
|
+
return self.config_file
|
|
123
|
+
text = set_statusline(self._read_config_file(), changes, where=self.config_file)
|
|
124
|
+
try:
|
|
125
|
+
write_text_atomically(self.config_file, text)
|
|
126
|
+
except OSError as error:
|
|
127
|
+
raise ConfigEditError(f"{self.config_file} could not be written: {error}") from error
|
|
128
|
+
hidden = {name for name in hidden if name not in changes} | {name for name, v in changes.items() if not v}
|
|
129
|
+
# The program's parts in their order, then the ones a plugin added (their names are not in NAMES).
|
|
130
|
+
ordered = (*(name for name in NAMES if name in hidden), *sorted(hidden - set(NAMES)))
|
|
131
|
+
self.runtime.config = replace(self.runtime.config, statusline_hidden=ordered)
|
|
132
|
+
return self.config_file
|
|
@@ -195,6 +195,9 @@ class WaitEntry(TimedEntry):
|
|
|
195
195
|
tips: tuple[str, ...] = ()
|
|
196
196
|
#: The line the request ended on, written when the row is settled.
|
|
197
197
|
text: str = ""
|
|
198
|
+
#: The items of the line, one string each, written with the line; the presenter joins them with the separator
|
|
199
|
+
#: and breaks the row between two, never inside one. Empty means the line is ``text`` alone.
|
|
200
|
+
parts: tuple[str, ...] = ()
|
|
198
201
|
|
|
199
202
|
|
|
200
203
|
@dataclass(slots=True, kw_only=True)
|
|
@@ -80,6 +80,7 @@ from .text import (
|
|
|
80
80
|
bounded_rows,
|
|
81
81
|
duration_text,
|
|
82
82
|
elapsed_text,
|
|
83
|
+
pack_segments,
|
|
83
84
|
quiet_text,
|
|
84
85
|
terminal_safe,
|
|
85
86
|
tip_text,
|
|
@@ -106,6 +107,8 @@ TOOL_ROLES = {
|
|
|
106
107
|
"view_image": "image",
|
|
107
108
|
"glob": "search",
|
|
108
109
|
"grep": "search",
|
|
110
|
+
"web_search": "web-search",
|
|
111
|
+
"ask_user": "ask-user",
|
|
109
112
|
"write_file": "write",
|
|
110
113
|
"edit": "write",
|
|
111
114
|
"replace_in_file": "write", # what a session stored before the rename called it
|
|
@@ -120,8 +123,12 @@ TOOL_ROLES = {
|
|
|
120
123
|
|
|
121
124
|
|
|
122
125
|
def tool_color(tool: str, theme: Theme) -> str:
|
|
123
|
-
"""Return the colour one tool paints its rows with.
|
|
124
|
-
|
|
126
|
+
"""Return the colour one tool paints its rows with.
|
|
127
|
+
|
|
128
|
+
A role spelled with a hyphen (``web-search``) names the theme field it stands for (``web_search``).
|
|
129
|
+
"""
|
|
130
|
+
role = TOOL_ROLES.get(tool, "").replace("-", "_")
|
|
131
|
+
return getattr(theme.tools, role, theme.accent)
|
|
125
132
|
|
|
126
133
|
|
|
127
134
|
#: The entry fields that are not part of how a row looks: its identity, and the
|
|
@@ -483,13 +490,15 @@ class WaitPresenter(Presenter[WaitEntry]):
|
|
|
483
490
|
"""
|
|
484
491
|
if not entry.running:
|
|
485
492
|
settled = entry.text or f"Processed for {elapsed_text(entry.duration or 0.0)}"
|
|
493
|
+
ink = Style(foreground=theme.muted)
|
|
494
|
+
room = max(1, width - CONTENT_INDENT)
|
|
495
|
+
packed = pack_segments(list(entry.parts) or settled.split(f" {SEPARATOR} "), room)
|
|
486
496
|
return [
|
|
487
497
|
TextLine(),
|
|
488
|
-
|
|
489
|
-
(TextLine((Span(" " * CONTENT_INDENT +
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
)[0],
|
|
498
|
+
*(
|
|
499
|
+
layout_rich_lines((TextLine((Span(" " * CONTENT_INDENT + row, ink),)),), width, wrap=False)[0]
|
|
500
|
+
for row in packed
|
|
501
|
+
),
|
|
493
502
|
]
|
|
494
503
|
spans = list(_running_label(entry.title, theme, frame))
|
|
495
504
|
if entry.duration is not None:
|
|
@@ -575,7 +584,12 @@ class ToolPresenter(Presenter[T]):
|
|
|
575
584
|
}.get(entry.status, STATUS)
|
|
576
585
|
)
|
|
577
586
|
hue = tool_color(entry.tool, theme)
|
|
578
|
-
|
|
587
|
+
# A failure is the error colour, and a row that did not happen at all — a skipped tool, a cancelled
|
|
588
|
+
# question — is a caution rather than a result, so it is amber and not the tool's own hue.
|
|
589
|
+
colour = {
|
|
590
|
+
EntryStatus.FAILED: theme.error,
|
|
591
|
+
EntryStatus.SKIPPED: theme.warning,
|
|
592
|
+
}.get(entry.status, hue)
|
|
579
593
|
marker = Style(foreground=colour)
|
|
580
594
|
label = Style(foreground=colour)
|
|
581
595
|
muted = Style(foreground=theme.muted)
|