holmesgpt 0.13.0__tar.gz → 0.13.1__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.
Potentially problematic release.
This version of holmesgpt might be problematic. Click here for more details.
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/PKG-INFO +1 -1
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/__init__.py +1 -1
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/common/env_vars.py +4 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/core/llm.py +3 -1
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/core/tool_calling_llm.py +112 -11
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/core/toolset_manager.py +1 -5
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/core/tracing.py +1 -1
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/main.py +7 -1
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/prompts/_fetch_logs.jinja2 +4 -0
- holmesgpt-0.13.1/holmes/plugins/runbooks/CLAUDE.md +85 -0
- holmesgpt-0.13.1/holmes/plugins/runbooks/README.md +46 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/argocd/__init__.py +65 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/argocd/constants.py +120 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/aws/__init__.py +66 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/aws/constants.py +529 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/azure/__init__.py +56 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/azure/constants.py +339 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/bash_instructions.jinja2 +13 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/bash/bash_toolset.py +47 -13
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/common/bash_command.py +131 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/bash/common/stringify.py +14 -1
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/common/validators.py +115 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/docker/__init__.py +59 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/docker/constants.py +255 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/helm/__init__.py +61 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/helm/constants.py +92 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/kubectl/__init__.py +101 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/bash/kubectl/constants.py +0 -14
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/kubectl/kubectl_describe.py +48 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/kubectl/kubectl_events.py +40 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/kubectl/kubectl_get.py +48 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/kubectl/kubectl_logs.py +39 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/bash/kubectl/kubectl_run.py +1 -1
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/kubectl/kubectl_top.py +42 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/parse_command.py +177 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/utilities/base64_util.py +12 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/utilities/cut.py +12 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/utilities/grep/__init__.py +10 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/utilities/head.py +12 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/utilities/jq.py +79 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/utilities/sed.py +164 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/utilities/sort.py +15 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/utilities/tail.py +12 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/utilities/tr.py +57 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/utilities/uniq.py +12 -0
- holmesgpt-0.13.1/holmes/plugins/toolsets/bash/utilities/wc.py +12 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/prometheus/prometheus.py +42 -12
- holmesgpt-0.13.1/holmes/utils/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/utils/console/logging.py +6 -1
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/pyproject.toml +3 -2
- holmesgpt-0.13.0/holmes/plugins/runbooks/README.md +0 -22
- holmesgpt-0.13.0/holmes/plugins/toolsets/bash/bash_instructions.jinja2 +0 -14
- holmesgpt-0.13.0/holmes/plugins/toolsets/bash/common/validators.py +0 -24
- holmesgpt-0.13.0/holmes/plugins/toolsets/bash/grep/__init__.py +0 -52
- holmesgpt-0.13.0/holmes/plugins/toolsets/bash/kubectl/__init__.py +0 -100
- holmesgpt-0.13.0/holmes/plugins/toolsets/bash/kubectl/kubectl_describe.py +0 -66
- holmesgpt-0.13.0/holmes/plugins/toolsets/bash/kubectl/kubectl_events.py +0 -88
- holmesgpt-0.13.0/holmes/plugins/toolsets/bash/kubectl/kubectl_get.py +0 -108
- holmesgpt-0.13.0/holmes/plugins/toolsets/bash/kubectl/kubectl_logs.py +0 -20
- holmesgpt-0.13.0/holmes/plugins/toolsets/bash/kubectl/kubectl_top.py +0 -81
- holmesgpt-0.13.0/holmes/plugins/toolsets/bash/parse_command.py +0 -103
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/LICENSE.txt +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/README.md +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/.git_archival.json +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/clients/robusta_client.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/common/openshift.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/config.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/core/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/core/config.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/core/conversations.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/core/investigation.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/core/investigation_structured_output.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/core/issue.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/core/models.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/core/openai_formatting.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/core/performance_timing.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/core/prompt.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/core/resource_instruction.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/core/runbooks.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/core/safeguards.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/core/supabase_dal.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/core/todo_manager.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/core/tools.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/core/tools_utils/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/core/tools_utils/tool_executor.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/core/tools_utils/toolset_utils.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/interactive.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/destinations/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/destinations/slack/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/destinations/slack/plugin.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/interfaces.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/prompts/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/prompts/_ai_safety.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/prompts/_current_date_time.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/prompts/_default_log_prompt.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/prompts/_general_instructions.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/prompts/_global_instructions.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/prompts/_permission_errors.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/prompts/_runbook_instructions.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/prompts/_toolsets_instructions.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/prompts/generic_ask.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/prompts/generic_ask_conversation.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/prompts/generic_ask_for_issue_conversation.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/prompts/generic_investigation.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/prompts/generic_post_processing.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/prompts/generic_ticket.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/prompts/investigation_output_format.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/prompts/investigation_procedure.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/prompts/kubernetes_workload_ask.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/prompts/kubernetes_workload_chat.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/runbooks/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/runbooks/catalog.json +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/runbooks/jira.yaml +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/runbooks/kube-prometheus-stack.yaml +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/runbooks/networking/dns_troubleshooting_instructions.md +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/runbooks/upgrade/upgrade_troubleshooting_instructions.md +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/sources/github/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/sources/jira/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/sources/opsgenie/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/sources/pagerduty/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/sources/prometheus/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/sources/prometheus/models.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/sources/prometheus/plugin.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/aks-node-health.yaml +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/aks.yaml +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/argocd.yaml +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/atlas_mongodb/instructions.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/atlas_mongodb/mongodb_atlas.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/aws.yaml +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/azure_sql/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/azure_sql/apis/alert_monitoring_api.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/azure_sql/apis/azure_sql_api.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/azure_sql/apis/connection_failure_api.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/azure_sql/apis/connection_monitoring_api.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/azure_sql/apis/storage_analysis_api.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/azure_sql/azure_base_toolset.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/azure_sql/azure_sql_instructions.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/azure_sql/azure_sql_toolset.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/azure_sql/install.md +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/azure_sql/tools/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/azure_sql/tools/analyze_connection_failures.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/azure_sql/tools/analyze_database_connections.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/azure_sql/tools/analyze_database_health_status.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/azure_sql/tools/analyze_database_performance.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/azure_sql/tools/analyze_database_storage.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/azure_sql/tools/get_active_alerts.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/azure_sql/tools/get_slow_queries.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/azure_sql/tools/get_top_cpu_queries.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/azure_sql/tools/get_top_data_io_queries.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/azure_sql/tools/get_top_log_io_queries.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/azure_sql/utils.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/bash/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/bash/common/bash.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/bash/common/config.py +0 -0
- {holmesgpt-0.13.0/holmes/plugins/toolsets/grafana → holmesgpt-0.13.1/holmes/plugins/toolsets/bash/utilities}/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/confluence.yaml +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/consts.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/coralogix/api.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/coralogix/toolset_coralogix_logs.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/coralogix/utils.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/datadog/datadog_api.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/datadog/datadog_metrics_instructions.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/datadog/datadog_rds_instructions.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/datadog/datadog_traces_formatter.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/datadog/instructions_datadog_traces.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/datadog/toolset_datadog_logs.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/datadog/toolset_datadog_metrics.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/datadog/toolset_datadog_rds.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/datadog/toolset_datadog_traces.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/docker.yaml +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/git.py +0 -0
- {holmesgpt-0.13.0/holmes/plugins/toolsets/investigator → holmesgpt-0.13.1/holmes/plugins/toolsets/grafana}/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/grafana/base_grafana_toolset.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/grafana/common.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/grafana/grafana_api.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/grafana/loki_api.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/grafana/tempo_api.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/grafana/toolset_grafana.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/grafana/toolset_grafana_loki.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/grafana/toolset_grafana_tempo.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/grafana/toolset_grafana_tempo.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/grafana/trace_parser.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/helm.yaml +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/internet/internet.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/internet/notion.py +0 -0
- {holmesgpt-0.13.0/holmes/plugins/toolsets/logging_utils → holmesgpt-0.13.1/holmes/plugins/toolsets/investigator}/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/investigator/core_investigation.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/investigator/investigator_instructions.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/investigator/model.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/kafka.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/kubernetes.yaml +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/kubernetes_logs.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/kubernetes_logs.yaml +0 -0
- {holmesgpt-0.13.0/holmes/plugins/toolsets/opensearch → holmesgpt-0.13.1/holmes/plugins/toolsets/logging_utils}/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/logging_utils/logging_api.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/logging_utils/types.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/mcp/toolset_mcp.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/newrelic.py +0 -0
- {holmesgpt-0.13.0/holmes/plugins/toolsets/robusta → holmesgpt-0.13.1/holmes/plugins/toolsets/opensearch}/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/opensearch/opensearch.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/opensearch/opensearch_logs.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/opensearch/opensearch_traces.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/opensearch/opensearch_traces_instructions.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/opensearch/opensearch_utils.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/prometheus/prometheus_instructions.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/rabbitmq/api.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/rabbitmq/rabbitmq_instructions.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/rabbitmq/toolset_rabbitmq.py +0 -0
- {holmesgpt-0.13.0/holmes/plugins/toolsets/runbook → holmesgpt-0.13.1/holmes/plugins/toolsets/robusta}/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/robusta/robusta.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/robusta/robusta_instructions.jinja2 +0 -0
- {holmesgpt-0.13.0/holmes/utils → holmesgpt-0.13.1/holmes/plugins/toolsets/runbook}/__init__.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/runbook/runbook_fetcher.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/service_discovery.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/servicenow/install.md +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/servicenow/instructions.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/servicenow/servicenow.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/slab.yaml +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/toolsets/utils.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/plugins/utils.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/utils/cache.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/utils/cert_utils.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/utils/colors.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/utils/console/consts.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/utils/console/result.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/utils/default_toolset_installation_guide.jinja2 +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/utils/definitions.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/utils/env.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/utils/file_utils.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/utils/global_instructions.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/utils/holmes_status.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/utils/holmes_sync_toolsets.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/utils/keygen_utils.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/utils/llms.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/utils/markdown_utils.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/utils/pydantic_utils.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/utils/stream.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/utils/tags.py +0 -0
- {holmesgpt-0.13.0 → holmesgpt-0.13.1}/holmes/version.py +0 -0
|
@@ -34,6 +34,7 @@ LOG_PERFORMANCE = os.environ.get("LOG_PERFORMANCE", None)
|
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
ENABLE_TELEMETRY = load_bool("ENABLE_TELEMETRY", False)
|
|
37
|
+
DEVELOPMENT_MODE = load_bool("DEVELOPMENT_MODE", False)
|
|
37
38
|
SENTRY_DSN = os.environ.get("SENTRY_DSN", "")
|
|
38
39
|
SENTRY_TRACES_SAMPLE_RATE = float(os.environ.get("SENTRY_TRACES_SAMPLE_RATE", "0.0"))
|
|
39
40
|
|
|
@@ -63,3 +64,6 @@ TOOL_SCHEMA_NO_PARAM_OBJECT_IF_NO_PARAMS = load_bool(
|
|
|
63
64
|
MAX_OUTPUT_TOKEN_RESERVATION = int(
|
|
64
65
|
os.environ.get("MAX_OUTPUT_TOKEN_RESERVATION", 16384)
|
|
65
66
|
) ## 16k
|
|
67
|
+
|
|
68
|
+
# When using the bash tool, setting BASH_TOOL_UNSAFE_ALLOW_ALL will skip any command validation and run any command requested by the LLM
|
|
69
|
+
BASH_TOOL_UNSAFE_ALLOW_ALL = load_bool("BASH_TOOL_UNSAFE_ALLOW_ALL", False)
|
|
@@ -119,7 +119,9 @@ class DefaultLLM(LLM):
|
|
|
119
119
|
"environment variable for proper functionality. For more information, refer to the documentation: "
|
|
120
120
|
"https://docs.litellm.ai/docs/providers/watsonx#usage---models-in-deployment-spaces"
|
|
121
121
|
)
|
|
122
|
-
elif provider == "bedrock" and
|
|
122
|
+
elif provider == "bedrock" and (
|
|
123
|
+
os.environ.get("AWS_PROFILE") or os.environ.get("AWS_BEARER_TOKEN_BEDROCK")
|
|
124
|
+
):
|
|
123
125
|
model_requirements = {"keys_in_environment": True, "missing_keys": []}
|
|
124
126
|
else:
|
|
125
127
|
#
|
|
@@ -10,7 +10,7 @@ from openai import BadRequestError
|
|
|
10
10
|
from openai.types.chat.chat_completion_message_tool_call import (
|
|
11
11
|
ChatCompletionMessageToolCall,
|
|
12
12
|
)
|
|
13
|
-
from pydantic import BaseModel
|
|
13
|
+
from pydantic import BaseModel, Field
|
|
14
14
|
from rich.console import Console
|
|
15
15
|
|
|
16
16
|
from holmes.common.env_vars import TEMPERATURE, MAX_OUTPUT_TOKEN_RESERVATION
|
|
@@ -43,6 +43,78 @@ from holmes.core.todo_manager import (
|
|
|
43
43
|
get_todo_manager,
|
|
44
44
|
)
|
|
45
45
|
|
|
46
|
+
# Create a named logger for cost tracking
|
|
47
|
+
cost_logger = logging.getLogger("holmes.costs")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class LLMCosts(BaseModel):
|
|
51
|
+
"""Tracks cost and token usage for LLM calls."""
|
|
52
|
+
|
|
53
|
+
total_cost: float = 0.0
|
|
54
|
+
total_tokens: int = 0
|
|
55
|
+
prompt_tokens: int = 0
|
|
56
|
+
completion_tokens: int = 0
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _extract_cost_from_response(full_response) -> float:
|
|
60
|
+
"""Extract cost value from LLM response.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
full_response: The raw LLM response object
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
The cost as a float, or 0.0 if not available
|
|
67
|
+
"""
|
|
68
|
+
try:
|
|
69
|
+
cost_value = (
|
|
70
|
+
full_response._hidden_params.get("response_cost", 0)
|
|
71
|
+
if hasattr(full_response, "_hidden_params")
|
|
72
|
+
else 0
|
|
73
|
+
)
|
|
74
|
+
# Ensure cost is a float
|
|
75
|
+
return float(cost_value) if cost_value is not None else 0.0
|
|
76
|
+
except Exception:
|
|
77
|
+
return 0.0
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _process_cost_info(
|
|
81
|
+
full_response, costs: Optional[LLMCosts] = None, log_prefix: str = "LLM call"
|
|
82
|
+
) -> None:
|
|
83
|
+
"""Process cost and token information from LLM response.
|
|
84
|
+
|
|
85
|
+
Logs the cost information and optionally accumulates it into a costs object.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
full_response: The raw LLM response object
|
|
89
|
+
costs: Optional LLMCosts object to accumulate costs into
|
|
90
|
+
log_prefix: Prefix for logging messages (e.g., "LLM call", "Post-processing")
|
|
91
|
+
"""
|
|
92
|
+
try:
|
|
93
|
+
cost = _extract_cost_from_response(full_response)
|
|
94
|
+
usage = getattr(full_response, "usage", {})
|
|
95
|
+
|
|
96
|
+
if usage:
|
|
97
|
+
prompt_toks = usage.get("prompt_tokens", 0)
|
|
98
|
+
completion_toks = usage.get("completion_tokens", 0)
|
|
99
|
+
total_toks = usage.get("total_tokens", 0)
|
|
100
|
+
cost_logger.debug(
|
|
101
|
+
f"{log_prefix} cost: ${cost:.6f} | Tokens: {prompt_toks} prompt + {completion_toks} completion = {total_toks} total"
|
|
102
|
+
)
|
|
103
|
+
# Accumulate costs and tokens if costs object provided
|
|
104
|
+
if costs:
|
|
105
|
+
costs.total_cost += cost
|
|
106
|
+
costs.prompt_tokens += prompt_toks
|
|
107
|
+
costs.completion_tokens += completion_toks
|
|
108
|
+
costs.total_tokens += total_toks
|
|
109
|
+
elif cost > 0:
|
|
110
|
+
cost_logger.debug(
|
|
111
|
+
f"{log_prefix} cost: ${cost:.6f} | Token usage not available"
|
|
112
|
+
)
|
|
113
|
+
if costs:
|
|
114
|
+
costs.total_cost += cost
|
|
115
|
+
except Exception as e:
|
|
116
|
+
logging.debug(f"Could not extract cost information: {e}")
|
|
117
|
+
|
|
46
118
|
|
|
47
119
|
def format_tool_result_data(tool_result: StructuredToolResult) -> str:
|
|
48
120
|
tool_response = tool_result.data
|
|
@@ -186,11 +258,11 @@ class ToolCallResult(BaseModel):
|
|
|
186
258
|
}
|
|
187
259
|
|
|
188
260
|
|
|
189
|
-
class LLMResult(
|
|
261
|
+
class LLMResult(LLMCosts):
|
|
190
262
|
tool_calls: Optional[List[ToolCallResult]] = None
|
|
191
263
|
result: Optional[str] = None
|
|
192
264
|
unprocessed_result: Optional[str] = None
|
|
193
|
-
instructions: List[str] =
|
|
265
|
+
instructions: List[str] = Field(default_factory=list)
|
|
194
266
|
# TODO: clean up these two
|
|
195
267
|
prompt: Optional[str] = None
|
|
196
268
|
messages: Optional[List[dict]] = None
|
|
@@ -259,6 +331,8 @@ class ToolCallingLLM:
|
|
|
259
331
|
) -> LLMResult:
|
|
260
332
|
perf_timing = PerformanceTiming("tool_calling_llm.call")
|
|
261
333
|
tool_calls = [] # type: ignore
|
|
334
|
+
costs = LLMCosts()
|
|
335
|
+
|
|
262
336
|
tools = self.tool_executor.get_all_tools_openai_format(
|
|
263
337
|
target_model=self.llm.model
|
|
264
338
|
)
|
|
@@ -299,6 +373,9 @@ class ToolCallingLLM:
|
|
|
299
373
|
)
|
|
300
374
|
logging.debug(f"got response {full_response.to_json()}") # type: ignore
|
|
301
375
|
|
|
376
|
+
# Extract and accumulate cost information
|
|
377
|
+
_process_cost_info(full_response, costs, "LLM call")
|
|
378
|
+
|
|
302
379
|
perf_timing.measure("llm.completion")
|
|
303
380
|
# catch a known error that occurs with Azure and replace the error message with something more obvious to the user
|
|
304
381
|
except BadRequestError as e:
|
|
@@ -352,11 +429,14 @@ class ToolCallingLLM:
|
|
|
352
429
|
if post_process_prompt and user_prompt:
|
|
353
430
|
logging.info("Running post processing on investigation.")
|
|
354
431
|
raw_response = text_response
|
|
355
|
-
post_processed_response =
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
432
|
+
post_processed_response, post_processing_cost = (
|
|
433
|
+
self._post_processing_call(
|
|
434
|
+
prompt=user_prompt,
|
|
435
|
+
investigation=raw_response,
|
|
436
|
+
user_prompt=post_process_prompt,
|
|
437
|
+
)
|
|
359
438
|
)
|
|
439
|
+
costs.total_cost += post_processing_cost
|
|
360
440
|
|
|
361
441
|
perf_timing.end(f"- completed in {i} iterations -")
|
|
362
442
|
return LLMResult(
|
|
@@ -365,6 +445,7 @@ class ToolCallingLLM:
|
|
|
365
445
|
tool_calls=tool_calls,
|
|
366
446
|
prompt=json.dumps(messages, indent=2),
|
|
367
447
|
messages=messages,
|
|
448
|
+
**costs.model_dump(), # Include all cost fields
|
|
368
449
|
)
|
|
369
450
|
|
|
370
451
|
perf_timing.end(f"- completed in {i} iterations -")
|
|
@@ -373,6 +454,7 @@ class ToolCallingLLM:
|
|
|
373
454
|
tool_calls=tool_calls,
|
|
374
455
|
prompt=json.dumps(messages, indent=2),
|
|
375
456
|
messages=messages,
|
|
457
|
+
**costs.model_dump(), # Include all cost fields
|
|
376
458
|
)
|
|
377
459
|
|
|
378
460
|
if text_response and text_response.strip():
|
|
@@ -403,6 +485,9 @@ class ToolCallingLLM:
|
|
|
403
485
|
|
|
404
486
|
perf_timing.measure(f"tool completed {tool_call_result.tool_name}")
|
|
405
487
|
|
|
488
|
+
# Update the tool number offset for the next iteration
|
|
489
|
+
tool_number_offset += len(tools_to_call)
|
|
490
|
+
|
|
406
491
|
# Add a blank line after all tools in this batch complete
|
|
407
492
|
if tools_to_call:
|
|
408
493
|
logging.info("")
|
|
@@ -540,7 +625,7 @@ class ToolCallingLLM:
|
|
|
540
625
|
investigation,
|
|
541
626
|
user_prompt: Optional[str] = None,
|
|
542
627
|
system_prompt: str = "You are an AI assistant summarizing Kubernetes issues.",
|
|
543
|
-
) -> Optional[str]:
|
|
628
|
+
) -> tuple[Optional[str], float]:
|
|
544
629
|
try:
|
|
545
630
|
user_prompt = ToolCallingLLM.__load_post_processing_user_prompt(
|
|
546
631
|
prompt, investigation, user_prompt
|
|
@@ -559,10 +644,18 @@ class ToolCallingLLM:
|
|
|
559
644
|
]
|
|
560
645
|
full_response = self.llm.completion(messages=messages, temperature=0)
|
|
561
646
|
logging.debug(f"Post processing response {full_response}")
|
|
562
|
-
|
|
647
|
+
|
|
648
|
+
# Extract and log cost information for post-processing
|
|
649
|
+
post_processing_cost = _extract_cost_from_response(full_response)
|
|
650
|
+
if post_processing_cost > 0:
|
|
651
|
+
cost_logger.debug(
|
|
652
|
+
f"Post-processing LLM cost: ${post_processing_cost:.6f}"
|
|
653
|
+
)
|
|
654
|
+
|
|
655
|
+
return full_response.choices[0].message.content, post_processing_cost # type: ignore
|
|
563
656
|
except Exception:
|
|
564
657
|
logging.exception("Failed to run post processing", exc_info=True)
|
|
565
|
-
return investigation
|
|
658
|
+
return investigation, 0.0
|
|
566
659
|
|
|
567
660
|
@sentry_sdk.trace
|
|
568
661
|
def truncate_messages_to_fit_context(
|
|
@@ -602,6 +695,7 @@ class ToolCallingLLM:
|
|
|
602
695
|
perf_timing.measure("get_all_tools_openai_format")
|
|
603
696
|
max_steps = self.max_steps
|
|
604
697
|
i = 0
|
|
698
|
+
tool_number_offset = 0
|
|
605
699
|
|
|
606
700
|
while i < max_steps:
|
|
607
701
|
i += 1
|
|
@@ -634,6 +728,10 @@ class ToolCallingLLM:
|
|
|
634
728
|
stream=False,
|
|
635
729
|
drop_params=True,
|
|
636
730
|
)
|
|
731
|
+
|
|
732
|
+
# Log cost information for this iteration (no accumulation in streaming)
|
|
733
|
+
_process_cost_info(full_response, log_prefix="LLM iteration")
|
|
734
|
+
|
|
637
735
|
perf_timing.measure("llm.completion")
|
|
638
736
|
# catch a known error that occurs with Azure and replace the error message with something more obvious to the user
|
|
639
737
|
except BadRequestError as e:
|
|
@@ -695,7 +793,7 @@ class ToolCallingLLM:
|
|
|
695
793
|
tool_to_call=t, # type: ignore
|
|
696
794
|
previous_tool_calls=tool_calls,
|
|
697
795
|
trace_span=DummySpan(), # Streaming mode doesn't support tracing yet
|
|
698
|
-
tool_number=tool_index,
|
|
796
|
+
tool_number=tool_number_offset + tool_index,
|
|
699
797
|
)
|
|
700
798
|
)
|
|
701
799
|
yield StreamMessage(
|
|
@@ -716,6 +814,9 @@ class ToolCallingLLM:
|
|
|
716
814
|
data=tool_call_result.as_streaming_tool_result_response(),
|
|
717
815
|
)
|
|
718
816
|
|
|
817
|
+
# Update the tool number offset for the next iteration
|
|
818
|
+
tool_number_offset += len(tools_to_call)
|
|
819
|
+
|
|
719
820
|
raise Exception(
|
|
720
821
|
f"Too many LLM calls - exceeded max_steps: {i}/{self.max_steps}"
|
|
721
822
|
)
|
|
@@ -266,11 +266,7 @@ class ToolsetManager:
|
|
|
266
266
|
toolset.path = cached_status.get("path", None)
|
|
267
267
|
# check prerequisites for only enabled toolset when the toolset is loaded from cache. When the toolset is
|
|
268
268
|
# not loaded from cache, the prerequisites are checked in the refresh_toolset_status method.
|
|
269
|
-
if
|
|
270
|
-
toolset.enabled
|
|
271
|
-
and toolset.status == ToolsetStatusEnum.ENABLED
|
|
272
|
-
and using_cached
|
|
273
|
-
):
|
|
269
|
+
if toolset.enabled and toolset.status == ToolsetStatusEnum.ENABLED:
|
|
274
270
|
enabled_toolsets_from_cache.append(toolset)
|
|
275
271
|
self.check_toolset_prerequisites(enabled_toolsets_from_cache)
|
|
276
272
|
|
|
@@ -120,7 +120,7 @@ class DummySpan:
|
|
|
120
120
|
class DummyTracer:
|
|
121
121
|
"""A no-op tracer implementation for when tracing is disabled."""
|
|
122
122
|
|
|
123
|
-
def start_experiment(self, experiment_name=None,
|
|
123
|
+
def start_experiment(self, experiment_name=None, additional_metadata=None):
|
|
124
124
|
"""No-op experiment creation."""
|
|
125
125
|
return None
|
|
126
126
|
|
|
@@ -104,6 +104,11 @@ opt_verbose: Optional[List[bool]] = typer.Option(
|
|
|
104
104
|
"-v",
|
|
105
105
|
help="Verbose output. You can pass multiple times to increase the verbosity. e.g. -v or -vv or -vvv",
|
|
106
106
|
)
|
|
107
|
+
opt_log_costs: bool = typer.Option(
|
|
108
|
+
False,
|
|
109
|
+
"--log-costs",
|
|
110
|
+
help="Show LLM cost information in the output",
|
|
111
|
+
)
|
|
107
112
|
opt_echo_request: bool = typer.Option(
|
|
108
113
|
True,
|
|
109
114
|
"--echo/--no-echo",
|
|
@@ -176,6 +181,7 @@ def ask(
|
|
|
176
181
|
custom_toolsets: Optional[List[Path]] = opt_custom_toolsets,
|
|
177
182
|
max_steps: Optional[int] = opt_max_steps,
|
|
178
183
|
verbose: Optional[List[bool]] = opt_verbose,
|
|
184
|
+
log_costs: bool = opt_log_costs,
|
|
179
185
|
# semi-common options
|
|
180
186
|
destination: Optional[DestinationType] = opt_destination,
|
|
181
187
|
slack_token: Optional[str] = opt_slack_token,
|
|
@@ -219,7 +225,7 @@ def ask(
|
|
|
219
225
|
"""
|
|
220
226
|
Ask any question and answer using available tools
|
|
221
227
|
"""
|
|
222
|
-
console = init_logging(verbose) # type: ignore
|
|
228
|
+
console = init_logging(verbose, log_costs) # type: ignore
|
|
223
229
|
# Detect and read piped input
|
|
224
230
|
piped_data = None
|
|
225
231
|
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
{%- set k8s_yaml_ts = toolsets | selectattr("name", "equalto", "kubernetes/logs") | rejectattr("fetch_pod_logs", "defined") | first -%}
|
|
5
5
|
{%- set opensearch_ts = toolsets | selectattr("name", "equalto", "opensearch/logs") | first -%}
|
|
6
6
|
{%- set datadog_ts = toolsets | selectattr("name", "equalto", "datadog/logs") | first -%}
|
|
7
|
+
{%- set bash_ts = toolsets | selectattr("name", "equalto", "bash") | first -%}
|
|
7
8
|
|
|
8
9
|
## Logs
|
|
9
10
|
|
|
@@ -44,6 +45,9 @@ Tools to search and fetch logs from Kubernetes.
|
|
|
44
45
|
* Check both kubectl_logs and kubectl_previous_logs because a pod restart mean kubectl_logs may not have relevant logs
|
|
45
46
|
{%- elif opensearch_ts and opensearch_ts.status == "enabled" -%}
|
|
46
47
|
{% include '_default_log_prompt.jinja2' %}
|
|
48
|
+
{%- elif bash_ts and bash_ts.status == "enabled" -%}
|
|
49
|
+
Use the tool `run_bash_command` to run `kubectl logs` commands and fetch any relevant pod logs.
|
|
50
|
+
DO NOT use `--tail` or `| tail` when calling `kubectl logs` because you may miss critical information.
|
|
47
51
|
{%- else -%}
|
|
48
52
|
* You have not been given access to tools to fetch kubernetes logs for nodes, pods, services or apps. This is likely a misconfiguration.
|
|
49
53
|
* If you need logs to answer questions or investigate issues, tell the user to configure the documentation and enable one of these toolsets:
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
You are an expert in automated diagnostics and runbook creation for an AI-driven troubleshooting agents. I will provide you with one or more issue descriptions or test scenarios.
|
|
2
|
+
|
|
3
|
+
Your task is to generate a strictly executable runbook for AI Agent to follow. The runbook should be machine-readable but human-understandable, and must include the following sections:
|
|
4
|
+
|
|
5
|
+
# Runbook Content Structure
|
|
6
|
+
|
|
7
|
+
## 1. Goal
|
|
8
|
+
- **Primary Objective:** Clearly define the specific category of issues this runbook addresses (e.g., "diagnose network connectivity problems", "troubleshoot pod startup failures", "investigate performance degradation").
|
|
9
|
+
- **Scope:** Specify the environment, technology stack, or system components covered by this runbook.
|
|
10
|
+
- **Agent Mandate:** Explicitly state that the AI agent must follow the workflow steps sequentially and systematically without deviation to ensure consistent, thorough troubleshooting.
|
|
11
|
+
- **Expected Outcome:** Define what successful completion of this runbook should achieve (root cause identification, issue resolution, or escalation criteria).
|
|
12
|
+
|
|
13
|
+
## 2. Workflow for [Issue Category] Diagnosis
|
|
14
|
+
- Provide numbered, sequential steps the AI agent must execute in order.
|
|
15
|
+
- Each step should specify:
|
|
16
|
+
- **Action:** Describe the diagnostic function conceptually (e.g., "retrieve container logs from specified pod", "check service connectivity between components", "examine resource utilization metrics")
|
|
17
|
+
- **Function Description:** Explain what the function should accomplish rather than naming specific tools (e.g., "query the cluster to list all pods in a namespace and their current status" instead of "kubectl_get_pods()")
|
|
18
|
+
- **Parameters:** What data/arguments to pass to the function (namespace, pod name, time range, etc.)
|
|
19
|
+
- **Expected Output:** What information to gather from the result (status codes, error messages, metrics, configurations)
|
|
20
|
+
- **Success/Failure Criteria:** How to interpret the output and what indicates normal vs. problematic conditions
|
|
21
|
+
- Use conditional logic (IF/ELSE) when branching is required based on findings.
|
|
22
|
+
- Describe functions generically so they can be mapped to available tools (e.g., "execute a command to test network connectivity" rather than "ping_host()")
|
|
23
|
+
- Include verification steps to confirm each diagnostic action was successful.
|
|
24
|
+
|
|
25
|
+
## 3. Synthesize Findings
|
|
26
|
+
- **Data Correlation:** Describe how the AI agent should combine outputs from multiple workflow steps.
|
|
27
|
+
- **Pattern Recognition:** Specify what patterns, error messages, or metrics indicate specific root causes.
|
|
28
|
+
- **Prioritization Logic:** Provide criteria for ranking potential causes by likelihood or severity.
|
|
29
|
+
- **Evidence Requirements:** Define what evidence is needed to confidently identify each potential root cause.
|
|
30
|
+
- **Example Scenarios:** Include sample synthesis statements showing how findings should be summarized.
|
|
31
|
+
|
|
32
|
+
## 4. Recommended Remediation Steps
|
|
33
|
+
- **Immediate Actions:** List temporary workarounds or urgent fixes for critical issues.
|
|
34
|
+
- **Permanent Solutions:** Provide step-by-step permanent remediation procedures.
|
|
35
|
+
- **Verification Steps:** Define how to confirm each remediation action was successful.
|
|
36
|
+
- **Documentation References:** Include links to official documentation, best practices, or vendor guidance.
|
|
37
|
+
- **Escalation Criteria:** Specify when and how to escalate if remediation steps fail.
|
|
38
|
+
- **Post-Remediation Monitoring:** Describe what to monitor to prevent recurrence.
|
|
39
|
+
|
|
40
|
+
# File Organization Guidelines
|
|
41
|
+
|
|
42
|
+
## Folder Structure
|
|
43
|
+
*Category folders are used to distinguish and categorize different runbooks based on their focus area or technology domain. Each runbook must be placed into a specific category folder under `holmes/plugins/runbooks/` for better organization and discoverability. Create a new category folder if your runbook doesn't fit into existing categories.*
|
|
44
|
+
|
|
45
|
+
## File Naming
|
|
46
|
+
*Use consistent naming conventions for runbook files:*
|
|
47
|
+
|
|
48
|
+
- Use descriptive, lowercase names with hyphens: `dns-resolution-troubleshooting.md`
|
|
49
|
+
- Include the issue type or technology: `redis-connection-issues.md`
|
|
50
|
+
- Avoid generic names like `troubleshooting.md` or `debug.md`
|
|
51
|
+
|
|
52
|
+
### Catalog Registration
|
|
53
|
+
After creating your runbook, you must add an entry to `catalog.json` in the runbooks directory to make it discoverable by AI agents.
|
|
54
|
+
|
|
55
|
+
**Steps to add a new catalog entry:**
|
|
56
|
+
|
|
57
|
+
1. **Open** `holmes/plugins/runbooks/catalog.json`
|
|
58
|
+
2. **Add your entry** to the JSON array following this structure:
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"name": "Brief, descriptive name of the runbook",
|
|
62
|
+
"path": "category-folder/your-runbook-filename.md",
|
|
63
|
+
"description": "Clear description of what issues this runbook addresses",
|
|
64
|
+
"tags": ["relevant", "tags", "for", "search"]
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
3. **Ensure proper JSON formatting** - add a comma after the previous entry if needed
|
|
69
|
+
4. **Validate the JSON** is properly formatted before committing
|
|
70
|
+
|
|
71
|
+
**Field Guidelines:**
|
|
72
|
+
- `name`: Keep concise but descriptive (e.g., "Redis Connection Issues")
|
|
73
|
+
- `path`: Always include the category folder (e.g., "database/redis-connection-issues.md")
|
|
74
|
+
- `description`: Explain what specific problems this runbook solves
|
|
75
|
+
- `tags`: Include technology names, issue types, and relevant keywords
|
|
76
|
+
|
|
77
|
+
Example catalog entry:
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"name": "DNS Resolution Troubleshooting",
|
|
81
|
+
"path": "networking/dns-resolution-troubleshooting.md",
|
|
82
|
+
"description": "Comprehensive guide for diagnosing and resolving DNS resolution issues in Kubernetes clusters",
|
|
83
|
+
"tags": ["dns", "networking", "kubernetes", "troubleshooting"]
|
|
84
|
+
}
|
|
85
|
+
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Runbooks
|
|
2
|
+
|
|
3
|
+
Runbooks folder contains operational runbooks for the HolmesGPT project. Runbooks provide step-by-step instructions for common tasks, troubleshooting, and maintenance procedures related to the plugins in this directory.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
- Standardize operational processes
|
|
8
|
+
- Enable quick onboarding for new team members
|
|
9
|
+
- Reduce downtime by providing clear troubleshooting steps
|
|
10
|
+
|
|
11
|
+
## Structure
|
|
12
|
+
|
|
13
|
+
### Structured Runbook
|
|
14
|
+
|
|
15
|
+
Structured runbooks are designed for specific issues when conditions like issue name, id or source match, the corresponding instructions will be returned for investigation.
|
|
16
|
+
For example, the investigation in [kube-prometheus-stack.yaml](kube-prometheus-stack.yaml) will be returned when the issue to be investigated match either KubeSchedulerDown or KubeControllerManagerDown.
|
|
17
|
+
This runbook is mainly used for `holmes investigate`
|
|
18
|
+
|
|
19
|
+
### Catalog
|
|
20
|
+
|
|
21
|
+
Catalog specified in [catalog.json](catalog.json) contains a collection of runbooks written in markdown.
|
|
22
|
+
During runtime, LLM will compare the runbook description with the user question and return the most matched runbook for investigation. It's possible no runbook is returned for no match.
|
|
23
|
+
|
|
24
|
+
## Generating Runbooks
|
|
25
|
+
|
|
26
|
+
To ensure all runbooks follow a consistent format and improve troubleshooting accuracy, contributors should use the standardized [runbook format prompt](runbook-format.prompt.md) when creating new runbooks.
|
|
27
|
+
|
|
28
|
+
### Using the Runbook Format Prompt
|
|
29
|
+
|
|
30
|
+
1. **Start with the Template**: Use `prompt.md` as your guide when creating new runbooks
|
|
31
|
+
2. **Follow the Structure**: Ensure your runbook includes all required sections:
|
|
32
|
+
- **Goal**: Clear definition of issues addressed and agent mandate
|
|
33
|
+
- **Workflow**: Sequential diagnostic steps with detailed function descriptions
|
|
34
|
+
- **Synthesize Findings**: Logic for combining outputs and identifying root causes
|
|
35
|
+
- **Recommended Remediation Steps**: Both immediate and permanent solutions
|
|
36
|
+
|
|
37
|
+
### Benefits of Using the Standard Format
|
|
38
|
+
|
|
39
|
+
- **Consistency**: All runbooks follow the same structure and terminology
|
|
40
|
+
- **AI Agent Compatibility**: Ensures runbooks are machine-readable and executable by AI agents
|
|
41
|
+
- **Improved Accuracy**: Standardized format reduces ambiguity and improves diagnostic success rates
|
|
42
|
+
- **Maintainability**: Easier to update and maintain runbooks across the project
|
|
43
|
+
|
|
44
|
+
### Example Usage
|
|
45
|
+
|
|
46
|
+
When creating a runbook for a new issue category (e.g., storage problems, authentication failures), provide the issue description to an LLM along with the prompt template to generate a properly formatted runbook that follows the established patterns.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
from typing import Any, Optional
|
|
3
|
+
|
|
4
|
+
from holmes.plugins.toolsets.bash.common.bash_command import BashCommand
|
|
5
|
+
from holmes.plugins.toolsets.bash.common.config import BashExecutorConfig
|
|
6
|
+
from holmes.plugins.toolsets.bash.common.stringify import escape_shell_args
|
|
7
|
+
from holmes.plugins.toolsets.bash.argocd.constants import (
|
|
8
|
+
ALLOWED_ARGOCD_COMMANDS,
|
|
9
|
+
DENIED_ARGOCD_COMMANDS,
|
|
10
|
+
)
|
|
11
|
+
from holmes.plugins.toolsets.bash.common.validators import (
|
|
12
|
+
validate_command_and_operations,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ArgocdCommand(BashCommand):
|
|
17
|
+
def __init__(self):
|
|
18
|
+
super().__init__("argocd")
|
|
19
|
+
|
|
20
|
+
def add_parser(self, parent_parser: Any):
|
|
21
|
+
"""Create Argo CD CLI parser with safe command validation."""
|
|
22
|
+
argocd_parser = parent_parser.add_parser(
|
|
23
|
+
"argocd", help="Argo CD Command Line Interface", exit_on_error=False
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
# Add command subparser
|
|
27
|
+
argocd_parser.add_argument(
|
|
28
|
+
"command", help="Argo CD command (e.g., app, cluster, proj, repo)"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# Capture remaining arguments
|
|
32
|
+
argocd_parser.add_argument(
|
|
33
|
+
"options",
|
|
34
|
+
nargs=argparse.REMAINDER,
|
|
35
|
+
default=[],
|
|
36
|
+
help="Argo CD CLI subcommands, operations, and options",
|
|
37
|
+
)
|
|
38
|
+
return argocd_parser
|
|
39
|
+
|
|
40
|
+
def validate_command(
|
|
41
|
+
self, command: Any, original_command: str, config: Optional[BashExecutorConfig]
|
|
42
|
+
) -> None:
|
|
43
|
+
if hasattr(command, "options"):
|
|
44
|
+
validate_command_and_operations(
|
|
45
|
+
command.command,
|
|
46
|
+
command.options,
|
|
47
|
+
ALLOWED_ARGOCD_COMMANDS,
|
|
48
|
+
DENIED_ARGOCD_COMMANDS,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
def stringify_command(
|
|
52
|
+
self, command: Any, original_command: str, config: Optional[BashExecutorConfig]
|
|
53
|
+
) -> str:
|
|
54
|
+
"""Convert parsed Argo CD command back to safe command string."""
|
|
55
|
+
parts = ["argocd", command.command]
|
|
56
|
+
|
|
57
|
+
if hasattr(command, "options") and command.options:
|
|
58
|
+
parts.extend(command.options)
|
|
59
|
+
|
|
60
|
+
return " ".join(escape_shell_args(parts))
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def create_argocd_parser(parent_parser: Any):
|
|
64
|
+
argocd_command = ArgocdCommand()
|
|
65
|
+
return argocd_command.add_parser(parent_parser)
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
ALLOWED_ARGOCD_COMMANDS: dict[str, dict] = {
|
|
2
|
+
# Application management (read-only)
|
|
3
|
+
"app": {
|
|
4
|
+
"list": {},
|
|
5
|
+
"get": {},
|
|
6
|
+
"resources": {},
|
|
7
|
+
"diff": {},
|
|
8
|
+
"history": {},
|
|
9
|
+
"manifests": {},
|
|
10
|
+
"logs": {},
|
|
11
|
+
"wait": {}, # Wait for app to reach desired state (read-only monitoring)
|
|
12
|
+
},
|
|
13
|
+
# Cluster management (read-only)
|
|
14
|
+
"cluster": {
|
|
15
|
+
"list": {},
|
|
16
|
+
"get": {},
|
|
17
|
+
},
|
|
18
|
+
# Project management (read-only)
|
|
19
|
+
"proj": {
|
|
20
|
+
"list": {},
|
|
21
|
+
"get": {},
|
|
22
|
+
},
|
|
23
|
+
# Repository management (read-only)
|
|
24
|
+
"repo": {
|
|
25
|
+
"list": {},
|
|
26
|
+
"get": {},
|
|
27
|
+
},
|
|
28
|
+
# Context management (read-only operations)
|
|
29
|
+
"context": {},
|
|
30
|
+
# Version information (completely safe)
|
|
31
|
+
"version": {},
|
|
32
|
+
# Account information (read-only)
|
|
33
|
+
"account": {
|
|
34
|
+
"list": {},
|
|
35
|
+
"get": {},
|
|
36
|
+
"get-user-info": {},
|
|
37
|
+
"can-i": {},
|
|
38
|
+
},
|
|
39
|
+
# Administrative commands (limited read-only)
|
|
40
|
+
"admin": {
|
|
41
|
+
"dashboard": {}, # Starts read-only web UI
|
|
42
|
+
"settings": {}, # Shows/validates settings (read-only)
|
|
43
|
+
},
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
DENIED_ARGOCD_COMMANDS: dict[str, dict] = {
|
|
47
|
+
# Authentication operations (sensitive)
|
|
48
|
+
"login": {},
|
|
49
|
+
"logout": {},
|
|
50
|
+
"relogin": {},
|
|
51
|
+
# Application lifecycle operations (state-modifying)
|
|
52
|
+
"app": {
|
|
53
|
+
"create": {},
|
|
54
|
+
"delete": {},
|
|
55
|
+
"sync": {},
|
|
56
|
+
"rollback": {},
|
|
57
|
+
"edit": {},
|
|
58
|
+
"set": {},
|
|
59
|
+
"unset": {},
|
|
60
|
+
"patch": {},
|
|
61
|
+
"delete-resource": {},
|
|
62
|
+
"terminate-op": {},
|
|
63
|
+
"actions": {}, # Custom resource actions
|
|
64
|
+
},
|
|
65
|
+
# Account management (sensitive)
|
|
66
|
+
"account": {
|
|
67
|
+
"generate-token": {},
|
|
68
|
+
"delete-token": {},
|
|
69
|
+
"update-password": {},
|
|
70
|
+
"bcrypt": {},
|
|
71
|
+
},
|
|
72
|
+
# Cluster management (state-modifying)
|
|
73
|
+
"cluster": {
|
|
74
|
+
"add": {},
|
|
75
|
+
"rm": {},
|
|
76
|
+
"set": {},
|
|
77
|
+
"rotate-auth": {},
|
|
78
|
+
},
|
|
79
|
+
# Project management (state-modifying)
|
|
80
|
+
"proj": {
|
|
81
|
+
"create": {},
|
|
82
|
+
"delete": {},
|
|
83
|
+
"edit": {},
|
|
84
|
+
"add-source": {},
|
|
85
|
+
"remove-source": {},
|
|
86
|
+
"add-destination": {},
|
|
87
|
+
"remove-destination": {},
|
|
88
|
+
"add-cluster-resource-whitelist": {},
|
|
89
|
+
"remove-cluster-resource-whitelist": {},
|
|
90
|
+
"add-namespace-resource-blacklist": {},
|
|
91
|
+
"remove-namespace-resource-blacklist": {},
|
|
92
|
+
"add-cluster-resource-blacklist": {},
|
|
93
|
+
"remove-cluster-resource-blacklist": {},
|
|
94
|
+
"add-namespace-resource-whitelist": {},
|
|
95
|
+
"remove-namespace-resource-whitelist": {},
|
|
96
|
+
"add-orphaned-ignore": {},
|
|
97
|
+
"remove-orphaned-ignore": {},
|
|
98
|
+
"add-signature-key": {},
|
|
99
|
+
"remove-signature-key": {},
|
|
100
|
+
"set-orphaned-ignore": {},
|
|
101
|
+
"add-role": {},
|
|
102
|
+
"remove-role": {},
|
|
103
|
+
"add-role-token": {},
|
|
104
|
+
"delete-role-token": {},
|
|
105
|
+
"set-role": {},
|
|
106
|
+
},
|
|
107
|
+
# Repository management (state-modifying)
|
|
108
|
+
"repo": {
|
|
109
|
+
"add": {},
|
|
110
|
+
"rm": {},
|
|
111
|
+
},
|
|
112
|
+
# Certificate management
|
|
113
|
+
"cert": {},
|
|
114
|
+
# GPG key management
|
|
115
|
+
"gpg": {},
|
|
116
|
+
# Application set operations
|
|
117
|
+
"appset": {},
|
|
118
|
+
# Notification operations
|
|
119
|
+
"notifications": {},
|
|
120
|
+
}
|