cade-cli 0.20.2__tar.gz → 0.20.4__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.
- {cade_cli-0.20.2 → cade_cli-0.20.4}/PKG-INFO +2 -2
- {cade_cli-0.20.2 → cade_cli-0.20.4}/pyproject.toml +1 -1
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/core/agent.py +2 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/core/config.py +9 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/core/runtime.py +1 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/gateway/app.py +5 -2
- cade_cli-0.20.4/src/cadecoder/daemon/gateway/principal.py +40 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/gateway/resources.py +6 -3
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/install.py +17 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/runner.py +11 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/supervisor.py +37 -2
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/execution/context_window.py +12 -3
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/execution/orchestrator.py +17 -1
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/providers/anthropic.py +1 -1
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/providers/base.py +3 -1
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/providers/openai.py +4 -1
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/telemetry/otel.py +17 -1
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/templates/serve/launchd.plist.tmpl +2 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/templates/serve/systemd.service.tmpl +1 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/ui/session.py +6 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/.gitignore +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/LICENSE +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/README.md +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/__main__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/_metadata.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/config.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/errors.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/grants.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/resources.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/sandbox.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/server.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/tools/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/tools/_read_cache.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/tools/access.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/tools/agents.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/tools/filesystem.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/tools/git.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/tools/notifications.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/tools/questions.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/tools/results.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/tools/schemas.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/tools/search.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/tools/shell.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/tools/tasks.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/tools/web_fetch.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/tools/web_search.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/utils.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/web/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/web/arcade_client.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/web/cache.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/web/extract.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/web/markdown.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/web/preapproved.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/web/prompts.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/web/scrape.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/web/search/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/web/search/arcade.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/web/search/base.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cade_mcp_local/web/search/http.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/ai/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/ai/prompts.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/cli/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/cli/app.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/cli/auth.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/cli/commands/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/cli/commands/account.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/cli/commands/agent_group.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/cli/commands/agents.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/cli/commands/auth.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/cli/commands/chat.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/cli/commands/cron.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/cli/commands/daemon.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/cli/commands/grant.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/cli/commands/hooks.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/cli/commands/mcp.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/cli/commands/mem.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/cli/commands/tasks.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/cli/commands/thread.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/cli/commands/tools.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/cli/mcp_hosts.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/cli/onboarding.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/cli/ui.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/core/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/core/binary.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/core/comms.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/core/constants.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/core/errors.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/core/frozen.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/core/git.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/core/inbox.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/core/logging.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/core/memory.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/core/model_specs.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/core/names.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/core/paths.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/core/secrets.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/core/spawn.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/core/text.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/core/types.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/adapters/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/adapters/base.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/adapters/factory.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/adapters/imessage.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/adapters/registry.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/adapters/stub.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/adapters/telegram.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/allowlist.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/attach.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/chunker.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/client.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/commands.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/config.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/control.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/cron.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/elicitation.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/ensure.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/format.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/gateway/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/gateway/auth.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/gateway/constants.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/gateway/elicitation.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/gateway/exposure.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/gateway/host_agent.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/gateway/limits.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/gateway/middleware.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/gateway/subscriptions.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/gateway/turn_bridge.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/grants.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/inbox.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/inbox_cron.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/lock.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/mesh.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/message_pump.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/observability.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/owner.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/progress_sink.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/registry.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/router.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/runner_main.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/secrets.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/secrets_broker.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/server.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/services.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/sinks.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/tokens.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/traffic.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/turns.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/daemon/wake.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/execution/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/execution/mcp_schema_index.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/execution/parallel.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/execution/tool_result_store.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/execution/tool_schema_cache.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/hooks/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/hooks/config.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/hooks/engine.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/hooks/executors/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/hooks/executors/callback.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/hooks/executors/command.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/hooks/executors/http.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/hooks/executors/prompt.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/hooks/executors/ssrf_guard.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/hooks/matchers.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/hooks/registry.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/hooks/types.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/host_plugin/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/host_plugin/assets/.claude-plugin/marketplace.json +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/host_plugin/assets/.claude-plugin/plugin.json +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/host_plugin/assets/.cursor-plugin/marketplace.json +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/host_plugin/assets/.cursor-plugin/plugin.json +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/host_plugin/assets/agents/operator.md +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/host_plugin/assets/commands/ask.md +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/host_plugin/assets/commands/memory.md +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/host_plugin/assets/commands/tasks.md +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/host_plugin/assets/mcp.json +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/host_plugin/assets/rules/gateway.mdc +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/host_plugin/assets/skills/ask/SKILL.md +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/host_plugin/assets/skills/memory/SKILL.md +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/host_plugin/assets/skills/tasks/SKILL.md +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/host_plugin/doctor.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/host_plugin/install.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/host_plugin/paths.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/host_plugin/state.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/providers/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/providers/http_client.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/providers/ollama.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/storage/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/storage/threads.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/tasks/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/tasks/scheduler.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/tasks/store.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/tasks/types.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/telemetry/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/templates/login_failed.html +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/templates/login_success.html +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/templates/serve/serve.toml.example +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/templates/styles.css +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/tools/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/tools/manager/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/tools/manager/_request_ctx.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/tools/manager/base.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/tools/manager/composite.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/tools/manager/config.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/tools/manager/mcp.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/tools/search/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/tools/search/discovered.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/tools/search/scoring.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/tools/search/service.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/ui/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/ui/completion.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/ui/display.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/ui/elicitation.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/ui/input.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/ui/slash.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/voice/__init__.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/voice/audio.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/voice/cleanup.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/voice/session.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/voice/stt.py +0 -0
- {cade_cli-0.20.2 → cade_cli-0.20.4}/src/cadecoder/voice/tts.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: cade-cli
|
|
3
|
-
Version: 0.20.
|
|
3
|
+
Version: 0.20.4
|
|
4
4
|
Summary: Cade - The CLI Agent from Arcade.dev (install: curl -fsSL https://arcadeagent.dev/install | sh)
|
|
5
5
|
Project-URL: Homepage, https://arcade.dev
|
|
6
6
|
Project-URL: Documentation, https://arcadeagent.dev/docs
|
|
@@ -120,6 +120,8 @@ class AgentConfig(BaseModel):
|
|
|
120
120
|
model: str = constants.DEFAULT_AI_MODEL
|
|
121
121
|
provider: str | None = None
|
|
122
122
|
temperature: float | None = None
|
|
123
|
+
# Overrides the model registry's context window (tokens) for this agent.
|
|
124
|
+
context_window: int | None = None
|
|
123
125
|
|
|
124
126
|
# Personality
|
|
125
127
|
system_prompt: str | None = None
|
|
@@ -54,6 +54,9 @@ class GlobalConfig(BaseModel):
|
|
|
54
54
|
provider: str = "anthropic"
|
|
55
55
|
model: str = constants.DEFAULT_AI_MODEL
|
|
56
56
|
temperature: float | None = None
|
|
57
|
+
# Overrides the model registry's context window (tokens). Per-agent
|
|
58
|
+
# ``context_window`` in ``config/agents/<name>.toml`` takes precedence.
|
|
59
|
+
context_window: int | None = None
|
|
57
60
|
debug_mode: bool = False
|
|
58
61
|
voice: VoiceConfig = Field(default_factory=VoiceConfig)
|
|
59
62
|
ui: UIConfig = Field(default_factory=UIConfig)
|
|
@@ -192,6 +195,11 @@ def build_runtime():
|
|
|
192
195
|
if active_agent.temperature is not None
|
|
193
196
|
else global_config.temperature
|
|
194
197
|
)
|
|
198
|
+
context_window = (
|
|
199
|
+
active_agent.context_window
|
|
200
|
+
if active_agent.context_window is not None
|
|
201
|
+
else global_config.context_window
|
|
202
|
+
)
|
|
195
203
|
runtime = RuntimeEnvironment(
|
|
196
204
|
paths=paths,
|
|
197
205
|
context_name=active_agent.id,
|
|
@@ -201,6 +209,7 @@ def build_runtime():
|
|
|
201
209
|
model=model,
|
|
202
210
|
provider=provider,
|
|
203
211
|
temperature=temperature,
|
|
212
|
+
context_window=context_window,
|
|
204
213
|
agent=active_agent,
|
|
205
214
|
)
|
|
206
215
|
runtime.ensure_dirs()
|
|
@@ -24,6 +24,7 @@ from cadecoder.daemon.gateway.exposure import LOCAL_GROUPS, ExposurePolicy
|
|
|
24
24
|
from cadecoder.daemon.gateway.host_agent import get_host_agent
|
|
25
25
|
from cadecoder.daemon.gateway.limits import PrincipalLimits
|
|
26
26
|
from cadecoder.daemon.gateway.middleware import ExposureMiddleware, HostAgentMiddleware
|
|
27
|
+
from cadecoder.daemon.gateway.principal import local_principal
|
|
27
28
|
from cadecoder.daemon.gateway.resources import register_gateway_resources
|
|
28
29
|
from cadecoder.daemon.gateway.turn_bridge import TurnBridge, TurnBridgeError
|
|
29
30
|
from cadecoder.daemon.supervisor import Supervisor
|
|
@@ -56,9 +57,11 @@ def _principal_and_policy(context: Context) -> tuple[str, list[str], list[str]]:
|
|
|
56
57
|
"""
|
|
57
58
|
owner = getattr(context, "_resource_owner", None)
|
|
58
59
|
if owner is None:
|
|
59
|
-
return
|
|
60
|
+
return local_principal(context), [], list(LOCAL_GROUPS)
|
|
60
61
|
claims = getattr(owner, "claims", {}) or {}
|
|
61
|
-
principal = str(
|
|
62
|
+
principal = str(
|
|
63
|
+
claims.get("cade_principal") or getattr(context, "user_id", "") or local_principal(context)
|
|
64
|
+
)
|
|
62
65
|
agents = claims.get("cade_agents")
|
|
63
66
|
expose = claims.get("cade_expose")
|
|
64
67
|
return (
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Shared principal fallback for unauthenticated (loopback/local) MCP callers.
|
|
2
|
+
|
|
3
|
+
Used by both the ``Cade_Ask`` tool (``app.py``) and the ``threads://``
|
|
4
|
+
resource listing (``resources.py``) so a thread written under one is found
|
|
5
|
+
under the other.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import re
|
|
11
|
+
|
|
12
|
+
from arcade_mcp_server import Context
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def client_app_name(context: Context | None) -> str | None:
|
|
16
|
+
"""Best-effort slug of the connecting MCP client (e.g. ``claude``, ``cursor``).
|
|
17
|
+
|
|
18
|
+
Read from the ``clientInfo.name`` negotiated during MCP ``initialize``.
|
|
19
|
+
Returns ``None`` when unavailable, so the caller can fall back to a flat
|
|
20
|
+
``"local"`` principal.
|
|
21
|
+
"""
|
|
22
|
+
session = getattr(context, "_session", None)
|
|
23
|
+
params = getattr(session, "client_params", None)
|
|
24
|
+
client_info = getattr(params, "clientInfo", None)
|
|
25
|
+
name = getattr(client_info, "name", None)
|
|
26
|
+
if not name:
|
|
27
|
+
return None
|
|
28
|
+
slug = re.sub(r"[^a-z0-9]+", "-", name.strip().lower()).strip("-")
|
|
29
|
+
return slug or None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def local_principal(context: Context | None) -> str:
|
|
33
|
+
"""Principal for an unauthenticated (loopback/local) caller.
|
|
34
|
+
|
|
35
|
+
Scoped per connecting app when its ``clientInfo.name`` is known, so e.g.
|
|
36
|
+
Claude Desktop and Cursor each keep their own default thread rather than
|
|
37
|
+
sharing one ``local:default`` conversation across every local MCP client.
|
|
38
|
+
"""
|
|
39
|
+
app_name = client_app_name(context)
|
|
40
|
+
return f"local:{app_name}" if app_name else "local"
|
|
@@ -30,6 +30,7 @@ from cadecoder.daemon.gateway.constants import (
|
|
|
30
30
|
THREADS_URI,
|
|
31
31
|
)
|
|
32
32
|
from cadecoder.daemon.gateway.host_agent import active_agent_name, get_host_agent
|
|
33
|
+
from cadecoder.daemon.gateway.principal import local_principal
|
|
33
34
|
from cadecoder.storage.threads import BaseThreadHistory, get_thread_history
|
|
34
35
|
|
|
35
36
|
if TYPE_CHECKING:
|
|
@@ -37,13 +38,15 @@ if TYPE_CHECKING:
|
|
|
37
38
|
|
|
38
39
|
|
|
39
40
|
def _current_principal() -> str:
|
|
40
|
-
"""Principal name from the active model context;
|
|
41
|
+
"""Principal name from the active model context; scoped per local app when unauthenticated."""
|
|
41
42
|
context = get_current_model_context()
|
|
42
43
|
owner = getattr(context, "_resource_owner", None) if context else None
|
|
43
44
|
if owner is None:
|
|
44
|
-
return
|
|
45
|
+
return local_principal(context)
|
|
45
46
|
claims = getattr(owner, "claims", {}) or {}
|
|
46
|
-
return str(
|
|
47
|
+
return str(
|
|
48
|
+
claims.get("cade_principal") or getattr(owner, "user_id", "") or local_principal(context)
|
|
49
|
+
)
|
|
47
50
|
|
|
48
51
|
|
|
49
52
|
def _active_agent_name() -> str:
|
|
@@ -199,6 +199,22 @@ def _log_path() -> str:
|
|
|
199
199
|
|
|
200
200
|
|
|
201
201
|
def _common_vars() -> dict[str, str]:
|
|
202
|
+
"""Template substitutions for launchd/systemd unit files.
|
|
203
|
+
|
|
204
|
+
``CADE_OTEL`` is ``1`` when the env is already set or
|
|
205
|
+
``~/.cade/config/otel.enable`` exists, so a service reinstall picks up
|
|
206
|
+
tracing without hand-editing the unit.
|
|
207
|
+
"""
|
|
208
|
+
otel_on = (
|
|
209
|
+
os.environ.get("CADE_OTEL", "").strip().lower()
|
|
210
|
+
in (
|
|
211
|
+
"1",
|
|
212
|
+
"true",
|
|
213
|
+
"yes",
|
|
214
|
+
"on",
|
|
215
|
+
)
|
|
216
|
+
or (get_runtime().paths.config_dir / "otel.enable").is_file()
|
|
217
|
+
)
|
|
202
218
|
return {
|
|
203
219
|
"LABEL": _LABEL,
|
|
204
220
|
"CADE_BIN": _cade_binary(),
|
|
@@ -207,6 +223,7 @@ def _common_vars() -> dict[str, str]:
|
|
|
207
223
|
"HOME": str(Path.home()),
|
|
208
224
|
"PATH": os.environ.get("PATH", "/usr/local/bin:/usr/bin:/bin"),
|
|
209
225
|
"LOG_PATH": _log_path(),
|
|
226
|
+
"CADE_OTEL": "1" if otel_on else "0",
|
|
210
227
|
}
|
|
211
228
|
|
|
212
229
|
|
|
@@ -74,6 +74,7 @@ class InProcessRunner:
|
|
|
74
74
|
defer_user_mcp_schemas: str = "auto",
|
|
75
75
|
) -> None:
|
|
76
76
|
self.agent_name = agent_name
|
|
77
|
+
self.model = model
|
|
77
78
|
self._orchestrator = orchestrator or create_orchestrator(
|
|
78
79
|
default_model=model,
|
|
79
80
|
persona=persona or agent_name,
|
|
@@ -84,6 +85,7 @@ class InProcessRunner:
|
|
|
84
85
|
# threads proceed concurrently (subject to TurnRunner's global gate).
|
|
85
86
|
self._thread_locks: dict[str, asyncio.Lock] = {}
|
|
86
87
|
self.last_active_at = time.monotonic()
|
|
88
|
+
log.info(f"InProcessRunner ready agent={agent_name!r} model={model}")
|
|
87
89
|
|
|
88
90
|
def _lock_for(self, thread_id: str) -> asyncio.Lock:
|
|
89
91
|
lock = self._thread_locks.get(thread_id)
|
|
@@ -146,6 +148,15 @@ class SubprocessRunner:
|
|
|
146
148
|
writer: asyncio.StreamWriter | None = None,
|
|
147
149
|
) -> None:
|
|
148
150
|
self.agent_name = agent_name
|
|
151
|
+
# Mirror the agent's configured model so the supervisor can detect
|
|
152
|
+
# stale subprocess runners after ``cade account init``.
|
|
153
|
+
try:
|
|
154
|
+
from cadecoder.core import agent as agent_mod
|
|
155
|
+
|
|
156
|
+
agent = agent_mod.resolve(agent_name)
|
|
157
|
+
self.model = agent.model if agent is not None else ""
|
|
158
|
+
except Exception: # noqa: BLE001
|
|
159
|
+
self.model = ""
|
|
149
160
|
self.last_active_at = time.monotonic()
|
|
150
161
|
self._reader = reader
|
|
151
162
|
self._writer = writer
|
|
@@ -81,9 +81,13 @@ class Supervisor:
|
|
|
81
81
|
|
|
82
82
|
Concurrent callers for the same agent share one start via a per-agent
|
|
83
83
|
lock, so a burst of gateway calls never spawns duplicate runners.
|
|
84
|
+
|
|
85
|
+
If the agent's configured model changed since the runner was created
|
|
86
|
+
(e.g. after ``cade account init``), the stale runner is replaced so
|
|
87
|
+
chat does not keep calling the previous provider until idle eviction.
|
|
84
88
|
"""
|
|
85
89
|
existing = self._runners.get(agent_name)
|
|
86
|
-
if existing is not None:
|
|
90
|
+
if existing is not None and not self._runner_is_stale(agent_name, existing):
|
|
87
91
|
return existing
|
|
88
92
|
|
|
89
93
|
async with self._lock:
|
|
@@ -94,14 +98,45 @@ class Supervisor:
|
|
|
94
98
|
|
|
95
99
|
async with start_lock:
|
|
96
100
|
existing = self._runners.get(agent_name)
|
|
97
|
-
if existing is not None:
|
|
101
|
+
if existing is not None and not self._runner_is_stale(agent_name, existing):
|
|
98
102
|
return existing
|
|
103
|
+
if existing is not None:
|
|
104
|
+
log.info(
|
|
105
|
+
f"recycling runner for agent {agent_name!r} (config model changed since start)"
|
|
106
|
+
)
|
|
107
|
+
self._runners.pop(agent_name, None)
|
|
108
|
+
try:
|
|
109
|
+
await existing.aclose()
|
|
110
|
+
except Exception as exc: # noqa: BLE001
|
|
111
|
+
log.debug(f"stale runner close failed for {agent_name!r}: {exc}")
|
|
99
112
|
created = self._factory(agent_name)
|
|
100
113
|
runner: RunnerHandle = await created if asyncio.iscoroutine(created) else created
|
|
101
114
|
self._runners[agent_name] = runner
|
|
102
115
|
log.info(f"started runner for agent {agent_name!r}")
|
|
103
116
|
return runner
|
|
104
117
|
|
|
118
|
+
def _runner_is_stale(self, agent_name: str, runner: RunnerHandle) -> bool:
|
|
119
|
+
"""True when the cached runner's model no longer matches agent config."""
|
|
120
|
+
try:
|
|
121
|
+
agent = agent_mod.resolve(agent_name)
|
|
122
|
+
except Exception: # noqa: BLE001
|
|
123
|
+
return False
|
|
124
|
+
if agent is None:
|
|
125
|
+
return False
|
|
126
|
+
runner_model = getattr(runner, "model", None)
|
|
127
|
+
if runner_model is None:
|
|
128
|
+
orch = getattr(runner, "_orchestrator", None)
|
|
129
|
+
runner_model = getattr(orch, "default_model", None)
|
|
130
|
+
if not runner_model:
|
|
131
|
+
return False
|
|
132
|
+
if runner_model == agent.model:
|
|
133
|
+
return False
|
|
134
|
+
log.warning(
|
|
135
|
+
f"agent {agent_name!r} model is {agent.model!r} but runner still has "
|
|
136
|
+
f"{runner_model!r} — will recreate"
|
|
137
|
+
)
|
|
138
|
+
return True
|
|
139
|
+
|
|
105
140
|
def running_agents(self) -> list[str]:
|
|
106
141
|
return sorted(self._runners)
|
|
107
142
|
|
|
@@ -191,6 +191,7 @@ class ContextWindowManager:
|
|
|
191
191
|
model: str = DEFAULT_AI_MODEL,
|
|
192
192
|
backup_dir: Path | None = None,
|
|
193
193
|
chars_per_token: float = 4.0,
|
|
194
|
+
context_window_override: int | None = None,
|
|
194
195
|
) -> None:
|
|
195
196
|
"""Initialize context window manager.
|
|
196
197
|
|
|
@@ -198,12 +199,15 @@ class ContextWindowManager:
|
|
|
198
199
|
model: Model name for context limit lookup
|
|
199
200
|
backup_dir: Directory for storing context backups
|
|
200
201
|
chars_per_token: Character to token ratio for estimation
|
|
202
|
+
context_window_override: User-configured context window (tokens)
|
|
203
|
+
that takes precedence over the model registry's value
|
|
201
204
|
"""
|
|
202
205
|
self.model = model
|
|
203
206
|
self.chars_per_token = chars_per_token
|
|
204
207
|
|
|
205
|
-
# Context window and response reserve come from the central model
|
|
206
|
-
|
|
208
|
+
# Context window and response reserve come from the central model
|
|
209
|
+
# registry, unless the user has overridden the window size in config.
|
|
210
|
+
self.context_limit = context_window_override or model_specs.context_window(model)
|
|
207
211
|
self.response_reserve = model_specs.max_output_tokens(model)
|
|
208
212
|
self.effective_limit = self.context_limit - self.response_reserve
|
|
209
213
|
|
|
@@ -888,17 +892,22 @@ class ContextWindowManager:
|
|
|
888
892
|
def create_context_manager(
|
|
889
893
|
model: str = DEFAULT_AI_MODEL,
|
|
890
894
|
backup_dir: Path | None = None,
|
|
895
|
+
context_window_override: int | None = None,
|
|
891
896
|
) -> ContextWindowManager:
|
|
892
897
|
"""Factory function to create a context window manager.
|
|
893
898
|
|
|
894
899
|
Args:
|
|
895
900
|
model: Model name for context limit lookup
|
|
896
901
|
backup_dir: Directory for storing context backups
|
|
902
|
+
context_window_override: User-configured context window (tokens)
|
|
903
|
+
that takes precedence over the model registry's value
|
|
897
904
|
|
|
898
905
|
Returns:
|
|
899
906
|
Configured ContextWindowManager instance
|
|
900
907
|
"""
|
|
901
|
-
return ContextWindowManager(
|
|
908
|
+
return ContextWindowManager(
|
|
909
|
+
model=model, backup_dir=backup_dir, context_window_override=context_window_override
|
|
910
|
+
)
|
|
902
911
|
|
|
903
912
|
|
|
904
913
|
__all__ = [
|
|
@@ -204,7 +204,9 @@ class Orchestrator:
|
|
|
204
204
|
# Context window backups are scoped to the active context.
|
|
205
205
|
backup_dir = runtime.context_backups_dir
|
|
206
206
|
self.context_manager = context_manager or create_context_manager(
|
|
207
|
-
model=self.default_model,
|
|
207
|
+
model=self.default_model,
|
|
208
|
+
backup_dir=backup_dir,
|
|
209
|
+
context_window_override=runtime.context_window,
|
|
208
210
|
)
|
|
209
211
|
|
|
210
212
|
# Tool result store — uses CADE_TOOL_RESULT_DIR env var (set by create_orchestrator)
|
|
@@ -295,6 +297,20 @@ class Orchestrator:
|
|
|
295
297
|
while should_continue and iteration < MAX_EXECUTION_ITERATIONS:
|
|
296
298
|
iteration += 1
|
|
297
299
|
log.info(f"Execution iteration {iteration}")
|
|
300
|
+
provider_label = ""
|
|
301
|
+
try:
|
|
302
|
+
provider_label = str(
|
|
303
|
+
getattr(getattr(self.provider, "provider_type", None), "value", "")
|
|
304
|
+
or getattr(self.provider, "provider_type", "")
|
|
305
|
+
or ""
|
|
306
|
+
)
|
|
307
|
+
except Exception: # noqa: BLE001
|
|
308
|
+
provider_label = type(self.provider).__name__
|
|
309
|
+
base_url = getattr(self.provider, "base_url", None) or ""
|
|
310
|
+
log.info(
|
|
311
|
+
f"LLM call model={self.default_model} provider={provider_label or '?'} "
|
|
312
|
+
f"base_url={base_url or 'default'} tools={len(tools) if tools else 0}"
|
|
313
|
+
)
|
|
298
314
|
|
|
299
315
|
# Drain task/notification queue as system messages so the LLM
|
|
300
316
|
# sees pending task completions before the next provider call.
|
|
@@ -414,7 +414,7 @@ class AnthropicProvider(Provider):
|
|
|
414
414
|
# Convert tools from OpenAI format to Anthropic format
|
|
415
415
|
if request.tools:
|
|
416
416
|
anthropic_request["tools"] = self._convert_tools_to_anthropic(request.tools)
|
|
417
|
-
log.info(f"Anthropic request
|
|
417
|
+
log.info(f"Anthropic request model={request.model} tools={len(request.tools)}")
|
|
418
418
|
tool_names = [t.get("function", {}).get("name", "unknown") for t in request.tools[:5]]
|
|
419
419
|
log.debug(f"First few tools: {tool_names}")
|
|
420
420
|
|
|
@@ -238,7 +238,9 @@ async def stream_with_retry(
|
|
|
238
238
|
await asyncio.sleep(delay)
|
|
239
239
|
|
|
240
240
|
assert last_exc is not None
|
|
241
|
-
log.error(
|
|
241
|
+
log.error(
|
|
242
|
+
f"{provider.provider_type.value} streaming failed: {type(last_exc).__name__}: {last_exc!r}"
|
|
243
|
+
)
|
|
242
244
|
yield StreamEvent(
|
|
243
245
|
type="error",
|
|
244
246
|
content=provider.format_error_for_user(last_exc),
|
|
@@ -353,7 +353,10 @@ class OpenAIProvider(Provider):
|
|
|
353
353
|
|
|
354
354
|
if request.tools:
|
|
355
355
|
openai_request["tools"] = request.tools
|
|
356
|
-
log.info(
|
|
356
|
+
log.info(
|
|
357
|
+
f"OpenAI request model={request.model} tools={len(request.tools)} "
|
|
358
|
+
f"base_url={self.base_url or 'api.openai.com'}"
|
|
359
|
+
)
|
|
357
360
|
# Log first few tool names for debugging
|
|
358
361
|
tool_names = [t.get("function", {}).get("name", "unknown") for t in request.tools[:5]]
|
|
359
362
|
log.debug(f"First few tools: {tool_names}")
|
|
@@ -177,9 +177,22 @@ def _build_exporter() -> tuple[Any, str]:
|
|
|
177
177
|
return exporter, f"otlp/http:{http_endpoint}"
|
|
178
178
|
|
|
179
179
|
|
|
180
|
+
def _otel_enable_file() -> bool:
|
|
181
|
+
"""True when ``~/.cade/config/otel.enable`` exists (daemon-friendly toggle)."""
|
|
182
|
+
try:
|
|
183
|
+
from cadecoder.core.paths import get_paths
|
|
184
|
+
|
|
185
|
+
return (get_paths().config_dir / "otel.enable").is_file()
|
|
186
|
+
except Exception: # noqa: BLE001
|
|
187
|
+
return False
|
|
188
|
+
|
|
189
|
+
|
|
180
190
|
def init_telemetry(*, force: bool = False) -> bool:
|
|
181
191
|
"""Initialize the tracer provider when ``CADE_OTEL=1``.
|
|
182
192
|
|
|
193
|
+
Also enabled when ``~/.cade/config/otel.enable`` exists so the launchd
|
|
194
|
+
daemon can emit spans without inheriting the chat process env.
|
|
195
|
+
|
|
183
196
|
Safe to call multiple times. Returns True when tracing is live.
|
|
184
197
|
|
|
185
198
|
Args:
|
|
@@ -190,9 +203,12 @@ def init_telemetry(*, force: bool = False) -> bool:
|
|
|
190
203
|
return _enabled
|
|
191
204
|
_initialized = True
|
|
192
205
|
|
|
193
|
-
if not _truthy("CADE_OTEL"):
|
|
206
|
+
if not _truthy("CADE_OTEL") and not _otel_enable_file():
|
|
194
207
|
_enabled = False
|
|
195
208
|
return False
|
|
209
|
+
# Normalize so child helpers that re-check the env see the same gate.
|
|
210
|
+
if not _truthy("CADE_OTEL"):
|
|
211
|
+
os.environ["CADE_OTEL"] = "1"
|
|
196
212
|
|
|
197
213
|
try:
|
|
198
214
|
from opentelemetry import trace
|
|
@@ -108,6 +108,12 @@ def _try_attach_gateway(session: "ChatSession") -> bool:
|
|
|
108
108
|
# Probe the session so cold failures fall back before the first turn.
|
|
109
109
|
session._gateway._ensure_session()
|
|
110
110
|
log.info("chat session attached to cade daemon gateway")
|
|
111
|
+
if os.environ.get("CADE_OTEL", "").strip().lower() in ("1", "true", "yes", "on"):
|
|
112
|
+
log.warning(
|
|
113
|
+
"CADE_OTEL=1 is set on this chat process, but turns run inside the "
|
|
114
|
+
"daemon — export CADE_OTEL=1 for the daemon and restart it "
|
|
115
|
+
"(`cade daemon restart`), or touch ~/.cade/config/otel.enable"
|
|
116
|
+
)
|
|
111
117
|
return True
|
|
112
118
|
except Exception as e: # noqa: BLE001
|
|
113
119
|
# Warning (not debug): autostart is on by default; a silent fallback
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|