tsugite-cli 0.24.0__tar.gz → 0.25.0__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.
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/.gitignore +1 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/PKG-INFO +2 -1
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/pyproject.toml +2 -1
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/agent_preparation.py +6 -5
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/agent_runner/__init__.py +0 -2
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/agent_runner/runner.py +40 -67
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/agent_runner/steps.py +1 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/approval.py +14 -7
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/attachments/agent_config.py +1 -1
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/builtin_agents/default.md +14 -13
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/builtin_agents/job_verifier.md +3 -1
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/builtin_skills/codebase-exploration/SKILL.md +1 -1
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/builtin_skills/response-patterns/SKILL.md +11 -14
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/cli/helpers.py +2 -2
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/cli/run.py +1 -52
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/core/agent.py +92 -5
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/core/executor.py +28 -2
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/core/subprocess_executor.py +10 -7
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/history/base.py +2 -2
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/history/models.py +22 -9
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/history/sqlite_backend.py +15 -7
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/history/ui_events.py +1 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/md_agents.py +1 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/permissions.py +34 -5
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/providers/openai_compat.py +1 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/schemas/agent.schema.json +10 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/tools/__init__.py +6 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/tools/agents.py +2 -17
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/tools/http.py +23 -11
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/tools/jobs.py +5 -4
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/tools/notify.py +21 -6
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/tools/schedule.py +13 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/tools/sessions.py +216 -6
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/tools/shell_tools.py +6 -3
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/workspace/models.py +22 -6
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/AGENTS.md +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/CONTRIBUTING.md +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/LICENSE +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/README.md +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/__init__.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/agent_inheritance.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/agent_runner/exec_directives.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/agent_runner/exec_runner.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/agent_runner/helpers.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/agent_runner/history_integration.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/agent_runner/metrics.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/agent_runner/models.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/agent_runner/validation.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/agent_utils.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/attachments/__init__.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/attachments/auto_context.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/attachments/base.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/attachments/delegation.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/attachments/file.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/attachments/inline.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/attachments/storage.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/attachments/url.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/builtin_agents/.gitkeep +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/builtin_agents/code_searcher.md +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/builtin_agents/file_searcher.md +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/builtin_agents/job_worker.md +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/builtin_agents/onboard.md +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/builtin_context.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/builtin_skills/.gitkeep +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/builtin_skills/external-agent-bridge/SKILL.md +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/builtin_skills/python-math/SKILL.md +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/builtin_skills/scheduling/SKILL.md +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/builtin_skills/skill-authoring/SKILL.md +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/builtin_skills/tsugite-agent-basics/SKILL.md +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/builtin_skills/tsugite-jinja-reference/SKILL.md +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/builtin_skills/tsugite-skill-basics/SKILL.md +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/cache.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/cancellation.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/cli/__init__.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/cli/agents.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/cli/attachments.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/cli/cache.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/cli/chat.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/cli/config.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/cli/daemon.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/cli/exec.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/cli/history.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/cli/init.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/cli/models.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/cli/plugins.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/cli/render.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/cli/secrets.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/cli/skills.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/cli/tools.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/cli/usage.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/cli/validate.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/cli/workspace.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/config.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/console.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/constants.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/context.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/context_block.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/core/__init__.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/core/content_blocks.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/core/executor_registry.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/core/memory.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/core/proxy.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/core/record_store.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/core/sandbox.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/core/state.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/core/tools.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/daemon_client.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/events/__init__.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/events/base.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/events/bus.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/events/events.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/events/helpers.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/exceptions.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/history/__init__.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/history/reconstruction.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/history/registry.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/history/sqlite_conn.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/history/sqlite_schema.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/hooks.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/interaction.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/models.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/options.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/plugins.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/prompt_xml.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/providers/__init__.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/providers/anthropic.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/providers/base.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/providers/model_cache.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/providers/model_registry.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/providers/ollama.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/providers/openrouter.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/py.typed +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/renderer.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/schemas/__init__.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/secrets/__init__.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/secrets/backend.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/secrets/env.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/secrets/exec.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/secrets/file.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/secrets/masking.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/secrets/redaction.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/secrets/registry.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/secrets/sqlite.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/shell_tool_config.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/skill_discovery.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/templates/AGENTS.md +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/templates/IDENTITY.md +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/templates/MEMORY.md +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/templates/USER.md +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/templates/personas/casual-technical.md +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/templates/personas/marvin.md +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/templates/personas/minimal.md +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/tools/artifacts.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/tools/daemon_control.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/tools/fs.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/tools/history.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/tools/interactive.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/tools/secrets.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/tools/shell.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/tools/skills.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/tools/time.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/tsugite.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/ui/__init__.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/ui/base.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/ui/chat.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/ui/dispatch.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/ui/helpers.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/ui/jsonl.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/ui/plain.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/ui/repl_chat.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/ui/repl_commands.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/ui/repl_completer.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/ui/repl_handler.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/ui_context.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/ui_surfaces.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/usage/__init__.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/usage/quota.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/usage/store.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/user_agent.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/utils.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/workspace/__init__.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/workspace/session.py +0 -0
- {tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/workspace/templates.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: tsugite-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.25.0
|
|
4
4
|
Summary: Micro-agent runner for task automation using markdown definitions
|
|
5
5
|
Author: Justyn Shull
|
|
6
6
|
License: GNU AFFERO GENERAL PUBLIC LICENSE
|
|
@@ -241,6 +241,7 @@ License: GNU AFFERO GENERAL PUBLIC LICENSE
|
|
|
241
241
|
License-File: LICENSE
|
|
242
242
|
Keywords: agents,automation,cli,jinja2
|
|
243
243
|
Requires-Python: >=3.11
|
|
244
|
+
Requires-Dist: certifi>=2026.10.23
|
|
244
245
|
Requires-Dist: cryptography>=46.0.5
|
|
245
246
|
Requires-Dist: html2text>=2020.1.16
|
|
246
247
|
Requires-Dist: httpx>=0.25
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "tsugite-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.25.0"
|
|
4
4
|
description = "Micro-agent runner for task automation using markdown definitions"
|
|
5
5
|
authors = [{ name = "Justyn Shull" }]
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -12,6 +12,7 @@ dependencies = [
|
|
|
12
12
|
"jinja2>=3.1",
|
|
13
13
|
"pyyaml>=6.0",
|
|
14
14
|
"httpx>=0.25",
|
|
15
|
+
"certifi>=2026.10.23",
|
|
15
16
|
"rich>=13.0",
|
|
16
17
|
"questionary>=2.1.1",
|
|
17
18
|
"html2text>=2020.1.16",
|
|
@@ -434,7 +434,6 @@ class AgentPreparer:
|
|
|
434
434
|
_combine_instructions,
|
|
435
435
|
execute_exec_directives,
|
|
436
436
|
execute_tool_directives,
|
|
437
|
-
get_default_instructions,
|
|
438
437
|
)
|
|
439
438
|
from tsugite.core.agent import build_system_prompt
|
|
440
439
|
from tsugite.renderer import AgentRenderer
|
|
@@ -506,12 +505,16 @@ class AgentPreparer:
|
|
|
506
505
|
skip_reason=skip_reason,
|
|
507
506
|
)
|
|
508
507
|
|
|
508
|
+
tools = self._expand_tools(agent_config, full_context, interactive_mode)
|
|
509
|
+
# Templates test membership against the names actually installed, not the
|
|
510
|
+
# frontmatter specs (`"@secrets"`).
|
|
511
|
+
full_context["tools"] = [t.name for t in tools]
|
|
512
|
+
|
|
509
513
|
try:
|
|
510
514
|
rendered_prompt = renderer.render(modified_content, full_context)
|
|
511
515
|
except Exception as e:
|
|
512
516
|
raise RuntimeError(f"Template rendering failed: {e}") from e
|
|
513
517
|
|
|
514
|
-
base_instructions = get_default_instructions()
|
|
515
518
|
agent_instructions = getattr(agent_config, "instructions", "")
|
|
516
519
|
|
|
517
520
|
# Render agent instructions as Jinja2 template
|
|
@@ -521,9 +524,7 @@ class AgentPreparer:
|
|
|
521
524
|
except Exception as e:
|
|
522
525
|
raise RuntimeError(f"Failed to render agent instructions: {e}") from e
|
|
523
526
|
|
|
524
|
-
combined_instructions = _combine_instructions(
|
|
525
|
-
|
|
526
|
-
tools = self._expand_tools(agent_config, full_context, interactive_mode)
|
|
527
|
+
combined_instructions = _combine_instructions(agent_instructions)
|
|
527
528
|
|
|
528
529
|
skill_load = self._load_skills(agent_config, prompt, full_context, _skill_manager, event_bus)
|
|
529
530
|
skills, expiring_skills = skill_load.skills, skill_load.expiring
|
|
@@ -31,7 +31,6 @@ from tsugite.agent_runner.runner import ( # noqa: F401
|
|
|
31
31
|
_execute_agent_with_prompt,
|
|
32
32
|
execute_prefetch,
|
|
33
33
|
execute_tool_directives,
|
|
34
|
-
get_default_instructions,
|
|
35
34
|
preview_multistep_agent,
|
|
36
35
|
run_agent,
|
|
37
36
|
run_agent_async,
|
|
@@ -47,7 +46,6 @@ __all__ = [
|
|
|
47
46
|
"execute_exec_directives",
|
|
48
47
|
"run_python_block",
|
|
49
48
|
"ExecBlockResult",
|
|
50
|
-
"get_default_instructions",
|
|
51
49
|
"AgentExecutionResult",
|
|
52
50
|
"StepMetrics",
|
|
53
51
|
"display_step_metrics",
|
|
@@ -10,7 +10,7 @@ from pathlib import Path # noqa: E402
|
|
|
10
10
|
from types import SimpleNamespace # noqa: E402
|
|
11
11
|
from typing import TYPE_CHECKING, Any, Dict, List, Optional # noqa: E402
|
|
12
12
|
|
|
13
|
-
from tsugite.core.agent import TsugiteAgent # noqa: E402
|
|
13
|
+
from tsugite.core.agent import NO_ACTION_MESSAGE, AgentResult, TsugiteAgent # noqa: E402
|
|
14
14
|
from tsugite.core.executor_registry import get_executor_class # noqa: E402
|
|
15
15
|
from tsugite.core.proxy import _parse_pattern # noqa: E402
|
|
16
16
|
from tsugite.core.state import session_state_path # noqa: E402
|
|
@@ -155,31 +155,6 @@ def _setup_event_context(event_bus: Optional["EventBus"]) -> None:
|
|
|
155
155
|
set_ui_context(event_bus=event_bus)
|
|
156
156
|
|
|
157
157
|
|
|
158
|
-
def get_default_instructions() -> str:
|
|
159
|
-
"""Get minimal default instructions. Detailed guidance comes from skills.
|
|
160
|
-
|
|
161
|
-
Returns:
|
|
162
|
-
Default instructions for code execution mode
|
|
163
|
-
"""
|
|
164
|
-
base = "You accomplish tasks by writing Python code.\n\n"
|
|
165
|
-
|
|
166
|
-
output = (
|
|
167
|
-
"## Output\n\n"
|
|
168
|
-
"- `print(x)` - See in next turn (internal)\n"
|
|
169
|
-
"- `send_message(msg)` - Show user progress\n"
|
|
170
|
-
"- `final_answer(msg)` - Final response (stops execution)\n\n"
|
|
171
|
-
)
|
|
172
|
-
|
|
173
|
-
rules = (
|
|
174
|
-
"## Rules\n\n"
|
|
175
|
-
"1. Always respond with Python code blocks\n"
|
|
176
|
-
"2. Call `final_answer()` when done\n"
|
|
177
|
-
"3. Variables persist between turns\n"
|
|
178
|
-
)
|
|
179
|
-
|
|
180
|
-
return base + output + rules
|
|
181
|
-
|
|
182
|
-
|
|
183
158
|
def _render_args(value: Any, renderer: AgentRenderer, context: Dict[str, Any]) -> Any:
|
|
184
159
|
"""Recursively render Jinja in string leaves of a tool args structure.
|
|
185
160
|
|
|
@@ -320,32 +295,17 @@ def execute_tool_directives(
|
|
|
320
295
|
return modified_content, new_context
|
|
321
296
|
|
|
322
297
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
For models like Claude/Deepseek that expose reasoning_content, displays the actual reasoning.
|
|
327
|
-
|
|
328
|
-
Args:
|
|
329
|
-
agent: The TsugiteAgent instance that just completed execution
|
|
330
|
-
custom_logger: Custom logger to display reasoning content
|
|
331
|
-
"""
|
|
332
|
-
if not hasattr(agent, "memory") or not agent.memory.reasoning_history:
|
|
333
|
-
return
|
|
298
|
+
# Daemon chat sources with a person at the other end; any other source counts as background.
|
|
299
|
+
INTERACTIVE_SOURCES = frozenset({"http", "discord"})
|
|
334
300
|
|
|
335
|
-
# Display each reasoning entry
|
|
336
|
-
for reasoning_content in agent.memory.reasoning_history:
|
|
337
|
-
if reasoning_content and custom_logger:
|
|
338
|
-
# Check if custom_logger has ui_handler (custom UI mode)
|
|
339
|
-
ui_handler = get_ui_handler(custom_logger)
|
|
340
|
-
if ui_handler:
|
|
341
|
-
from tsugite.events import EventBus, ReasoningContentEvent
|
|
342
301
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
302
|
+
def _run_is_interactive(channel_metadata: Optional[Dict[str, Any]]) -> bool:
|
|
303
|
+
"""Whether a person is present: the session source in the daemon, the TTY otherwise."""
|
|
304
|
+
source = (channel_metadata or {}).get("source")
|
|
305
|
+
return source in INTERACTIVE_SOURCES if source else is_interactive()
|
|
346
306
|
|
|
347
307
|
|
|
348
|
-
def _make_pre_llm_call_callback(hooks_dir: Path, agent_name: str):
|
|
308
|
+
def _make_pre_llm_call_callback(hooks_dir: Path, agent_name: str, interactive: bool):
|
|
349
309
|
"""Build an async callback that fires pre_llm_call hooks to mutate outgoing
|
|
350
310
|
messages in place. Returns None when no such hooks exist (keeps the hot path clean)."""
|
|
351
311
|
from tsugite.hooks import fire_hooks, load_hooks_config
|
|
@@ -359,7 +319,7 @@ def _make_pre_llm_call_callback(hooks_dir: Path, agent_name: str):
|
|
|
359
319
|
hooks_dir,
|
|
360
320
|
"pre_llm_call",
|
|
361
321
|
{"messages": messages, "model": model, "agent": agent_name},
|
|
362
|
-
interactive=
|
|
322
|
+
interactive=interactive,
|
|
363
323
|
)
|
|
364
324
|
|
|
365
325
|
return _callback
|
|
@@ -401,6 +361,7 @@ async def _execute_agent_with_prompt(
|
|
|
401
361
|
user_input_for_history: Optional[str] = None,
|
|
402
362
|
channel_metadata: Optional[Dict[str, Any]] = None,
|
|
403
363
|
usage_sink: Optional[Dict[str, Any]] = None,
|
|
364
|
+
requires_action: bool = False,
|
|
404
365
|
) -> str | AgentExecutionResult:
|
|
405
366
|
"""Execute agent with a prepared agent.
|
|
406
367
|
|
|
@@ -409,6 +370,9 @@ async def _execute_agent_with_prompt(
|
|
|
409
370
|
`usage_sink`, when given, receives this call's token and cost counters. It is
|
|
410
371
|
how a multi-step run collects accounting from steps that return plain
|
|
411
372
|
strings.
|
|
373
|
+
|
|
374
|
+
`requires_action` makes a run that ends without executing any code raise, so a
|
|
375
|
+
step whose result feeds later steps cannot pass on a prose answer.
|
|
412
376
|
"""
|
|
413
377
|
if exec_options is None:
|
|
414
378
|
exec_options = ExecutionOptions()
|
|
@@ -445,8 +409,9 @@ async def _execute_agent_with_prompt(
|
|
|
445
409
|
hooks_dir = path_context.effective_cwd
|
|
446
410
|
else:
|
|
447
411
|
hooks_dir = Path.cwd()
|
|
448
|
-
|
|
449
|
-
|
|
412
|
+
interactive = _run_is_interactive(channel_metadata)
|
|
413
|
+
setup_hook_handler(hooks_dir, event_bus, interactive=interactive)
|
|
414
|
+
pre_llm_call_cb = _make_pre_llm_call_callback(hooks_dir, agent_config.name, interactive)
|
|
450
415
|
|
|
451
416
|
# Start with tools from prepared agent
|
|
452
417
|
tools = list(prepared.tools) # Make a copy
|
|
@@ -615,7 +580,7 @@ async def _execute_agent_with_prompt(
|
|
|
615
580
|
hook_vars=hook_vars,
|
|
616
581
|
storage=session_storage,
|
|
617
582
|
pre_llm_call=pre_llm_call_cb,
|
|
618
|
-
expects_action=(channel_metadata or {}).get("source") == "scheduler",
|
|
583
|
+
expects_action=requires_action or (channel_metadata or {}).get("source") == "scheduler",
|
|
619
584
|
)
|
|
620
585
|
# Set event_bus in context so tools can access it during execution
|
|
621
586
|
_setup_event_context(event_bus)
|
|
@@ -633,9 +598,6 @@ async def _execute_agent_with_prompt(
|
|
|
633
598
|
stream=exec_options.stream,
|
|
634
599
|
)
|
|
635
600
|
|
|
636
|
-
# Extract and display reasoning content if present
|
|
637
|
-
_extract_reasoning_content(agent, custom_logger)
|
|
638
|
-
|
|
639
601
|
if usage_sink is not None:
|
|
640
602
|
usage_sink.update(
|
|
641
603
|
token_count=agent.total_tokens,
|
|
@@ -666,10 +628,18 @@ async def _execute_agent_with_prompt(
|
|
|
666
628
|
except Exception as e:
|
|
667
629
|
logger.debug("Failed to record usage: %s", e)
|
|
668
630
|
|
|
631
|
+
if requires_action and agent.ended_no_action:
|
|
632
|
+
steps = result.steps if isinstance(result, AgentResult) and result.steps else []
|
|
633
|
+
raise AgentExecutionError(
|
|
634
|
+
NO_ACTION_MESSAGE,
|
|
635
|
+
execution_steps=steps,
|
|
636
|
+
token_usage=agent.total_tokens,
|
|
637
|
+
cost=agent.reported_cost,
|
|
638
|
+
step_count=len(steps),
|
|
639
|
+
)
|
|
640
|
+
|
|
669
641
|
# Return appropriate format
|
|
670
642
|
if exec_options.return_token_usage:
|
|
671
|
-
from tsugite.core.agent import AgentResult
|
|
672
|
-
|
|
673
643
|
if isinstance(result, AgentResult):
|
|
674
644
|
step_count = len(result.steps) if result.steps else 0
|
|
675
645
|
steps_list = result.steps if result.steps else []
|
|
@@ -712,8 +682,6 @@ async def _execute_agent_with_prompt(
|
|
|
712
682
|
session_id=session_storage.session_id if session_storage else None,
|
|
713
683
|
)
|
|
714
684
|
else:
|
|
715
|
-
from tsugite.core.agent import AgentResult
|
|
716
|
-
|
|
717
685
|
if isinstance(result, AgentResult):
|
|
718
686
|
return str(result.output)
|
|
719
687
|
else:
|
|
@@ -829,15 +797,17 @@ def _domain_within_ceiling(desired_pattern: str, ceiling: list) -> bool:
|
|
|
829
797
|
|
|
830
798
|
|
|
831
799
|
def _resolve_workspace_dir(workspace: Optional[Any], path_context: Optional[Any]) -> Optional[Path]:
|
|
832
|
-
"""Resolve the executor
|
|
800
|
+
"""Resolve the directory the executor runs code in.
|
|
833
801
|
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
Workspace), so without this fallback the sandbox would bind/chdir the daemon's
|
|
837
|
-
CWD instead of the agent's workspace (or job worktree).
|
|
802
|
+
Checks: an explicit Workspace -> the directory bound with set_workspace_dir
|
|
803
|
+
(the daemon binds the session's working directory) -> path_context.workspace_dir.
|
|
838
804
|
"""
|
|
805
|
+
from tsugite.cli.helpers import get_workspace_dir
|
|
806
|
+
|
|
839
807
|
if workspace:
|
|
840
808
|
return workspace.path
|
|
809
|
+
if bound := get_workspace_dir():
|
|
810
|
+
return bound
|
|
841
811
|
if path_context and getattr(path_context, "workspace_dir", None):
|
|
842
812
|
return path_context.workspace_dir
|
|
843
813
|
return None
|
|
@@ -872,6 +842,7 @@ class _RunSetup:
|
|
|
872
842
|
resume_after_compaction: bool = False
|
|
873
843
|
resume_cost_baseline: float = 0.0
|
|
874
844
|
conversation_id: Optional[str] = None
|
|
845
|
+
requires_action: bool = False
|
|
875
846
|
|
|
876
847
|
|
|
877
848
|
def _prepare_step(agent: Any, prompt: str, context: Dict[str, Any], setup: "_RunSetup") -> "PreparedAgent":
|
|
@@ -923,7 +894,7 @@ async def _run_unit(
|
|
|
923
894
|
"rendered_prompt": prepared.rendered_prompt[:500] if prepared.rendered_prompt else "",
|
|
924
895
|
"tools": [t.name for t in prepared.tools] if prepared.tools else [],
|
|
925
896
|
},
|
|
926
|
-
interactive=
|
|
897
|
+
interactive=_run_is_interactive(setup.channel_metadata),
|
|
927
898
|
on_status=setup.on_status,
|
|
928
899
|
on_result=setup.on_hook_result,
|
|
929
900
|
)
|
|
@@ -955,6 +926,7 @@ async def _run_unit(
|
|
|
955
926
|
model_kwargs=model_kwargs,
|
|
956
927
|
injectable_vars=injectable_vars,
|
|
957
928
|
usage_sink=usage_sink,
|
|
929
|
+
requires_action=setup.requires_action,
|
|
958
930
|
)
|
|
959
931
|
|
|
960
932
|
try:
|
|
@@ -1128,10 +1100,11 @@ async def run_agent_async(
|
|
|
1128
1100
|
on_status = None
|
|
1129
1101
|
on_hook_result = None
|
|
1130
1102
|
|
|
1103
|
+
interactive = _run_is_interactive(channel_metadata)
|
|
1131
1104
|
hook_vars = await fire_pre_message_hooks(
|
|
1132
1105
|
hooks_dir,
|
|
1133
1106
|
{"message": hook_message, "agent_name": agent_path.stem},
|
|
1134
|
-
interactive=
|
|
1107
|
+
interactive=interactive,
|
|
1135
1108
|
on_status=on_status,
|
|
1136
1109
|
on_result=on_hook_result,
|
|
1137
1110
|
)
|
|
@@ -1145,7 +1118,7 @@ async def run_agent_async(
|
|
|
1145
1118
|
hooks_dir,
|
|
1146
1119
|
"pre_context_build",
|
|
1147
1120
|
{"message": hook_message, "agent_name": agent_path.stem, **context, "blocks": context_blocks},
|
|
1148
|
-
interactive=
|
|
1121
|
+
interactive=interactive,
|
|
1149
1122
|
on_status=on_status,
|
|
1150
1123
|
on_result=on_hook_result,
|
|
1151
1124
|
)
|
|
@@ -31,23 +31,28 @@ _LABEL_TO_DECISION = {
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
def request_approval(
|
|
34
|
-
prompt: str,
|
|
34
|
+
prompt: str,
|
|
35
|
+
*,
|
|
36
|
+
allow_always: bool = False,
|
|
37
|
+
allow_never: bool = False,
|
|
38
|
+
extra_options: Optional[dict[str, str]] = None,
|
|
39
|
+
detail: Optional[str] = None,
|
|
35
40
|
) -> str:
|
|
36
41
|
"""Ask the user to approve an action, returning an :data:`ApprovalDecision`.
|
|
37
42
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
back to a decision.
|
|
43
|
+
Offers ``Approve``/``Deny`` plus the optional choices below as an
|
|
44
|
+
``"approval"`` question on the active interaction backend, and maps the
|
|
45
|
+
chosen label back to a decision.
|
|
42
46
|
|
|
43
47
|
Args:
|
|
44
48
|
prompt: The action to approve, phrased as a question.
|
|
45
49
|
allow_always: Offer an "Always allow" option (a persistent allow).
|
|
46
50
|
allow_never: Offer an "Always deny" option (a persistent deny).
|
|
51
|
+
extra_options: Caller-specific choices, as ``{label: decision}``.
|
|
47
52
|
detail: Extra context appended below the prompt for the user to read.
|
|
48
53
|
|
|
49
54
|
Returns:
|
|
50
|
-
One of ``"approve"``, ``"deny"``, ``"always"``,
|
|
55
|
+
One of ``"approve"``, ``"deny"``, ``"always"``, ``"never"``, or a value of ``extra_options``.
|
|
51
56
|
|
|
52
57
|
Fail-closed: returns ``"deny"`` WITHOUT prompting when there is no backend or
|
|
53
58
|
the backend is non-interactive, and for any unrecognized reply.
|
|
@@ -61,7 +66,9 @@ def request_approval(
|
|
|
61
66
|
options.append(ALWAYS_LABEL)
|
|
62
67
|
if allow_never:
|
|
63
68
|
options.append(NEVER_LABEL)
|
|
69
|
+
decisions = _LABEL_TO_DECISION | (extra_options or {})
|
|
70
|
+
options.extend(extra_options or ())
|
|
64
71
|
|
|
65
72
|
question = f"{prompt}\n\n{detail}" if detail else prompt
|
|
66
73
|
answer = backend.ask_user(question, "approval", options)
|
|
67
|
-
return
|
|
74
|
+
return decisions.get(answer, "deny")
|
|
@@ -6,9 +6,17 @@ extends: none
|
|
|
6
6
|
# volatile memory last, so a change to today's memory / now.md doesn't invalidate
|
|
7
7
|
# the identity files' cache. A flat list would be one block; these are three.
|
|
8
8
|
attachments:
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
- - {path: PERSONA.md, optional: true}
|
|
10
|
+
- {path: SOUL.md, optional: true}
|
|
11
|
+
- {path: USER.md, optional: true}
|
|
12
|
+
- {path: IDENTITY.md, optional: true}
|
|
13
|
+
- {path: AGENTS.md, optional: true}
|
|
14
|
+
- - {path: MEMORY.md, optional: true}
|
|
15
|
+
- {path: "memory/{{ yesterday() }}.md", optional: true}
|
|
16
|
+
- {path: "memory/{{ date_format(datetime.now().replace(day=1) - timedelta(days=1), '%Y-%m') }}.md", optional: true}
|
|
17
|
+
- - {path: "memory/{{ today() }}.md", optional: true}
|
|
18
|
+
- {path: notes/context/now.md, optional: true}
|
|
19
|
+
- {path: NOW.md, optional: true}
|
|
12
20
|
max_turns: 10
|
|
13
21
|
tools:
|
|
14
22
|
- spawn_agent
|
|
@@ -65,7 +73,7 @@ instructions: |
|
|
|
65
73
|
- Break down complex tasks into clear steps
|
|
66
74
|
- Ask clarifying questions when the task is ambiguous
|
|
67
75
|
- Write Python code to accomplish tasks
|
|
68
|
-
-
|
|
76
|
+
- When you've completed the task, reply in plain text, or call return_value() for structured output
|
|
69
77
|
- If you intend to call multiple tools and there are no dependencies between the calls, make all independent calls in a single code block
|
|
70
78
|
- Never guess about code you have not read. Use read_file or list_files to investigate before answering questions about code
|
|
71
79
|
|
|
@@ -227,13 +235,6 @@ You have running tmux sessions that you can interact with using tmux tools (tmux
|
|
|
227
235
|
{% endfor %}
|
|
228
236
|
{% endif %}
|
|
229
237
|
|
|
230
|
-
{% if "run" in tools and "tmux_create" in tools %}
|
|
231
|
-
## Shell vs Tmux
|
|
232
|
-
|
|
233
|
-
- Use `run()` for commands that produce output and exit: `run("ls -la")`, `run("git status")`, `run("python script.py")`
|
|
234
|
-
- Use tmux tools for interactive programs (htop, k9s, psql, python REPL), long-running processes you want to monitor, or when you need a persistent shell session where state carries across commands
|
|
235
|
-
{% endif %}
|
|
236
|
-
|
|
237
238
|
{% if subagent_instructions is defined and subagent_instructions %}
|
|
238
239
|
{{ subagent_instructions }}
|
|
239
240
|
{% endif %}
|
|
@@ -291,11 +292,11 @@ Load these skills for specialized knowledge:
|
|
|
291
292
|
- **{{ skill.name }}** - {{ skill.description }}
|
|
292
293
|
{% endfor %}
|
|
293
294
|
|
|
294
|
-
Call `load_skill("skill_name")` and stop. The skill content appears next turn as `<
|
|
295
|
+
Call `load_skill("skill_name")` and stop. The skill content appears next turn as `<skill_content>`. Then use what you learned.
|
|
295
296
|
|
|
296
297
|
Do not act in the same turn you load a skill. Skip loading if you already know how to do the task.
|
|
297
298
|
|
|
298
|
-
Skills may show bash commands. Translate to Python: `
|
|
299
|
+
Skills may show bash commands. Translate to Python: `run("kubectl get pods")`
|
|
299
300
|
</available_skills>
|
|
300
301
|
{% endif %}
|
|
301
302
|
|
|
@@ -76,7 +76,9 @@ is `true` only if every `ac_results[i].pass` is `true`.
|
|
|
76
76
|
|
|
77
77
|
`reason` opens with the basis for the verdict, then one sentence:
|
|
78
78
|
|
|
79
|
-
- `inspected:` - you read the artifact
|
|
79
|
+
- `inspected:` - you read the artifact or file yourself with a tool call.
|
|
80
|
+
- `read Output:` - the deliverable is inline text and you judged the `## Output`
|
|
81
|
+
text itself, with no tool call.
|
|
80
82
|
- `ran <command>:` - you executed the command and judged its exit status.
|
|
81
83
|
- `accepted worker claim:` - you could not check it, so the verdict rests on
|
|
82
84
|
the worker's report.
|
{tsugite_cli-0.24.0 → tsugite_cli-0.25.0}/tsugite/builtin_skills/codebase-exploration/SKILL.md
RENAMED
|
@@ -365,7 +365,7 @@ If available via custom tools configuration, consider using:
|
|
|
365
365
|
tools:
|
|
366
366
|
- name: ast_search
|
|
367
367
|
description: Search code using AST patterns
|
|
368
|
-
command: "ast-grep -p
|
|
368
|
+
command: "ast-grep -p {pattern} {path}"
|
|
369
369
|
parameters:
|
|
370
370
|
pattern: {required: true}
|
|
371
371
|
path: "."
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: response-patterns
|
|
3
|
-
description: How to respond effectively - when to use print/send_message/
|
|
3
|
+
description: How to respond effectively - when to use print/send_message/return_value/ask_user
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Response Patterns
|
|
@@ -11,21 +11,18 @@ description: How to respond effectively - when to use print/send_message/final_a
|
|
|
11
11
|
|----------|----------|-----------|---------|
|
|
12
12
|
| `print(x)` | You (next turn) | Continues | Intermediate data |
|
|
13
13
|
| `send_message(msg)` | User | Continues | Progress updates |
|
|
14
|
-
| `
|
|
14
|
+
| `return_value(value)` | User | **Stops** | Structured final result |
|
|
15
15
|
| `ask_user(q)` | User | **Blocks** | Get user input |
|
|
16
16
|
|
|
17
17
|
## Simple Responses
|
|
18
18
|
|
|
19
|
-
No functions needed?
|
|
19
|
+
No functions needed? Reply in plain text:
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
- "Thanks" replies `You're welcome!`
|
|
22
|
+
- "What's 2+2?" replies `4`
|
|
23
|
+
- "What can you do?" replies `I can read/write files, run commands, and help with tasks.`
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
- "Thanks" → `final_answer("You're welcome!")`
|
|
27
|
-
- "What's 2+2?" → `final_answer("4")`
|
|
28
|
-
- "What can you do?" → `final_answer("I can read/write files, run commands, search code, and help with tasks.")`
|
|
25
|
+
Call `return_value(value)` only when the caller needs a structured result.
|
|
29
26
|
|
|
30
27
|
## Progress Updates
|
|
31
28
|
|
|
@@ -33,14 +30,14 @@ For longer tasks, keep user informed:
|
|
|
33
30
|
|
|
34
31
|
```python-exec
|
|
35
32
|
send_message("Searching codebase...")
|
|
36
|
-
results =
|
|
33
|
+
results = run("grep -rn 'def main' .")
|
|
37
34
|
print(results) # You'll see this next turn
|
|
38
35
|
```
|
|
39
36
|
|
|
40
37
|
```python-exec
|
|
41
|
-
send_message(f"Found {len(results)} matches. Analyzing...")
|
|
38
|
+
send_message(f"Found {len(results.splitlines())} matches. Analyzing...")
|
|
42
39
|
# ... more work ...
|
|
43
|
-
|
|
40
|
+
return_value("Here's what I found: ...")
|
|
44
41
|
```
|
|
45
42
|
|
|
46
43
|
## Asking the User
|
|
@@ -87,7 +84,7 @@ Use `ask_user` when:
|
|
|
87
84
|
- Ask unnecessary questions when a reasonable default exists
|
|
88
85
|
|
|
89
86
|
✅ Do:
|
|
90
|
-
-
|
|
87
|
+
- Plain text immediately for simple responses
|
|
91
88
|
- `send_message()` for progress on tasks > 5 seconds
|
|
92
89
|
- `ask_user()` when you genuinely need user input
|
|
93
90
|
- `print()` only for data YOU need to see
|
|
@@ -500,8 +500,8 @@ class PathContext:
|
|
|
500
500
|
effective_cwd: Path
|
|
501
501
|
|
|
502
502
|
|
|
503
|
-
#
|
|
504
|
-
# that don't receive PathContext explicitly. Task-local so concurrent agent runs
|
|
503
|
+
# The directory the running agent's code and fs tools work in, for call sites
|
|
504
|
+
# (fs tools, shell, subprocesses, the executor) that don't receive PathContext explicitly. Task-local so concurrent agent runs
|
|
505
505
|
# don't share state.
|
|
506
506
|
_workspace_dir_cv: contextvars.ContextVar[Optional[Path]] = contextvars.ContextVar("workspace_dir", default=None)
|
|
507
507
|
|
|
@@ -257,7 +257,6 @@ def run(
|
|
|
257
257
|
),
|
|
258
258
|
no_workspace: bool = typer.Option(False, "--no-workspace", help="Disable workspace (ignore default workspace)"),
|
|
259
259
|
new_session: bool = typer.Option(False, "--new-session", help="Start fresh session (ignore workspace session)"),
|
|
260
|
-
join_daemon: bool = typer.Option(False, "--daemon", "-d", help="Join the daemon's most recent session"),
|
|
261
260
|
sandbox: bool = typer.Option(False, "--sandbox", help="Run agent code in bubblewrap sandbox"),
|
|
262
261
|
no_sandbox: bool = typer.Option(False, "--no-sandbox", help="Disable sandbox (overrides config)"),
|
|
263
262
|
allow_domain: Optional[List[str]] = typer.Option(
|
|
@@ -282,7 +281,6 @@ def run(
|
|
|
282
281
|
tsu run --continue "prompt" # Continue latest conversation (auto-detect agent)
|
|
283
282
|
tsu run +assistant --continue "prompt" # Continue latest with specific agent
|
|
284
283
|
tsu run --continue --conversation-id CONV_ID "prompt" # Continue specific conversation
|
|
285
|
-
tsu run --daemon "follow up message" # Join the daemon's most recent session
|
|
286
284
|
"""
|
|
287
285
|
from tsugite.agent_runner import get_agent_info, run_agent
|
|
288
286
|
from tsugite.console import get_stderr_console
|
|
@@ -381,7 +379,7 @@ def run(
|
|
|
381
379
|
# Resolve UI mode to update ui_opts
|
|
382
380
|
ui_opts = _resolve_ui_mode(ui, ui_opts, stderr_console)
|
|
383
381
|
|
|
384
|
-
# Handle subagent mode
|
|
382
|
+
# Handle subagent mode
|
|
385
383
|
import os
|
|
386
384
|
|
|
387
385
|
if subagent_mode:
|
|
@@ -393,54 +391,6 @@ def run(
|
|
|
393
391
|
history_opts.enabled = False
|
|
394
392
|
os.environ["TSUGITE_SUBAGENT_MODE"] = "1"
|
|
395
393
|
|
|
396
|
-
daemon_metadata = None
|
|
397
|
-
if join_daemon:
|
|
398
|
-
from tsugite.agent_runner.history_integration import get_latest_conversation
|
|
399
|
-
|
|
400
|
-
try:
|
|
401
|
-
from tsugite_daemon.config import load_daemon_config
|
|
402
|
-
|
|
403
|
-
# Probe: the daemon battery has to be installed and configured.
|
|
404
|
-
load_daemon_config()
|
|
405
|
-
except ModuleNotFoundError as e:
|
|
406
|
-
stderr_console.print(
|
|
407
|
-
"[red]The daemon battery is not installed.[/red] Install it with: pip install tsugite-cli[daemon]"
|
|
408
|
-
)
|
|
409
|
-
raise typer.Exit(1) from e
|
|
410
|
-
except ValueError as e:
|
|
411
|
-
stderr_console.print(f"[red]Daemon config not found: {e}[/red]")
|
|
412
|
-
stderr_console.print("[dim]Run 'tsugite daemon' to start daemon first[/dim]")
|
|
413
|
-
raise typer.Exit(1)
|
|
414
|
-
|
|
415
|
-
user_id = os.environ.get("USER", "cli-user")
|
|
416
|
-
|
|
417
|
-
latest_conv_id = get_latest_conversation()
|
|
418
|
-
if latest_conv_id:
|
|
419
|
-
stderr_console.print(f"[cyan]Joining daemon session: {latest_conv_id}[/cyan]")
|
|
420
|
-
history_opts.continue_id = latest_conv_id
|
|
421
|
-
else:
|
|
422
|
-
stderr_console.print("[yellow]No active daemon session found[/yellow]")
|
|
423
|
-
stderr_console.print("[dim]Creating new daemon-managed session...[/dim]")
|
|
424
|
-
|
|
425
|
-
# Build CLI metadata for history
|
|
426
|
-
from datetime import datetime, timezone
|
|
427
|
-
|
|
428
|
-
daemon_metadata = {
|
|
429
|
-
"source": "cli",
|
|
430
|
-
"channel_id": None,
|
|
431
|
-
"user_id": user_id,
|
|
432
|
-
"reply_to": "cli",
|
|
433
|
-
"is_daemon_managed": True,
|
|
434
|
-
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
all_attachments = list(attachment) if attachment else []
|
|
438
|
-
attach_opts = AttachmentOptions(
|
|
439
|
-
sources=all_attachments,
|
|
440
|
-
refresh_cache=refresh_cache,
|
|
441
|
-
auto_context=auto_context,
|
|
442
|
-
)
|
|
443
|
-
|
|
444
394
|
# Handle conversation continuation - check before parsing args
|
|
445
395
|
if continue_conversation and not history_opts.continue_id:
|
|
446
396
|
from tsugite.agent_runner.history_integration import get_latest_conversation
|
|
@@ -641,7 +591,6 @@ def run(
|
|
|
641
591
|
continue_conversation_id=target_session,
|
|
642
592
|
system_prompt=system_prompt,
|
|
643
593
|
attachments=attachments,
|
|
644
|
-
channel_metadata=daemon_metadata,
|
|
645
594
|
status=status,
|
|
646
595
|
error_message=error_message,
|
|
647
596
|
)
|