zettcode 0.1.8__tar.gz → 0.1.9__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.8 → zettcode-0.1.9}/.gitignore +3 -0
- zettcode-0.1.9/PKG-INFO +60 -0
- zettcode-0.1.9/README.md +23 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/pyproject.toml +2 -47
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/__init__.py +1 -1
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/_compat.py +1 -1
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/extensions/mcp.py +14 -6
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/extensions/mcp_notice.py +15 -3
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/config.py +47 -2
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/sdk/__init__.py +38 -1
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/sdk/_translate.py +89 -5
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/sdk/client.py +136 -1
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/sdk/events.py +3 -0
- zettcode-0.1.9/src/zettcode/sdk/models.py +140 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/sdk/session.py +92 -22
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/sdk/types.py +183 -3
- zettcode-0.1.8/LICENSE +0 -21
- zettcode-0.1.8/PKG-INFO +0 -149
- zettcode-0.1.8/README.md +0 -112
- zettcode-0.1.8/README.zh-CN.md +0 -106
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/__init__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/__init__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/agent/__init__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/agent/base.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/agent/commands.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/agent/context.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/agent/exports.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/agent/interaction.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/agent/prompt.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/agent/sessions.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/agent/settings.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/agent/turns.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/conversation/__init__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/conversation/changes.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/conversation/effort_gauge.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/conversation/entries.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/conversation/presenters.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/conversation/projection.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/conversation/pulse.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/conversation/rendering.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/conversation/replay.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/conversation/shimmer.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/conversation/stops.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/conversation/text.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/conversation/tips.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/conversation/transcript/__init__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/conversation/transcript/fold.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/conversation/transcript/log.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/conversation/transcript/oneoff.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/conversation/transcript/stream.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/conversation/transcript/turn.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/dialogue/__init__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/dialogue/ask.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/dialogue/mentions.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/dialogue/relay.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/dialogue/side.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/dialogue/title.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/errors.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/export/__init__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/export/trace/script.js +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/export/trace/style.css +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/export/trace/template.html +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/extensions/__init__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/extensions/capabilities.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/extensions/compaction.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/extensions/context.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/extensions/messaging.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/extensions/messenger.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/extensions/subagents.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/extensions/tool_output.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/extensions/usage.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/permission/__init__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/permission/approval.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/permission/readonly.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/runtime.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/storage/__init__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/storage/layout.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/storage/ledger.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/storage/locks.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/storage/metadata.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/storage/records.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/agent/storage/store.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/brand.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/commandline/__init__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/commandline/arguments.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/commandline/completion.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/commandline/history.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/commandline/runner.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/commands.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/pets/__init__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/pets/cat.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/pets/chibi.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/pets/dog.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/pets/kangaroo.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/pets/model.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/pets/penguin.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/pets/polarbear.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/pets/scarfy.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/pets/seagull.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/pets/slime.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/pets/snowbear.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/pets/sprout.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/pets/tiger.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/pets/whale.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/pipeline.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/registry.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/__init__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/app.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/bars.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/boot.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/clipboard.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/commands.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/config_form.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/demo.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/followups.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/gc_policy.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/keys.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/labels.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/messaging.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/notices.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/providers.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/sessions.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/settings.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/shell.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/updating.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/__init__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/approval_page.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/ask_page.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/bash_page.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/completer.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/composer.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/context_charts.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/context_page.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/effort_page.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/follow_up.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/input_page.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/model_page.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/panel.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/pet.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/pet_page.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/root.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/self_compact_page.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/send_kind_page.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/sessions_page.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/statusline_page.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/steering.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/transcript.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/update_page.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/usage_charts.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/usage_page.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/app/ui/widgets/welcome.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/broker/__init__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/broker/__main__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/broker/client.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/broker/files.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/broker/finder.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/broker/hub.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/broker/log.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/broker/models.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/broker/process.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/broker/protocol.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/broker/roster.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/broker/runner.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/broker/server.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/broker/text.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/broker/web.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/cli.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/collector.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/config_edit.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/doctor.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/filelock.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/paths.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/plugins/__init__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/plugins/builtin_agent.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/plugins/builtin_commands.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/plugins/builtins.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/plugins/container.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/plugins/extension.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/plugins/loader.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/plugins/mixins.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/plugins/plugin.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/plugins/services.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/plugins/state.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/providers.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/py.typed +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/sdk/errors.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/sdk/handlers.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/statusline.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/__init__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/capabilities.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/clipboard.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/console.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/core/__init__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/core/app.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/core/events.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/core/focus.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/core/geometry.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/core/host.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/core/keymap.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/core/scheduler.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/core/screen.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/core/theme.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/core/widget.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/gallery.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/glyphs.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/input/__init__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/input/bridge.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/input/decoder.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/input/events.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/input/keys.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/input/reader.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/layout/__init__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/layout/box.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/layout/overlay.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/layout/scroll.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/layout/solver.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/layout/spacing.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/render/__init__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/render/ansi.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/render/canvas.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/render/code.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/render/color.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/render/renderer.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/render/rich_text.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/render/style.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/render/sweep.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/render/text.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/runner.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/terminal.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/testing/__init__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/testing/harness.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/testing/snapshot.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/theme_file.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/themes/ayu-mirage.toml +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/themes/catppuccin-latte.toml +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/themes/catppuccin-mocha.toml +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/themes/dracula.toml +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/themes/github-dimmed.toml +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/themes/github-light.toml +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/themes/gruvbox-dark.toml +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/themes/gruvbox-light.toml +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/themes/kanagawa.toml +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/themes/nord.toml +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/themes/one-dark.toml +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/themes/rose-pine-dawn.toml +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/themes/rose-pine.toml +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/themes/solarized-dark.toml +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/themes/solarized-light.toml +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/themes/tokyo-night.toml +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/widgets/__init__.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/widgets/collapsible.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/widgets/completion.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/widgets/console.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/widgets/dialog.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/widgets/diff.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/widgets/list.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/widgets/list_page.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/widgets/markdown.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/widgets/progress.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/widgets/rich_text.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/widgets/status.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/widgets/table.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/widgets/tasks.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/widgets/text.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/widgets/textarea.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/tui/widgets/toast.py +0 -0
- {zettcode-0.1.8 → zettcode-0.1.9}/src/zettcode/update.py +0 -0
|
@@ -21,6 +21,9 @@ docs/.vitepress/dist/
|
|
|
21
21
|
docs/.vitepress/cache/
|
|
22
22
|
docs/.vitepress/.temp/
|
|
23
23
|
|
|
24
|
+
# The TypeScript client is built from its sources; only dist/ is published.
|
|
25
|
+
clients/typescript/dist/
|
|
26
|
+
|
|
24
27
|
# The palette gallery is generated by `make palettes`: every widget painted in
|
|
25
28
|
# every palette, written by docs/scripts/palette_gallery.py. Regenerate it
|
|
26
29
|
# rather than committing a 2 MB copy that goes stale the moment a colour moves.
|
zettcode-0.1.9/PKG-INFO
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: zettcode
|
|
3
|
+
Version: 0.1.9
|
|
4
|
+
Summary: A focused terminal coding agent powered by zett-agent
|
|
5
|
+
Project-URL: Repository, https://github.com/Chang-LeHung/zettcode
|
|
6
|
+
Project-URL: Issues, https://github.com/Chang-LeHung/zettcode/issues
|
|
7
|
+
Author: Chang-LeHung
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Keywords: agent,coding-agent,llm,terminal,tui
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Operating System :: MacOS
|
|
13
|
+
Classifier: Operating System :: Microsoft :: Windows :: Windows 10
|
|
14
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: exceptiongroup<2,>=1.2; python_version < '3.11'
|
|
24
|
+
Requires-Dist: httpx<1,>=0.27
|
|
25
|
+
Requires-Dist: pydantic<3,>=2
|
|
26
|
+
Requires-Dist: pyperclip<2,>=1.9
|
|
27
|
+
Requires-Dist: setproctitle<2,>=1.3.7; os_name == 'posix'
|
|
28
|
+
Requires-Dist: starlette<2,>=0.48
|
|
29
|
+
Requires-Dist: tiktoken<1,>=0.12
|
|
30
|
+
Requires-Dist: tomli<3,>=2; python_version < '3.11'
|
|
31
|
+
Requires-Dist: truststore<1,>=0.10
|
|
32
|
+
Requires-Dist: uvicorn<1,>=0.35
|
|
33
|
+
Requires-Dist: wcwidth<1,>=0.2
|
|
34
|
+
Requires-Dist: websockets<17,>=15
|
|
35
|
+
Requires-Dist: zett-agent<0.2,>=0.1.17
|
|
36
|
+
Description-Content-Type: text/markdown
|
|
37
|
+
|
|
38
|
+
# ZettCode
|
|
39
|
+
|
|
40
|
+
A focused terminal coding agent powered by [zett-agent](https://pypi.org/project/zett-agent/): it reads and edits your
|
|
41
|
+
code, runs commands with your permission, and is driven by a model you choose. The repository also ships a Python SDK
|
|
42
|
+
and an HTTP server.
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install zettcode
|
|
46
|
+
zettcode
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
- [The guide](https://chang-lehung.github.io/zettcode/) — commands, keys, plugins, configuration
|
|
50
|
+
- [The SDK](https://chang-lehung.github.io/zettcode/sdk/) — drive the agent from Python
|
|
51
|
+
- [The server](https://chang-lehung.github.io/zettcode/server/) — drive it over HTTP
|
|
52
|
+
|
|
53
|
+
The full README, with the screenshots, is at the root of the repository.
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
import zettcode.sdk as zc
|
|
57
|
+
|
|
58
|
+
result = await zc.prompt("summarize the README", permission="deny")
|
|
59
|
+
print(result.text)
|
|
60
|
+
```
|
zettcode-0.1.9/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# ZettCode
|
|
2
|
+
|
|
3
|
+
A focused terminal coding agent powered by [zett-agent](https://pypi.org/project/zett-agent/): it reads and edits your
|
|
4
|
+
code, runs commands with your permission, and is driven by a model you choose. The repository also ships a Python SDK
|
|
5
|
+
and an HTTP server.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install zettcode
|
|
9
|
+
zettcode
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
- [The guide](https://chang-lehung.github.io/zettcode/) — commands, keys, plugins, configuration
|
|
13
|
+
- [The SDK](https://chang-lehung.github.io/zettcode/sdk/) — drive the agent from Python
|
|
14
|
+
- [The server](https://chang-lehung.github.io/zettcode/server/) — drive it over HTTP
|
|
15
|
+
|
|
16
|
+
The full README, with the screenshots, is at the root of the repository.
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
import zettcode.sdk as zc
|
|
20
|
+
|
|
21
|
+
result = await zc.prompt("summarize the README", permission="deny")
|
|
22
|
+
print(result.text)
|
|
23
|
+
```
|
|
@@ -5,7 +5,6 @@ readme = "README.md"
|
|
|
5
5
|
requires-python = ">=3.10"
|
|
6
6
|
dynamic = ["version"]
|
|
7
7
|
license = "MIT"
|
|
8
|
-
license-files = ["LICENSE"]
|
|
9
8
|
authors = [{name = "Chang-LeHung"}]
|
|
10
9
|
keywords = ["agent", "llm", "tui", "terminal", "coding-agent"]
|
|
11
10
|
classifiers = [
|
|
@@ -19,6 +18,7 @@ classifiers = [
|
|
|
19
18
|
"Programming Language :: Python :: 3.12",
|
|
20
19
|
"Programming Language :: Python :: 3.13",
|
|
21
20
|
"Programming Language :: Python :: 3.14",
|
|
21
|
+
"Programming Language :: Python :: 3.15",
|
|
22
22
|
"Typing :: Typed",
|
|
23
23
|
]
|
|
24
24
|
dependencies = [
|
|
@@ -75,53 +75,8 @@ path = "src/zettcode/__init__.py"
|
|
|
75
75
|
packages = ["src/zettcode"]
|
|
76
76
|
|
|
77
77
|
[tool.hatch.build.targets.sdist]
|
|
78
|
-
include = ["/src", "/README.md", "/
|
|
79
|
-
|
|
80
|
-
[dependency-groups]
|
|
81
|
-
dev = [
|
|
82
|
-
# Unlike the conditional runtime deps, these are installed on every
|
|
83
|
-
# interpreter so mypy can check the 3.10 branch of ``_compat`` for real.
|
|
84
|
-
"exceptiongroup>=1.2,<2",
|
|
85
|
-
"mypy>=1.14,<2",
|
|
86
|
-
"pytest>=8,<9",
|
|
87
|
-
"pytest-asyncio>=0.26,<2",
|
|
88
|
-
"pytest-cov>=7.1.0",
|
|
89
|
-
"ruff>=0.11,<1",
|
|
90
|
-
"tomli>=2,<3",
|
|
91
|
-
"viztracer>=1.1.1",
|
|
92
|
-
]
|
|
78
|
+
include = ["/src", "/README.md", "/pyproject.toml"]
|
|
93
79
|
|
|
94
80
|
[tool.pytest.ini_options]
|
|
95
81
|
testpaths = ["tests"]
|
|
96
82
|
asyncio_mode = "auto"
|
|
97
|
-
|
|
98
|
-
[tool.mypy]
|
|
99
|
-
python_version = "3.10"
|
|
100
|
-
files = ["src", "perf"]
|
|
101
|
-
# Check the pydantic storage models as models, not as plain classes.
|
|
102
|
-
plugins = ["pydantic.mypy"]
|
|
103
|
-
warn_unused_ignores = true
|
|
104
|
-
warn_redundant_casts = true
|
|
105
|
-
no_implicit_optional = true
|
|
106
|
-
|
|
107
|
-
[[tool.mypy.overrides]]
|
|
108
|
-
# Ships no stubs; the runner only calls the two documented functions.
|
|
109
|
-
module = ["pyperclip"]
|
|
110
|
-
ignore_missing_imports = true
|
|
111
|
-
|
|
112
|
-
[tool.ruff]
|
|
113
|
-
line-length = 120
|
|
114
|
-
target-version = "py310"
|
|
115
|
-
src = ["src", "tests", "perf"]
|
|
116
|
-
|
|
117
|
-
[tool.ruff.lint]
|
|
118
|
-
select = ["E", "F", "I", "UP", "B"]
|
|
119
|
-
ignore = ["E501"]
|
|
120
|
-
|
|
121
|
-
[tool.ruff.lint.isort]
|
|
122
|
-
known-first-party = ["zettcode"]
|
|
123
|
-
|
|
124
|
-
[tool.ruff.format]
|
|
125
|
-
quote-style = "double"
|
|
126
|
-
indent-style = "space"
|
|
127
|
-
line-ending = "lf"
|
|
@@ -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.9"
|
|
11
11
|
|
|
12
12
|
#: Where each public name lives; read by :func:`__getattr__` on first use.
|
|
13
13
|
_EXPORTS = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Small shims for the language versions this project supports.
|
|
2
2
|
|
|
3
|
-
ZettCode runs on Python 3.10 through 3.
|
|
3
|
+
ZettCode runs on Python 3.10 through 3.15, so the few things the standard
|
|
4
4
|
library grew in between live here instead of behind version checks at each use.
|
|
5
5
|
"""
|
|
6
6
|
|
|
@@ -137,12 +137,15 @@ class ReportingMcpExtension(McpExtension):
|
|
|
137
137
|
"""Return whether this is the first request its session has made, in a session the reader is in."""
|
|
138
138
|
return self._is_a_reader_session(context) and cast(str, context.config.session_id) not in self._narrated
|
|
139
139
|
|
|
140
|
-
async def _say_quietly(self, context: AgentRunContext | None, text: str) -> None:
|
|
141
|
-
"""Say a line without letting the saying fail the discovery it reports on.
|
|
140
|
+
async def _say_quietly(self, context: AgentRunContext | None, text: str, level: str = "info") -> None:
|
|
141
|
+
"""Say a line without letting the saying fail the discovery it reports on.
|
|
142
|
+
|
|
143
|
+
These are progress lines (a server is starting, or ready), so they are ``info`` unless said otherwise.
|
|
144
|
+
"""
|
|
142
145
|
if context is None:
|
|
143
146
|
return
|
|
144
147
|
try:
|
|
145
|
-
await self._say(context, text)
|
|
148
|
+
await self._say(context, text, level)
|
|
146
149
|
except Exception: # noqa: BLE001 - news about a server must never be what stops it
|
|
147
150
|
pass
|
|
148
151
|
|
|
@@ -188,14 +191,19 @@ class ReportingMcpExtension(McpExtension):
|
|
|
188
191
|
return [f"MCP server {name!r} in {path.name} is ignored: {reason}" for name, reason in skipped.items()]
|
|
189
192
|
|
|
190
193
|
@staticmethod
|
|
191
|
-
async def _say(context: AgentRunContext, text: str) -> None:
|
|
192
|
-
"""Publish one line for the transcript.
|
|
194
|
+
async def _say(context: AgentRunContext, text: str, level: str = "warn") -> None:
|
|
195
|
+
"""Publish one line for the transcript.
|
|
196
|
+
|
|
197
|
+
A line is a warning unless it says otherwise: what reaches here from the checks (a server that is down, an
|
|
198
|
+
entry that is ignored, a file that cannot be read) is something the reader may need to act on, and only the
|
|
199
|
+
progress lines of a start say ``info``.
|
|
200
|
+
"""
|
|
193
201
|
await context.emit(
|
|
194
202
|
AgentEvent(
|
|
195
203
|
type=AgentEventType.CUSTOM,
|
|
196
204
|
session_id=cast(str, context.config.session_id),
|
|
197
205
|
name=MCP_NOTICE_EVENT_NAME,
|
|
198
|
-
payload=notice_payload(text),
|
|
206
|
+
payload=notice_payload(text, level),
|
|
199
207
|
)
|
|
200
208
|
)
|
|
201
209
|
|
|
@@ -13,9 +13,21 @@ from zett_agent.events import AgentEvent
|
|
|
13
13
|
MCP_NOTICE_EVENT_NAME = "mcp_notice"
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
#: How serious a line of news is: ``info`` is progress (a server is starting, or ready), ``warn`` is something the
|
|
17
|
+
#: reader may need to act on (a server is down, an entry is ignored). A payload that names neither is ``info``.
|
|
18
|
+
LEVELS = ("info", "warn")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def notice_payload(text: str, level: str = "info") -> dict[str, str]:
|
|
22
|
+
"""Return the JSON-serializable payload that carries one line of MCP news and how serious it is."""
|
|
23
|
+
return {"text": text, "level": level if level in LEVELS else "info"}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def notice_level_from(event: AgentEvent) -> str:
|
|
27
|
+
"""Return how serious the notice an event carries is; ``info`` for a payload that does not say."""
|
|
28
|
+
payload = event.payload
|
|
29
|
+
level = payload.get("level") if isinstance(payload, dict) else None
|
|
30
|
+
return level if level in LEVELS else "info"
|
|
19
31
|
|
|
20
32
|
|
|
21
33
|
def notice_from(event: AgentEvent) -> str | None:
|
|
@@ -135,10 +135,23 @@ DEFAULT_SKILL_ROOT = "~/.zettcode/skills"
|
|
|
135
135
|
#: or ``both``, ahead of the user's own, so a project's version of a skill wins in that project.
|
|
136
136
|
WORKSPACE_SKILL_ROOT = ".zettcode/skills"
|
|
137
137
|
|
|
138
|
+
#: The same two places under the ``.agents`` directory that other coding agents share: ``~/.agents/skills`` for
|
|
139
|
+
#: the user and ``<workspace>/.agents/skills`` for a project. Each is scanned right after the ``.zettcode``
|
|
140
|
+
#: directory of its own scope, so a skill written for one of those tools is found with no copying, and a
|
|
141
|
+
#: ZettCode skill of the same name in the same scope still wins.
|
|
142
|
+
DEFAULT_AGENTS_SKILL_ROOT = "~/.agents/skills"
|
|
143
|
+
WORKSPACE_AGENTS_SKILL_ROOT = ".agents/skills"
|
|
144
|
+
|
|
138
145
|
#: The MCP server file a workspace may ship, relative to it. Read for ``[mcp] scope`` of
|
|
139
146
|
#: ``workspace`` or ``both``, and merged over the user's file by server name.
|
|
140
147
|
WORKSPACE_MCP_CONFIG = ".zettcode/mcp.json"
|
|
141
148
|
|
|
149
|
+
#: The same file under the shared ``.agents`` directory, for the workspace and for the user. Each is read right
|
|
150
|
+
#: after the ``.zettcode`` file of its own scope, so it only adds servers a ZettCode file does not name. The user's
|
|
151
|
+
#: is not read when ``[mcp] config`` names a file: whoever points at a team file means that file.
|
|
152
|
+
WORKSPACE_AGENTS_MCP_CONFIG = ".agents/mcp.json"
|
|
153
|
+
DEFAULT_AGENTS_MCP_CONFIG = "~/.agents/mcp.json"
|
|
154
|
+
|
|
142
155
|
#: API root of an Anthropic model whose entry names no ``base_url``. The
|
|
143
156
|
#: Messages API lives at the root itself, not under ``/v1``.
|
|
144
157
|
DEFAULT_ANTHROPIC_BASE_URL = "https://api.anthropic.com"
|
|
@@ -326,8 +339,8 @@ class ZettCodeConfig:
|
|
|
326
339
|
skills_enabled: Discover local skills and advertise them to the model.
|
|
327
340
|
skill_roots: Extra skill directories, searched before the directory :attr:`skills_scope`
|
|
328
341
|
names; a relative entry is resolved against the workspace.
|
|
329
|
-
skills_scope: Which of the workspace's ``.zettcode/skills`` and the user's
|
|
330
|
-
``~/.zettcode/skills`` to scan: ``"both"`` (the default) the project's first, so its version of
|
|
342
|
+
skills_scope: Which of the workspace's ``.zettcode/skills`` and ``.agents/skills`` and the user's
|
|
343
|
+
``~/.zettcode/skills`` and ``~/.agents/skills`` to scan: ``"both"`` (the default) the project's first, so its version of
|
|
331
344
|
a skill wins inside it; ``"workspace"`` the project's only, ``"global"`` the user's only.
|
|
332
345
|
mcp_enabled: Load MCP servers from :attr:`mcp_config` and the workspace's ``.zettcode/mcp.json``.
|
|
333
346
|
mcp_config: JSON file naming MCP servers; ``None`` uses ``~/.zettcode/mcp.json``.
|
|
@@ -440,8 +453,10 @@ class ZettCodeConfig:
|
|
|
440
453
|
roots: list[Path] = list(self.skill_roots)
|
|
441
454
|
if scope in ("workspace", "both"):
|
|
442
455
|
roots.append(_resolve_root(WORKSPACE_SKILL_ROOT, self.workspace))
|
|
456
|
+
roots.append(_resolve_root(WORKSPACE_AGENTS_SKILL_ROOT, self.workspace))
|
|
443
457
|
if scope in ("global", "both"):
|
|
444
458
|
roots.append(_resolve_root(DEFAULT_SKILL_ROOT, self.workspace))
|
|
459
|
+
roots.append(_resolve_root(DEFAULT_AGENTS_SKILL_ROOT, self.workspace))
|
|
445
460
|
# Ordered, one of each: a configured root may name the same directory a scope does.
|
|
446
461
|
return tuple(dict.fromkeys(roots))
|
|
447
462
|
|
|
@@ -456,8 +471,11 @@ class ZettCodeConfig:
|
|
|
456
471
|
files: list[Path] = []
|
|
457
472
|
if scope in ("workspace", "both"):
|
|
458
473
|
files.append(_resolve_root(WORKSPACE_MCP_CONFIG, self.workspace))
|
|
474
|
+
files.append(_resolve_root(WORKSPACE_AGENTS_MCP_CONFIG, self.workspace))
|
|
459
475
|
if scope in ("global", "both"):
|
|
460
476
|
files.append((self.mcp_config or Path(DEFAULT_MCP_CONFIG)).expanduser().resolve())
|
|
477
|
+
if self.mcp_config is None:
|
|
478
|
+
files.append(_resolve_root(DEFAULT_AGENTS_MCP_CONFIG, self.workspace))
|
|
461
479
|
return tuple(dict.fromkeys(files))
|
|
462
480
|
|
|
463
481
|
|
|
@@ -577,6 +595,33 @@ def _read_models(raw: object, source: Path) -> tuple[ModelConfig, ...]:
|
|
|
577
595
|
return tuple(models)
|
|
578
596
|
|
|
579
597
|
|
|
598
|
+
def read_models(path: str | Path | None = None) -> tuple[ModelConfig, ...]:
|
|
599
|
+
"""Return the models a config file lists, and nothing else it holds.
|
|
600
|
+
|
|
601
|
+
Unlike :func:`load_config`, no models is an answer (the file is new, or a program is being set up) and a
|
|
602
|
+
missing file is an empty one. A model that is configured wrongly is still an error, because it would fail on
|
|
603
|
+
the first request otherwise.
|
|
604
|
+
|
|
605
|
+
Args:
|
|
606
|
+
path: The file to read; ``$ZETTCODE_CONFIG`` or ``~/.zettcode/config.toml`` by default.
|
|
607
|
+
"""
|
|
608
|
+
source = config_path(path)
|
|
609
|
+
if not source.is_file():
|
|
610
|
+
return ()
|
|
611
|
+
try:
|
|
612
|
+
data = tomllib.loads(source.read_text(encoding="utf-8"))
|
|
613
|
+
except tomllib.TOMLDecodeError as error:
|
|
614
|
+
raise ValueError(f"Invalid config file {source}: {error}") from error
|
|
615
|
+
raw = data.get("models", [])
|
|
616
|
+
if raw is None:
|
|
617
|
+
return ()
|
|
618
|
+
if not isinstance(raw, list):
|
|
619
|
+
raise ValueError("Config key 'models' must be an array of tables ([[models]])")
|
|
620
|
+
if any(not isinstance(entry, dict) for entry in raw):
|
|
621
|
+
raise ValueError("Config key 'models' must be an array of tables ([[models]])")
|
|
622
|
+
return tuple(_entry_model(entry, index) for index, entry in enumerate(raw, start=1))
|
|
623
|
+
|
|
624
|
+
|
|
580
625
|
def _read_table(raw: object, key: str, source: Path, allowed: frozenset[str]) -> dict[str, object]:
|
|
581
626
|
"""Return one optional config table, rejecting unknown keys and wrong shapes."""
|
|
582
627
|
if raw is None:
|
|
@@ -59,8 +59,21 @@ if TYPE_CHECKING: # pragma: no cover - for type checkers and editors; at runtim
|
|
|
59
59
|
ToolStarted,
|
|
60
60
|
)
|
|
61
61
|
from .handlers import approve_all, approve_commands, deny_all
|
|
62
|
+
from .models import add_model, list_models, remove_model, update_model
|
|
62
63
|
from .session import RunStream, Session
|
|
63
|
-
from .types import
|
|
64
|
+
from .types import (
|
|
65
|
+
DayTotals,
|
|
66
|
+
Image,
|
|
67
|
+
MentionInfo,
|
|
68
|
+
ModelCheck,
|
|
69
|
+
ModelTotals,
|
|
70
|
+
RunResult,
|
|
71
|
+
SessionStatsInfo,
|
|
72
|
+
SessionTotals,
|
|
73
|
+
Totals,
|
|
74
|
+
Usage,
|
|
75
|
+
WorkspaceUsage,
|
|
76
|
+
)
|
|
64
77
|
|
|
65
78
|
#: Where each public name lives. The package resolves a name by importing only that module.
|
|
66
79
|
_EXPORTS: dict[str, str] = {
|
|
@@ -72,6 +85,14 @@ _EXPORTS: dict[str, str] = {
|
|
|
72
85
|
"RunResult": ".types",
|
|
73
86
|
"Usage": ".types",
|
|
74
87
|
"Image": ".types",
|
|
88
|
+
"MentionInfo": ".types",
|
|
89
|
+
"DayTotals": ".types",
|
|
90
|
+
"ModelCheck": ".types",
|
|
91
|
+
"ModelTotals": ".types",
|
|
92
|
+
"SessionStatsInfo": ".types",
|
|
93
|
+
"SessionTotals": ".types",
|
|
94
|
+
"Totals": ".types",
|
|
95
|
+
"WorkspaceUsage": ".types",
|
|
75
96
|
"TextDelta": ".events",
|
|
76
97
|
"ReasoningDelta": ".events",
|
|
77
98
|
"ToolStarted": ".events",
|
|
@@ -85,6 +106,10 @@ _EXPORTS: dict[str, str] = {
|
|
|
85
106
|
"ZettCodeError": ".errors",
|
|
86
107
|
"ConfigurationError": ".errors",
|
|
87
108
|
"RunError": ".errors",
|
|
109
|
+
"add_model": ".models",
|
|
110
|
+
"list_models": ".models",
|
|
111
|
+
"remove_model": ".models",
|
|
112
|
+
"update_model": ".models",
|
|
88
113
|
}
|
|
89
114
|
|
|
90
115
|
#: Kept literal so linters and editors can read it; a test checks it names exactly the keys of ``_EXPORTS``.
|
|
@@ -92,24 +117,36 @@ __all__ = [
|
|
|
92
117
|
"ApprovalRequested",
|
|
93
118
|
"Client",
|
|
94
119
|
"ConfigurationError",
|
|
120
|
+
"DayTotals",
|
|
95
121
|
"Finished",
|
|
96
122
|
"Image",
|
|
123
|
+
"MentionInfo",
|
|
124
|
+
"ModelCheck",
|
|
125
|
+
"ModelTotals",
|
|
97
126
|
"QuestionAsked",
|
|
98
127
|
"ReasoningDelta",
|
|
99
128
|
"RunError",
|
|
100
129
|
"RunResult",
|
|
101
130
|
"RunStream",
|
|
102
131
|
"Session",
|
|
132
|
+
"SessionStatsInfo",
|
|
133
|
+
"SessionTotals",
|
|
103
134
|
"TextDelta",
|
|
104
135
|
"ToolFinished",
|
|
105
136
|
"ToolStarted",
|
|
137
|
+
"Totals",
|
|
106
138
|
"Usage",
|
|
139
|
+
"WorkspaceUsage",
|
|
107
140
|
"ZettCodeError",
|
|
141
|
+
"add_model",
|
|
108
142
|
"approve_all",
|
|
109
143
|
"approve_commands",
|
|
110
144
|
"deny_all",
|
|
145
|
+
"list_models",
|
|
111
146
|
"prompt",
|
|
112
147
|
"prompt_sync",
|
|
148
|
+
"remove_model",
|
|
149
|
+
"update_model",
|
|
113
150
|
]
|
|
114
151
|
|
|
115
152
|
|
|
@@ -7,15 +7,17 @@ custom events, so it imports both, and is itself imported only when a run starts
|
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
-
from collections.abc import Mapping
|
|
10
|
+
from collections.abc import Mapping, Sequence
|
|
11
|
+
from typing import TYPE_CHECKING
|
|
11
12
|
|
|
12
13
|
from zett_agent.events import AgentEvent, AgentEventType
|
|
13
14
|
from zett_agent.extensions.shell_approval import SHELL_APPROVAL_EVENT_NAME
|
|
14
15
|
from zett_agent.messages import TextContent
|
|
15
16
|
|
|
16
17
|
from ..app.agent.dialogue.ask import question_from
|
|
17
|
-
from ..app.agent.extensions.mcp_notice import notice_from
|
|
18
|
+
from ..app.agent.extensions.mcp_notice import notice_from, notice_level_from
|
|
18
19
|
from ..app.agent.extensions.usage import USAGE_EVENT_NAME, UsageSnapshot
|
|
20
|
+
from ..app.agent.storage.ledger import Ledger, SessionStats, SessionUsage, Tally
|
|
19
21
|
from .events import (
|
|
20
22
|
AnyEvent,
|
|
21
23
|
ApprovalRequested,
|
|
@@ -34,9 +36,19 @@ from .events import (
|
|
|
34
36
|
UsageUpdated,
|
|
35
37
|
_Reply,
|
|
36
38
|
)
|
|
37
|
-
from .types import
|
|
39
|
+
from .types import (
|
|
40
|
+
Compaction,
|
|
41
|
+
DayTotals,
|
|
42
|
+
ModelCheck,
|
|
43
|
+
ModelTotals,
|
|
44
|
+
SessionStatsInfo,
|
|
45
|
+
SessionTotals,
|
|
46
|
+
Totals,
|
|
47
|
+
Usage,
|
|
48
|
+
WorkspaceUsage,
|
|
49
|
+
)
|
|
38
50
|
|
|
39
|
-
__all__ = ["translate", "usage_from"]
|
|
51
|
+
__all__ = ["checks_from", "ledger_from", "stats_from", "translate", "usage_from"]
|
|
40
52
|
|
|
41
53
|
|
|
42
54
|
def usage_from(snapshot: UsageSnapshot) -> Usage:
|
|
@@ -77,6 +89,78 @@ def _optional_int(value: object) -> int | None:
|
|
|
77
89
|
return int(value) if isinstance(value, (int, float)) and not isinstance(value, bool) else None
|
|
78
90
|
|
|
79
91
|
|
|
92
|
+
if TYPE_CHECKING: # pragma: no cover - annotations only
|
|
93
|
+
from ..doctor import Probe
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def totals_from(tally: Tally) -> Totals:
|
|
97
|
+
"""Return one tally as the SDK's own counters."""
|
|
98
|
+
return Totals(
|
|
99
|
+
requests=tally.requests,
|
|
100
|
+
input_tokens=tally.input_tokens,
|
|
101
|
+
output_tokens=tally.output_tokens,
|
|
102
|
+
cache_read_tokens=tally.cache_read_tokens,
|
|
103
|
+
reasoning_tokens=tally.reasoning_tokens,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def ledger_from(ledger: Ledger) -> WorkspaceUsage:
|
|
108
|
+
"""Return the workspace ledger as plain SDK values, ordered the way a page shows it."""
|
|
109
|
+
sessions = sorted(ledger.sessions, key=lambda item: item.updated, reverse=True)
|
|
110
|
+
models = sorted(ledger.models.items(), key=lambda pair: pair[1].total, reverse=True)
|
|
111
|
+
return WorkspaceUsage(
|
|
112
|
+
sessions=tuple(_session_totals(item) for item in sessions),
|
|
113
|
+
models=tuple(ModelTotals(name, totals_from(tally)) for name, tally in models),
|
|
114
|
+
days=tuple(DayTotals(day, totals_from(tally)) for day, tally in sorted(ledger.days.items())),
|
|
115
|
+
total=totals_from(ledger.total),
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _session_totals(usage: SessionUsage) -> SessionTotals:
|
|
120
|
+
"""Return one session's ledger row."""
|
|
121
|
+
return SessionTotals(
|
|
122
|
+
id=usage.session_id,
|
|
123
|
+
title=usage.title,
|
|
124
|
+
started=usage.started,
|
|
125
|
+
updated=usage.updated,
|
|
126
|
+
tokens=totals_from(usage.tally),
|
|
127
|
+
models=usage.models,
|
|
128
|
+
entries=usage.entries,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def stats_from(stats: SessionStats) -> SessionStatsInfo:
|
|
133
|
+
"""Return one session's stored totals."""
|
|
134
|
+
return SessionStatsInfo(
|
|
135
|
+
id=stats.session_id,
|
|
136
|
+
entries=stats.entries,
|
|
137
|
+
requests=stats.requests,
|
|
138
|
+
input_tokens=stats.input_tokens,
|
|
139
|
+
output_tokens=stats.output_tokens,
|
|
140
|
+
cache_read_tokens=stats.cache_read_tokens,
|
|
141
|
+
reasoning_tokens=stats.reasoning_tokens,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def checks_from(probes: Sequence[Probe]) -> tuple[ModelCheck, ...]:
|
|
146
|
+
"""Return the doctor probes as SDK values."""
|
|
147
|
+
checks: list[ModelCheck] = []
|
|
148
|
+
for probe in probes:
|
|
149
|
+
tokens = probe.tokens
|
|
150
|
+
checks.append(
|
|
151
|
+
ModelCheck(
|
|
152
|
+
model=probe.model.shown_name,
|
|
153
|
+
model_id=probe.model.model,
|
|
154
|
+
ok=probe.ok,
|
|
155
|
+
seconds=probe.seconds,
|
|
156
|
+
detail=probe.detail,
|
|
157
|
+
input_tokens=tokens[0] if tokens else None,
|
|
158
|
+
output_tokens=tokens[1] if tokens else None,
|
|
159
|
+
)
|
|
160
|
+
)
|
|
161
|
+
return tuple(checks)
|
|
162
|
+
|
|
163
|
+
|
|
80
164
|
def translate(event: AgentEvent, bridge: Bridge) -> list[AnyEvent]:
|
|
81
165
|
"""Return the SDK events one ``zett-agent`` event stands for; usually one, sometimes none or several.
|
|
82
166
|
|
|
@@ -176,4 +260,4 @@ def _custom(event: AgentEvent, session: str, bridge: Bridge) -> list[AnyEvent]:
|
|
|
176
260
|
)
|
|
177
261
|
]
|
|
178
262
|
line = notice_from(event)
|
|
179
|
-
return [Notice(session, line)] if line is not None else []
|
|
263
|
+
return [Notice(session, line, notice_level_from(event))] if line is not None else []
|