devops-bot-sdk 1.6.62__tar.gz → 1.6.64__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.
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/PKG-INFO +1 -1
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/devops_bot_sdk.egg-info/PKG-INFO +1 -1
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/devops_bot_sdk.egg-info/SOURCES.txt +2 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/__init__.py +2 -2
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/cli.py +344 -33
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/client.py +131 -10
- devops_bot_sdk-1.6.64/sdk/custom_agents.py +507 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/tickets.py +81 -48
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/api.py +84 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/models.py +35 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/static/app.js +223 -4
- devops_bot_sdk-1.6.64/sdk/ui/static/custom-agents.html +152 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/static/styles.css +10 -0
- devops_bot_sdk-1.6.64/tests/test_agent_crud_cli.py +740 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_ticket_cli.py +138 -57
- devops_bot_sdk-1.6.62/sdk/ui/static/custom-agents.html +0 -84
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/README.md +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/devops_bot_sdk.egg-info/dependency_links.txt +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/devops_bot_sdk.egg-info/entry_points.txt +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/devops_bot_sdk.egg-info/requires.txt +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/devops_bot_sdk.egg-info/top_level.txt +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/pyproject.toml +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/activity/__init__.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/activity/classifier.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/activity/collectors/__init__.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/activity/collectors/common.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/activity/collectors/linux_auditd.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/activity/collectors/macos_eslogger.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/activity/collectors/windows_eventlog.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/activity/models.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/activity/os_setup.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/activity/recorder.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/activity/redact.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/activity/settings.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/activity/shipper.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/activity/spool.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agentd.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/__init__.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/activity.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/builder.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/chat.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/connectors.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/engines/__init__.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/engines/claude_code.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/engines/http.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/engines/mcp.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/engines/n8n.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/engines/shell.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/integrations.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/inventory.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/library/__init__.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/manifest.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/prompt_studio.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/prompt_template.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/prompt_vars.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/run_log.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/schedules.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/secrets.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/ticket_run.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/usage.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/agents/varstore.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/browser_profile.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/collectors/__init__.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/collectors/files.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/collectors/process.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/collectors/screenshot.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/config.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/crucial.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/departments.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/design_verify/__init__.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/design_verify/assets.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/design_verify/bootstrap.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/design_verify/browser.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/design_verify/compare.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/design_verify/loop.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/estimator.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/exceptions.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/firewall.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/formats.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/git_ops.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/github_fetch.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/github_ingest.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/graph_recon.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/graphify.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/hooks/__init__.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/hooks/crucial_guard.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/intake.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ipc/__init__.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ipc/electron_bridge.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ipc/handlers.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/journal.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/local_exec.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/memory_guard.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/models/__init__.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/models/envelope.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/models/requests.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/models/responses.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/models/snapshots.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/phase_timer.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/plan_run.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/platform_compat.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/prd_progress.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/proof_readers.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/providers.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/py.typed +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/resume.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/router.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/run_auto.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/scheduler.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/self_report.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/self_report_local.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/sse.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/swagger.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/task_file.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/task_types.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/test.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/test_pipeline.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ticket_fields.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/tiers/__init__.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/tiers/mini_agent.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/__init__.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/dashboard.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/health.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/ip_allowlist.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/jobs.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/runner.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/security.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/server.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/service.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/session.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/setup_manager.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/static/agents.html +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/static/chat.html +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/static/default-agents.html +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/static/index.html +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/static/report.html +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/static/runs.html +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/static/schedules.html +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/static/setup.html +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/static/tickets.html +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/ui/swagger.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/updater.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/url_access.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/vendor/aidraftsman-cli-0.1.0.tgz +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/vps_health.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/sdk/write_hook.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/setup.cfg +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_activity_collectors.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_activity_core.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_activity_macos.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_activity_os_setup.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_activity_pipeline.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_agent_activity.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_agent_activity_tracking.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_agent_chat_features.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_agent_listing.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_agent_prompt_async.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_agent_prompt_models.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_agent_run_ticket.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_agent_schedules.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_agent_workspace_settings.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_agents_connectors_builder.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_allowed_tools_config.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_auto_agent_dispatch.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_browser_profile.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_cheap_tier.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_client_jira_projects.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_config_token_diagnostics.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_configure_token_owner.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_console_encoding.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_crash_recovery.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_departments.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_done_transition.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_epic_decompose_run.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_epic_inherited_agent_id.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_epic_session_isolation.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_estimator.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_fallback_cli.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_firewall_open_on_update.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_formats.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_git_action.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_github_fetch.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_github_ingest.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_graph_recon.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_graphify_build.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_graphify_hook_install.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_health.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_intake_job_outcome.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_intake_plan_review.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_journal.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_local_exec_provider.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_mcp_route_contract.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_memory_guard.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_phase_timer.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_plan_new_command.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_plan_run_activity.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_pr_identity.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_prd_artifact.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_project_path_resolution.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_proof_readers.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_providers.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_recon_session_isolation.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_resume.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_router.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_run_auto_agent_only.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_run_outputs.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_run_verdict_is_honest.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_schedule_api.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_schedule_outputs_and_plans.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_scheduler.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_self_report.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_service_token_warning.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_stale_panel_restart.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_swagger_command.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_task_file_and_plan_run.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_task_file_format_doc.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_ticket_fields.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_ticket_run_resolve_by_id.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_ticket_speed_fixes.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_tier_flag_parity.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_ui_gate.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_ui_lifespan.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_update_timer.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_updater_extras.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_updater_pep668.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_updater_reports_the_truth.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_url_access.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_vps_health.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_windows_loop_identity.py +0 -0
- {devops_bot_sdk-1.6.62 → devops_bot_sdk-1.6.64}/tests/test_write_hook.py +0 -0
|
@@ -13,6 +13,7 @@ sdk/cli.py
|
|
|
13
13
|
sdk/client.py
|
|
14
14
|
sdk/config.py
|
|
15
15
|
sdk/crucial.py
|
|
16
|
+
sdk/custom_agents.py
|
|
16
17
|
sdk/departments.py
|
|
17
18
|
sdk/estimator.py
|
|
18
19
|
sdk/exceptions.py
|
|
@@ -147,6 +148,7 @@ tests/test_activity_pipeline.py
|
|
|
147
148
|
tests/test_agent_activity.py
|
|
148
149
|
tests/test_agent_activity_tracking.py
|
|
149
150
|
tests/test_agent_chat_features.py
|
|
151
|
+
tests/test_agent_crud_cli.py
|
|
150
152
|
tests/test_agent_listing.py
|
|
151
153
|
tests/test_agent_prompt_async.py
|
|
152
154
|
tests/test_agent_prompt_models.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""AgentOS Desktop SDK — thin HTTPS/SSE client for the Electron app.
|
|
2
2
|
|
|
3
|
-
Version: 1.6.
|
|
3
|
+
Version: 1.6.64
|
|
4
4
|
|
|
5
5
|
Public surface:
|
|
6
6
|
BackendClient.from_config() — create client from ~/.agentos/config.toml
|
|
@@ -34,7 +34,7 @@ Rules:
|
|
|
34
34
|
- All data egress through submit_webhook only
|
|
35
35
|
"""
|
|
36
36
|
|
|
37
|
-
__version__ = "1.6.
|
|
37
|
+
__version__ = "1.6.64" # SINGLE SOURCE OF TRUTH — bump on every change; pyproject,
|
|
38
38
|
__author__ = "AgentOS" # sdk.client.SDK_VERSION and the UI server version all read this.
|
|
39
39
|
|
|
40
40
|
from sdk.client import BackendClient
|
|
@@ -20,16 +20,28 @@ Command surface:
|
|
|
20
20
|
runs in createdAt order behind anything already queued.
|
|
21
21
|
See sdk.intake.chat_cli.
|
|
22
22
|
|
|
23
|
-
agentos agent
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
23
|
+
agentos agent create --name NAME (--prompt TEXT | --prompt-file PATH)
|
|
24
|
+
[--var NAME[:LABEL[:TYPE[:DESCRIPTION]]]]… [--secret NAME[:DESCRIPTION]]…
|
|
25
|
+
[--skill ID]…
|
|
26
|
+
agentos agent create --from-file PATH
|
|
27
|
+
Create a custom agent through the AI backend (POST /api/v1/agents/custom),
|
|
28
|
+
which evaluates it — a rejection prints the reasons and score — and
|
|
29
|
+
forwards it to the platform; the SDK never writes a DB. PATH holds one JSON body
|
|
30
|
+
({name, prompt:{system_prompt, variables}, skills, secrets, media}) or
|
|
31
|
+
{"agents": [...]} to create many; names you already own are skipped.
|
|
32
|
+
Secrets are NAMES only. Without --var, the {{placeholders}} in the prompt
|
|
33
|
+
become the variables. See sdk.custom_agents — the Custom Agents page of
|
|
34
|
+
the control panel uses the same code.
|
|
35
|
+
agentos agent update NAME_OR_ID [--name NAME] [--prompt[-file] …] [--var …]…
|
|
36
|
+
[--secret …]… [--skill ID]… [--status active|inactive|disabled] [--from-file PATH]
|
|
37
|
+
PATCH /api/v1/agents/custom/{name or id} with only the given fields.
|
|
38
|
+
--var / --secret / --skill each REPLACE that whole list. Your own agents
|
|
39
|
+
only — the backend answers "not found" for anything else, department
|
|
40
|
+
agents included.
|
|
41
|
+
agentos agent delete NAME_OR_ID [--yes]
|
|
42
|
+
Show the agent and, after a y/N confirmation (skipped by --yes), delete it
|
|
43
|
+
on the platform (DELETE /api/v1/agents/custom/{name or id}), then forget its local copy
|
|
44
|
+
and stored keys. Cannot be undone.
|
|
33
45
|
agentos agent list
|
|
34
46
|
Show local (personal) agents (name, engine, trigger type), merged
|
|
35
47
|
with backend status when the backend is reachable, PLUS this user's
|
|
@@ -47,22 +59,25 @@ Command surface:
|
|
|
47
59
|
agentos agent enable <name> / agentos agent disable <name>
|
|
48
60
|
Flip the agent's backend status to "active" / "disabled".
|
|
49
61
|
agentos agent rm <name>
|
|
50
|
-
|
|
62
|
+
Remove the agent from THIS machine (local manifest, stored API keys, last
|
|
63
|
+
inputs) and best-effort de-register it by name on the AI backend. To
|
|
64
|
+
delete the agent itself on the platform, use `agentos agent delete`.
|
|
51
65
|
|
|
52
66
|
agentos ticket create --project KEY --summary TEXT [--type T] [--priority P]
|
|
53
67
|
[--assignee EMAIL] [--description[-file] …] [--instructions[-file] …]
|
|
54
68
|
[--parent ID] [--status S] [--points N]
|
|
55
|
-
File one ticket (POST /tasks
|
|
56
|
-
Task, priority to Medium, assignee to the token
|
|
57
|
-
first; a
|
|
69
|
+
File one ticket (POST /api/v1/tasks on the AI backend) and print its Jira
|
|
70
|
+
key. Type defaults to Task, priority to Medium, assignee to the token
|
|
71
|
+
owner (server-side). Validated locally first; a rejection prints the
|
|
72
|
+
backend's own messages.
|
|
58
73
|
agentos ticket update KEY_OR_ID [--summary …] [--description[-file] …]
|
|
59
74
|
[--instructions[-file] …] [--priority P] [--status S] [--points N]
|
|
60
75
|
[--assignee EMAIL] [--type T]
|
|
61
|
-
Change only the given fields (
|
|
76
|
+
Change only the given fields (PATCH /api/v1/tasks/{id}). Takes a Jira key or
|
|
62
77
|
the platform id. See sdk.tickets — the Tickets page uses the same code.
|
|
63
78
|
agentos ticket delete KEY_OR_ID [--yes]
|
|
64
79
|
Show the ticket and, after a y/N confirmation (skipped by --yes), delete it
|
|
65
|
-
(DELETE /tasks
|
|
80
|
+
(DELETE /api/v1/tasks/{id}). Cannot be undone.
|
|
66
81
|
|
|
67
82
|
agentos integration add <path>
|
|
68
83
|
Register an integration (MCP server, etc.) from a JSON file.
|
|
@@ -226,6 +241,7 @@ def _print_usage() -> None:
|
|
|
226
241
|
print(" agentos configure [--rotate]")
|
|
227
242
|
print(" agentos chat [--product-id ID] [--pv-id ID] [--no-autorun] # requirements → ticket")
|
|
228
243
|
print(" agentos agent <list|run NAME|chat NAME MSG|logs NAME|enable NAME|disable NAME|rm NAME>")
|
|
244
|
+
print(" agentos agent <create [flags]|update NAME_OR_ID [flags]|delete NAME_OR_ID [--yes]|help> # custom-agent CRUD")
|
|
229
245
|
print(" agentos agent <set-key NAME KEY[=VALUE]…|keys NAME|rm-key NAME KEY…> # persistent API keys (custom agents)")
|
|
230
246
|
print(" agentos ticket <create|update KEY_OR_ID|delete KEY_OR_ID|help>")
|
|
231
247
|
print(" agentos integration <add PATH|test NAME|list|rm NAME>")
|
|
@@ -246,13 +262,18 @@ def _agent_command(args: list[str]) -> None:
|
|
|
246
262
|
verb = args[0] if args else None
|
|
247
263
|
rest = args[1:]
|
|
248
264
|
|
|
249
|
-
#
|
|
250
|
-
#
|
|
251
|
-
#
|
|
265
|
+
# Create / update / delete go through the AI backend's /api/v1/agents/custom (the SDK
|
|
266
|
+
# never writes a DB) — see sdk.custom_agents. The old local-manifest wizard
|
|
267
|
+
# (`new` / `add PATH`) stays gone; point at the replacement.
|
|
252
268
|
if verb in ("new", "add"):
|
|
253
|
-
print("`agentos agent
|
|
254
|
-
"
|
|
255
|
-
|
|
269
|
+
print(f"`agentos agent {verb}` has been replaced by `agentos agent create` "
|
|
270
|
+
"(flags or --from-file PATH). See `agentos agent help`.")
|
|
271
|
+
sys.exit(1)
|
|
272
|
+
if verb in ("help", "-h", "--help"):
|
|
273
|
+
_agent_crud_usage()
|
|
274
|
+
sys.exit(0)
|
|
275
|
+
if verb in ("create", "update", "delete"):
|
|
276
|
+
_agent_crud_command(verb, rest)
|
|
256
277
|
return
|
|
257
278
|
if verb == "list":
|
|
258
279
|
_agent_list()
|
|
@@ -288,7 +309,7 @@ def _agent_command(args: list[str]) -> None:
|
|
|
288
309
|
_agent_rm_key(rest[0], rest[1:])
|
|
289
310
|
return
|
|
290
311
|
|
|
291
|
-
print("usage: agentos agent <
|
|
312
|
+
print("usage: agentos agent <create|update NAME_OR_ID|delete NAME_OR_ID|help|list|run NAME|run-ticket NAME [--ticket KEY] "
|
|
292
313
|
"[--var k=v]… [--secret K=V]… [--scope department --department-id UUID]|chat NAME MESSAGE|"
|
|
293
314
|
"template [NAME]|logs NAME|enable NAME|disable NAME|rm NAME|set-key NAME KEY[=VALUE]…|"
|
|
294
315
|
"keys NAME|rm-key NAME KEY…>")
|
|
@@ -506,21 +527,311 @@ def _agent_enable_disable(name: str, enable: bool) -> None:
|
|
|
506
527
|
|
|
507
528
|
|
|
508
529
|
def _agent_rm(name: str) -> None:
|
|
530
|
+
from sdk.client import BackendClient
|
|
531
|
+
|
|
532
|
+
asyncio.run(BackendClient.from_config().delete_custom_agent(name))
|
|
533
|
+
if _agent_forget_local(name):
|
|
534
|
+
print(f"removed '{name}' (and its stored API keys)")
|
|
535
|
+
else:
|
|
536
|
+
print(f"removed '{name}'")
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
def _agent_forget_local(name: str) -> bool:
|
|
540
|
+
"""Drop this machine's copy of an agent: manifest, last-used variables and
|
|
541
|
+
stored API keys. True when stored keys were removed."""
|
|
509
542
|
from sdk.agents import secrets as agent_secrets
|
|
510
543
|
from sdk.agents import varstore as agent_varstore
|
|
511
544
|
from sdk.agents.manifest import AGENTS_DIR
|
|
512
|
-
from sdk.client import BackendClient
|
|
513
545
|
|
|
514
|
-
asyncio.run(BackendClient.from_config().delete_custom_agent(name))
|
|
515
546
|
path = AGENTS_DIR / f"{name}.yaml"
|
|
516
547
|
if path.exists():
|
|
517
548
|
path.unlink()
|
|
518
|
-
# Remove the agent's persisted API keys + last-used variables too.
|
|
519
549
|
agent_varstore.delete_vars(name)
|
|
520
|
-
|
|
521
|
-
|
|
550
|
+
return bool(agent_secrets.delete_all(name))
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
# ── agent create / update / delete (AI backend /api/v1/agents/custom) ────
|
|
554
|
+
|
|
555
|
+
# Flags that take one value. Repeatable list flags are collected separately.
|
|
556
|
+
_AGENT_VALUE_FLAGS = {"--name", "--prompt", "--prompt-file", "--status", "--from-file"}
|
|
557
|
+
_AGENT_LIST_FLAGS = {"--var", "--secret", "--skill"}
|
|
558
|
+
_AGENT_UPDATE_ONLY = {"--status"}
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
def _agent_crud_usage() -> None:
|
|
562
|
+
print("usage: agentos agent <create|update NAME_OR_ID|delete NAME_OR_ID|help>")
|
|
563
|
+
print()
|
|
564
|
+
print(" agentos agent create --name NAME (--prompt TEXT | --prompt-file PATH)")
|
|
565
|
+
print(" [--var NAME[:LABEL[:TYPE[:DESCRIPTION]]]]… [--secret NAME[:DESCRIPTION]]… [--skill ID]…")
|
|
566
|
+
print(" agentos agent create --from-file PATH # one JSON body, or {\"agents\": [...]} (existing names skipped)")
|
|
567
|
+
print(" agentos agent update NAME_OR_ID [--name NAME] [--prompt TEXT | --prompt-file PATH]")
|
|
568
|
+
print(" [--var …]… [--secret …]… [--skill ID]… [--status active|inactive|disabled] [--from-file PATH]")
|
|
569
|
+
print(" agentos agent delete NAME_OR_ID [--yes] # asks to confirm unless --yes")
|
|
570
|
+
print()
|
|
571
|
+
print(" Use {{name}} in the prompt for inputs; without --var they are derived from the prompt.")
|
|
572
|
+
print(" Secrets are NAMES only (e.g. --secret GITHUB_TOKEN:\"repo access\"); values stay on")
|
|
573
|
+
print(" your machine (`agentos agent set-key`). On update, --var/--secret/--skill replace the list.")
|
|
574
|
+
print(" Only your own agents can be changed; department agents are read-only (\"not found\").")
|
|
575
|
+
print(" A create the backend's evaluation rejects prints `rejected: <reasons> (score N)`.")
|
|
576
|
+
print(" `agentos agent rm NAME` only removes this machine's copy — `delete` removes the agent.")
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
def _parse_var_flag(value: str) -> dict:
|
|
580
|
+
parts = value.split(":", 3)
|
|
581
|
+
parts += [""] * (4 - len(parts))
|
|
582
|
+
name, label, vtype, desc = (p.strip() for p in parts)
|
|
583
|
+
out = {"name": name, "label": label or name, "description": desc}
|
|
584
|
+
out["type"] = vtype or "text"
|
|
585
|
+
return out
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
def _parse_secret_flag(value: str) -> dict:
|
|
589
|
+
name, _, desc = value.partition(":")
|
|
590
|
+
return {"name": name.strip(), "description": desc.strip()}
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
def _read_text_file(flag: str, value: str) -> str:
|
|
594
|
+
path = Path(value).expanduser()
|
|
595
|
+
try:
|
|
596
|
+
return path.read_text(encoding="utf-8")
|
|
597
|
+
except OSError as exc:
|
|
598
|
+
print(f"error: {flag}: cannot read {path}: {exc.strerror or exc}")
|
|
599
|
+
sys.exit(1)
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
def _parse_agent_flags(args: list[str], *, creating: bool) -> tuple[dict, str | None]:
|
|
603
|
+
"""Flags → (wire payload, --from-file path). Exits 1 on an unknown flag, a
|
|
604
|
+
missing value, a value flag given twice, or an unreadable file."""
|
|
605
|
+
verb = "create" if creating else "update"
|
|
606
|
+
single: dict[str, str] = {}
|
|
607
|
+
lists: dict[str, list[str]] = {}
|
|
608
|
+
i = 0
|
|
609
|
+
while i < len(args):
|
|
610
|
+
flag = args[i]
|
|
611
|
+
known = flag in _AGENT_VALUE_FLAGS or flag in _AGENT_LIST_FLAGS
|
|
612
|
+
if not known or (creating and flag in _AGENT_UPDATE_ONLY):
|
|
613
|
+
print(f"error: unknown option for `agentos agent {verb}`: {flag}")
|
|
614
|
+
sys.exit(1)
|
|
615
|
+
if i + 1 >= len(args):
|
|
616
|
+
print(f"error: expected a value after {flag}")
|
|
617
|
+
sys.exit(1)
|
|
618
|
+
value = args[i + 1]
|
|
619
|
+
if flag in _AGENT_LIST_FLAGS:
|
|
620
|
+
lists.setdefault(flag, []).append(value)
|
|
621
|
+
else:
|
|
622
|
+
if flag in single:
|
|
623
|
+
print(f"error: pass {flag} once")
|
|
624
|
+
sys.exit(1)
|
|
625
|
+
single[flag] = value
|
|
626
|
+
i += 2
|
|
627
|
+
if "--prompt" in single and "--prompt-file" in single:
|
|
628
|
+
print("error: pass --prompt or --prompt-file, not both")
|
|
629
|
+
sys.exit(1)
|
|
630
|
+
|
|
631
|
+
payload: dict = {}
|
|
632
|
+
if "--name" in single:
|
|
633
|
+
payload["name"] = single["--name"]
|
|
634
|
+
prompt_text = single.get("--prompt")
|
|
635
|
+
if "--prompt-file" in single:
|
|
636
|
+
prompt_text = _read_text_file("--prompt-file", single["--prompt-file"])
|
|
637
|
+
prompt: dict = {}
|
|
638
|
+
if prompt_text is not None:
|
|
639
|
+
prompt["system_prompt"] = prompt_text
|
|
640
|
+
if "--var" in lists:
|
|
641
|
+
prompt["variables"] = [_parse_var_flag(v) for v in lists["--var"]]
|
|
642
|
+
if prompt:
|
|
643
|
+
payload["prompt"] = prompt
|
|
644
|
+
for v in lists.get("--secret", []):
|
|
645
|
+
if "=" in v:
|
|
646
|
+
print(f"error: --secret {v.split('=', 1)[0]}=…: secrets are NAMES only — never "
|
|
647
|
+
"pass a value. Store it on this machine with `agentos agent set-key`.")
|
|
648
|
+
sys.exit(1)
|
|
649
|
+
if "--secret" in lists:
|
|
650
|
+
payload["secrets"] = [_parse_secret_flag(v) for v in lists["--secret"]]
|
|
651
|
+
if "--skill" in lists:
|
|
652
|
+
payload["skills"] = list(lists["--skill"])
|
|
653
|
+
if "--status" in single:
|
|
654
|
+
payload["status"] = single["--status"]
|
|
655
|
+
return payload, single.get("--from-file")
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
def _load_agent_file(path_str: str) -> list[dict] | dict:
|
|
659
|
+
"""--from-file → one body (dict) or many (list, from {"agents": [...]})."""
|
|
660
|
+
import json
|
|
661
|
+
|
|
662
|
+
raw = _read_text_file("--from-file", path_str)
|
|
663
|
+
try:
|
|
664
|
+
data = json.loads(raw)
|
|
665
|
+
except ValueError as exc:
|
|
666
|
+
print(f"error: --from-file: {path_str} is not valid JSON: {exc}")
|
|
667
|
+
sys.exit(1)
|
|
668
|
+
if isinstance(data, dict) and "agents" in data:
|
|
669
|
+
agents = data["agents"]
|
|
670
|
+
if not isinstance(agents, list) or not all(isinstance(a, dict) for a in agents):
|
|
671
|
+
print('error: --from-file: "agents" must be a list of agent objects')
|
|
672
|
+
sys.exit(1)
|
|
673
|
+
return agents
|
|
674
|
+
if isinstance(data, list):
|
|
675
|
+
if not all(isinstance(a, dict) for a in data):
|
|
676
|
+
print("error: --from-file: every entry must be an agent object")
|
|
677
|
+
sys.exit(1)
|
|
678
|
+
return data
|
|
679
|
+
if not isinstance(data, dict):
|
|
680
|
+
print("error: --from-file: expected a JSON object")
|
|
681
|
+
sys.exit(1)
|
|
682
|
+
return data
|
|
683
|
+
|
|
684
|
+
|
|
685
|
+
def _merge_payload(base: dict, over: dict) -> dict:
|
|
686
|
+
"""Flags win over the file; a partial flag prompt merges into the file's prompt."""
|
|
687
|
+
out = {**base, **{k: v for k, v in over.items() if k != "prompt"}}
|
|
688
|
+
if "prompt" in over:
|
|
689
|
+
file_prompt = base.get("prompt") if isinstance(base.get("prompt"), dict) else {}
|
|
690
|
+
if isinstance(base.get("prompt"), str):
|
|
691
|
+
file_prompt = {"system_prompt": base["prompt"]}
|
|
692
|
+
out["prompt"] = {**file_prompt, **over["prompt"]}
|
|
693
|
+
return out
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
def _print_warnings(res: dict) -> None:
|
|
697
|
+
for w in res.get("warnings") or []:
|
|
698
|
+
print(f"warning: {w}")
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
def _agent_crud_command(verb: str, args: list[str]) -> None:
|
|
702
|
+
"""`agentos agent create|update|delete` — see sdk.custom_agents for the rules."""
|
|
703
|
+
if verb in {"update", "delete"} and (not args or args[0].startswith("--")):
|
|
704
|
+
_agent_crud_usage()
|
|
705
|
+
sys.exit(1)
|
|
706
|
+
if verb == "delete":
|
|
707
|
+
_agent_crud_delete(args[0], args[1:])
|
|
708
|
+
return
|
|
709
|
+
|
|
710
|
+
from sdk import custom_agents
|
|
711
|
+
from sdk.client import BackendClient
|
|
712
|
+
|
|
713
|
+
creating = verb == "create"
|
|
714
|
+
flag_args = args if creating else args[1:]
|
|
715
|
+
payload, from_file = _parse_agent_flags(flag_args, creating=creating)
|
|
716
|
+
many: list[dict] | None = None
|
|
717
|
+
if from_file:
|
|
718
|
+
loaded = _load_agent_file(from_file)
|
|
719
|
+
if isinstance(loaded, list):
|
|
720
|
+
if not creating:
|
|
721
|
+
print("error: --from-file with several agents is for `create` only")
|
|
722
|
+
sys.exit(1)
|
|
723
|
+
if payload:
|
|
724
|
+
print("error: a bulk --from-file cannot be combined with other flags")
|
|
725
|
+
sys.exit(1)
|
|
726
|
+
many = loaded
|
|
727
|
+
else:
|
|
728
|
+
loaded.pop("id", None)
|
|
729
|
+
payload = _merge_payload(loaded, payload)
|
|
730
|
+
|
|
731
|
+
if many is not None:
|
|
732
|
+
# Validate every entry before building a client, so a bad file never needs a token.
|
|
733
|
+
for n, item in enumerate(many, 1):
|
|
734
|
+
_, err, _ = custom_agents.build_body(item, creating=True)
|
|
735
|
+
if err:
|
|
736
|
+
print(f"error: agent #{n} ({item.get('name') or 'unnamed'}): {err}")
|
|
737
|
+
sys.exit(1)
|
|
738
|
+
client = BackendClient.from_config()
|
|
739
|
+
results = asyncio.run(custom_agents.create_many(client, many))
|
|
740
|
+
created = skipped = failed = 0
|
|
741
|
+
for res in results:
|
|
742
|
+
if res.get("skipped"):
|
|
743
|
+
skipped += 1
|
|
744
|
+
print(f"skipped {res['name']} (already exists)")
|
|
745
|
+
elif res["ok"]:
|
|
746
|
+
created += 1
|
|
747
|
+
print(f"created {res['name']} (id {res['id']})")
|
|
748
|
+
_print_warnings(res)
|
|
749
|
+
else:
|
|
750
|
+
failed += 1
|
|
751
|
+
print(f"error: {res.get('name') or ''}: {res['error']}".replace("error: : ", "error: "))
|
|
752
|
+
print(f"{created} created, {skipped} skipped, {failed} failed")
|
|
753
|
+
sys.exit(1 if failed else 0)
|
|
754
|
+
|
|
755
|
+
if creating:
|
|
756
|
+
if not payload.get("name") or not (
|
|
757
|
+
isinstance(payload.get("prompt"), (dict, str)) and payload.get("prompt")):
|
|
758
|
+
print("error: --name and --prompt (or --prompt-file / --from-file) are required")
|
|
759
|
+
sys.exit(1)
|
|
760
|
+
elif not payload:
|
|
761
|
+
print("error: nothing to update: pass at least one field")
|
|
762
|
+
_agent_crud_usage()
|
|
763
|
+
sys.exit(1)
|
|
764
|
+
# Validate before building a client, so a bad flag never needs a token.
|
|
765
|
+
if creating:
|
|
766
|
+
_, err, _ = custom_agents.build_body(payload, creating=True)
|
|
522
767
|
else:
|
|
523
|
-
|
|
768
|
+
err = custom_agents.precheck_update(payload)
|
|
769
|
+
if err:
|
|
770
|
+
print(f"error: {err}")
|
|
771
|
+
sys.exit(1)
|
|
772
|
+
|
|
773
|
+
client = BackendClient.from_config()
|
|
774
|
+
if creating:
|
|
775
|
+
res = asyncio.run(custom_agents.create_agent(client, payload))
|
|
776
|
+
else:
|
|
777
|
+
res = asyncio.run(custom_agents.update_agent(client, args[0], payload))
|
|
778
|
+
_print_warnings(res)
|
|
779
|
+
if not res["ok"]:
|
|
780
|
+
print(f"error: {res['error']}")
|
|
781
|
+
sys.exit(1)
|
|
782
|
+
if creating:
|
|
783
|
+
print(f"created {res['name']} (id {res['id'] or 'unknown'})")
|
|
784
|
+
ev = res.get("evaluation") or {}
|
|
785
|
+
if isinstance(ev, dict) and ev.get("score") is not None:
|
|
786
|
+
print(f"evaluation: accepted, score {ev['score']}")
|
|
787
|
+
else:
|
|
788
|
+
print(f"updated {res['name']}: {', '.join(res.get('fields') or sorted(payload))}")
|
|
789
|
+
sys.exit(0)
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
def _agent_crud_delete(target: str, flags: list[str]) -> None:
|
|
793
|
+
"""`agentos agent delete NAME_OR_ID [--yes]` — shows the agent, then asks."""
|
|
794
|
+
from sdk import custom_agents
|
|
795
|
+
from sdk.client import BackendClient
|
|
796
|
+
|
|
797
|
+
unknown = [f for f in flags if f not in {"--yes", "-y"}]
|
|
798
|
+
if unknown:
|
|
799
|
+
print(f"error: unknown option for `agentos agent delete`: {unknown[0]}")
|
|
800
|
+
sys.exit(1)
|
|
801
|
+
client = BackendClient.from_config()
|
|
802
|
+
rec: dict | None = None
|
|
803
|
+
name = target
|
|
804
|
+
if not flags:
|
|
805
|
+
# Show what is about to go. The server is the authority on "is it yours",
|
|
806
|
+
# so only a definite "not found" stops here.
|
|
807
|
+
rec, err = asyncio.run(custom_agents.get_agent(client, target))
|
|
808
|
+
if rec is None and err.startswith("agent not found"):
|
|
809
|
+
print(f"error: {err}")
|
|
810
|
+
sys.exit(1)
|
|
811
|
+
if rec is not None:
|
|
812
|
+
name = rec["name"] or rec["id"]
|
|
813
|
+
first = (rec["prompt"]["system_prompt"].strip().splitlines() or [""])[0][:100]
|
|
814
|
+
print(f"{name} (id {rec['id']}) [{rec.get('status') or '?'}] {first}")
|
|
815
|
+
try:
|
|
816
|
+
answer = input(f"Delete agent {name}? This cannot be undone. [y/N] ")
|
|
817
|
+
except EOFError:
|
|
818
|
+
answer = ""
|
|
819
|
+
if answer.strip().lower() not in {"y", "yes"}:
|
|
820
|
+
print("not deleted")
|
|
821
|
+
sys.exit(1)
|
|
822
|
+
res = asyncio.run(custom_agents.delete_agent(client, rec["id"] if rec else target))
|
|
823
|
+
if not res["ok"]:
|
|
824
|
+
print(f"error: {res['error']}")
|
|
825
|
+
sys.exit(1)
|
|
826
|
+
local_name = (rec or {}).get("name") or target
|
|
827
|
+
if local_name:
|
|
828
|
+
try:
|
|
829
|
+
_agent_forget_local(local_name)
|
|
830
|
+
except Exception as exc: # noqa: BLE001 — the platform delete already happened
|
|
831
|
+
print(f"warning: deleted on the platform, but this machine's copy was not "
|
|
832
|
+
f"cleaned up ({exc}); run `agentos agent rm {local_name}`")
|
|
833
|
+
print(f"deleted {name}")
|
|
834
|
+
sys.exit(0)
|
|
524
835
|
|
|
525
836
|
|
|
526
837
|
def _agent_exists(name: str) -> bool:
|
|
@@ -542,7 +853,7 @@ def _agent_set_key(name: str, pairs: list[str]) -> None:
|
|
|
542
853
|
|
|
543
854
|
if not _agent_exists(name):
|
|
544
855
|
print(f"error: no local agent named '{name}'. Install it first "
|
|
545
|
-
f"(agentos agent
|
|
856
|
+
f"(`agentos agent list` shows what this machine has; create one with `agentos agent create`).")
|
|
546
857
|
sys.exit(1)
|
|
547
858
|
|
|
548
859
|
updates: dict[str, str] = {}
|
|
@@ -645,7 +956,7 @@ def _pop_department_id(args: list[str]) -> tuple[str | None, list[str]]:
|
|
|
645
956
|
return dept_id, out
|
|
646
957
|
|
|
647
958
|
|
|
648
|
-
# `agentos ticket` flag → POST/
|
|
959
|
+
# `agentos ticket` flag → POST/PATCH /api/v1/tasks wire name. Text flags have a
|
|
649
960
|
# `-file` twin that reads the value from a file instead.
|
|
650
961
|
_TICKET_FLAGS = {
|
|
651
962
|
"--project": "projectKey", "--type": "type", "--summary": "summary",
|
|
@@ -655,7 +966,7 @@ _TICKET_FLAGS = {
|
|
|
655
966
|
}
|
|
656
967
|
_TICKET_FILE_FLAGS = {"--description-file": "--description",
|
|
657
968
|
"--instructions-file": "--instructions"}
|
|
658
|
-
# Create-only: neither is editable through
|
|
969
|
+
# Create-only: neither is editable through PATCH /api/v1/tasks/{id}.
|
|
659
970
|
_TICKET_CREATE_ONLY = {"--project", "--parent"}
|
|
660
971
|
|
|
661
972
|
|
|
@@ -830,7 +1141,7 @@ def _require_department_manager(verb: str) -> None:
|
|
|
830
1141
|
f"activate department agents, but only department managers (team_lead+) "
|
|
831
1142
|
f"can '{verb}' them.")
|
|
832
1143
|
print("note: your own custom agents are unrestricted — use `agentos agent "
|
|
833
|
-
"<
|
|
1144
|
+
"<create|update|delete|enable|disable|rm> …`.")
|
|
834
1145
|
sys.exit(1)
|
|
835
1146
|
|
|
836
1147
|
|