Files
wehub-resource-sync 4b6817381b
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
CI / coverage-report (push) Has been cancelled
CI / test-kubernetes (push) Has been cancelled
CI / should-run-thorough (push) Has been cancelled
CI / test-thorough (cloudwatch-demo) (push) Has been cancelled
CI / test-thorough (flink-ecs) (push) Has been cancelled
CI / test-thorough (upstream-lambda) (push) Has been cancelled
CI / test-thorough (prefect-ecs-fargate) (push) Has been cancelled
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Has been cancelled
Benchmark image — build + push to ECR (any adapter) / build + push (push) Has been cancelled
CI / quality (ubuntu-latest) (push) Has been cancelled
CI / test (tools-runtime) (push) Has been cancelled
CI / test (e2e-general) (push) Has been cancelled
CI / test (cli-runtime) (push) Has been cancelled
CI / test (e2e-provider-and-openclaw) (push) Has been cancelled
CI / test (integrations-and-misc) (push) Has been cancelled
Release / verify (push) Has been cancelled
Release / build-python-dist (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Has been cancelled
Release / publish-release (push) Has been cancelled
Release / publish-main-release (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Has been cancelled
Release / prepare (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Has been cancelled
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:10:45 +08:00

499 lines
18 KiB
Python

# ======== from tools/temporal_namespace_info_tool/ ========
"""Temporal namespace health overview tool."""
from __future__ import annotations
from typing import Any
from core.tool_framework.base import BaseTool
from integrations.temporal.client import TemporalClient, TemporalConfig
class TemporalNamespaceInfoTool(BaseTool):
"""Fetch namespace state and workflow counts grouped by execution status.
This is the first tool to call when investigating Temporal-related incidents.
It provides a high-level health snapshot: is the namespace active, and how
many workflows are running vs failed vs timed out. Use this to determine
whether something is wrong before drilling into specific workflows.
"""
name = "temporal_namespace_info"
source = "temporal"
description = (
"Fetch Temporal namespace health overview: namespace state and workflow "
"execution counts grouped by status (Running, Failed, TimedOut, etc.). "
"Use as the first investigation step to assess overall namespace health."
)
use_cases = [
"Getting a high-level health snapshot of a Temporal namespace",
"Checking if a namespace is active or deprecated/deleted",
"Counting how many workflows are currently running, failed, or timed out",
"Determining whether a Temporal incident is widespread or isolated",
"Initial triage before drilling into specific workflow failures",
]
requires = ["base_url", "namespace"]
injected_params = ["base_url", "api_key", "namespace"]
input_schema = {
"type": "object",
"properties": {
"base_url": {
"type": "string",
"description": "Temporal server base URL.",
},
"api_key": {
"type": "string",
"default": "",
"description": "Temporal API key. Empty for unauthenticated self-hosted clusters.",
},
"namespace": {
"type": "string",
"default": "default",
"description": "Temporal namespace to inspect.",
},
},
"required": ["base_url", "namespace"],
}
outputs = {
"name": "Namespace name",
"state": "Namespace state (REGISTERED, DEPRECATED, DELETED)",
"workflow_count": "Total workflow executions across all statuses",
"groups": "Breakdown of workflow counts by execution status",
}
def is_available(self, sources: dict[str, Any]) -> bool:
temporal = sources.get("temporal", {})
return bool(temporal.get("base_url"))
def extract_params(self, sources: dict[str, Any]) -> dict[str, Any]:
temporal = sources.get("temporal", {})
return {
"base_url": temporal.get("base_url", ""),
"api_key": temporal.get("api_key", ""),
"namespace": temporal.get("namespace", "default"),
}
def run(
self,
base_url: str,
api_key: str = "",
namespace: str = "default",
**_kwargs: Any,
) -> dict[str, Any]:
if not base_url:
return {
"source": "temporal",
"available": False,
"error": "base_url is required to connect to Temporal.",
}
config = TemporalConfig(base_url=base_url, api_key=api_key, namespace=namespace)
with TemporalClient(config) as client:
result = client.get_namespace_info()
if not result.get("success"):
return {
"source": "temporal",
"available": False,
"error": result.get("error", "Unknown error fetching namespace info."),
}
return {
"source": "temporal",
"available": True,
"name": result["name"],
"state": result["state"],
"workflow_count": result["workflow_count"],
"groups": result["groups"],
}
temporal_namespace_info = TemporalNamespaceInfoTool()
# ======== from tools/temporal_task_queue_tool/ ========
"""Temporal task queue description tool."""
from core.tool_framework.base import BaseTool
class TemporalTaskQueueTool(BaseTool):
"""Describe a task queue's pollers and backlog stats.
After identifying failed workflows and the task queues they ran on, use this
tool to check worker health. Empty pollers mean workers are down. A growing
backlog (high approximateBacklogCount, tasksAddRate > tasksDispatchRate)
means workers can't keep up. Stale lastAccessTime on pollers indicates
workers have stopped heartbeating.
Task queue names are discovered from workflow executions — each execution
reports which task queue it ran on. The Temporal API does not expose a
"list all task queues" endpoint.
"""
name = "temporal_task_queue"
source = "temporal"
description = (
"Describe a Temporal task queue: active worker pollers and backlog stats "
"(approximate count, age, add/dispatch rates). Use after identifying failed "
"workflows to check if workers are down or overwhelmed on that queue."
)
use_cases = [
"Checking if workers are polling a task queue (are they alive?)",
"Detecting worker outages (empty pollers list = no workers connected)",
"Identifying backlog buildup (tasks queued faster than dispatched)",
"Correlating workflow timeouts with stale worker heartbeats",
"Verifying worker capacity after a deployment or scaling event",
]
requires = ["base_url", "namespace"]
injected_params = ["base_url", "api_key", "namespace"]
input_schema = {
"type": "object",
"properties": {
"base_url": {
"type": "string",
"description": "Temporal server base URL.",
},
"api_key": {
"type": "string",
"default": "",
"description": "Temporal API key. Empty for unauthenticated self-hosted clusters.",
},
"namespace": {
"type": "string",
"default": "default",
"description": "Temporal namespace.",
},
"task_queue_name": {
"type": "string",
"description": (
"Name of the task queue to inspect. Obtain this from the taskQueue "
"field in workflow execution results."
),
},
},
"required": ["base_url", "namespace", "task_queue_name"],
}
outputs = {
"pollers": "List of active worker pollers with identity, lastAccessTime, and ratePerSecond",
"stats": "Backlog metrics: approximateBacklogCount, approximateBacklogAge, tasksAddRate, tasksDispatchRate",
"total": "Number of active pollers on this queue",
}
def is_available(self, sources: dict[str, Any]) -> bool:
temporal = sources.get("temporal", {})
return bool(temporal.get("base_url"))
def extract_params(self, sources: dict[str, Any]) -> dict[str, Any]:
temporal = sources.get("temporal", {})
return {
"base_url": temporal.get("base_url", ""),
"api_key": temporal.get("api_key", ""),
"namespace": temporal.get("namespace", "default"),
}
def run(
self,
base_url: str,
task_queue_name: str,
api_key: str = "",
namespace: str = "default",
**_kwargs: Any,
) -> dict[str, Any]:
if not base_url:
return {
"source": "temporal",
"available": False,
"error": "base_url is required to connect to Temporal.",
"pollers": [],
"stats": {},
}
if not task_queue_name:
return {
"source": "temporal",
"available": True,
"error": "task_queue_name is required. Get it from the taskQueue field in workflow execution results.",
"pollers": [],
"stats": {},
}
config = TemporalConfig(base_url=base_url, api_key=api_key, namespace=namespace)
with TemporalClient(config) as client:
result = client.describe_task_queue(task_queue_name=task_queue_name)
if not result.get("success"):
return {
"source": "temporal",
"available": False,
"error": result.get("error", "Unknown error describing task queue."),
"pollers": [],
"stats": {},
}
return {
"source": "temporal",
"available": True,
"pollers": result["pollers"],
"stats": result["stats"],
"total": result["total"],
}
temporal_task_queue = TemporalTaskQueueTool()
# ======== from tools/temporal_workflow_history_tool/ ========
"""Temporal workflow execution history tool."""
from core.tool_framework.base import BaseTool
class TemporalWorkflowHistoryTool(BaseTool):
"""Fetch the event history for a specific workflow execution.
After identifying a failed workflow via the workflows tool, use this to see
the ordered sequence of events that tells the story of what happened:
workflow started, activity scheduled, activity failed, workflow failed, etc.
This is essential for diagnosing root cause — e.g. "the payment activity
timed out after 3 retries" or "the child workflow was terminated externally."
"""
name = "temporal_workflow_history"
source = "temporal"
description = (
"Fetch the event history for a specific Temporal workflow execution. "
"Shows the ordered sequence of events (started, activity scheduled, "
"activity failed, workflow failed, etc.) to diagnose why a workflow failed."
)
use_cases = [
"Diagnosing why a specific workflow execution failed",
"Identifying which activity within a workflow timed out or errored",
"Tracing the sequence of events leading to workflow failure",
"Checking if a workflow was terminated externally or failed internally",
"Finding retry patterns that indicate transient vs persistent failures",
]
requires = ["base_url", "namespace"]
injected_params = ["base_url", "api_key", "namespace"]
input_schema = {
"type": "object",
"properties": {
"base_url": {
"type": "string",
"description": "Temporal server base URL.",
},
"api_key": {
"type": "string",
"default": "",
"description": "Temporal API key. Empty for unauthenticated self-hosted clusters.",
},
"namespace": {
"type": "string",
"default": "default",
"description": "Temporal namespace.",
},
"workflow_id": {
"type": "string",
"description": "The workflow ID to fetch history for.",
},
"run_id": {
"type": "string",
"default": "",
"description": (
"Specific run ID. If omitted, returns history for the latest run "
"of the given workflow ID."
),
},
"next_page_token": {
"type": "string",
"default": "",
"description": "Pagination token from a previous response to fetch the next page.",
},
},
"required": ["base_url", "namespace", "workflow_id"],
}
outputs = {
"events": "Ordered list of history events with eventId, eventTime, and eventType",
"total": "Number of events returned in this page",
"next_page_token": "Token for fetching the next page of events",
"archived": "Whether the history was retrieved from archival storage",
}
def is_available(self, sources: dict[str, Any]) -> bool:
temporal = sources.get("temporal", {})
return bool(temporal.get("base_url"))
def extract_params(self, sources: dict[str, Any]) -> dict[str, Any]:
temporal = sources.get("temporal", {})
return {
"base_url": temporal.get("base_url", ""),
"api_key": temporal.get("api_key", ""),
"namespace": temporal.get("namespace", "default"),
}
def run(
self,
base_url: str,
workflow_id: str,
api_key: str = "",
namespace: str = "default",
run_id: str = "",
next_page_token: str = "",
**_kwargs: Any,
) -> dict[str, Any]:
if not base_url:
return {
"source": "temporal",
"available": False,
"error": "base_url is required to connect to Temporal.",
"events": [],
}
if not workflow_id:
return {
"source": "temporal",
"available": True,
"error": "workflow_id is required to fetch execution history.",
"events": [],
}
config = TemporalConfig(base_url=base_url, api_key=api_key, namespace=namespace)
with TemporalClient(config) as client:
result = client.get_workflow_history(
workflow_id=workflow_id,
run_id=run_id if run_id else None,
next_page_token=next_page_token if next_page_token else None,
)
if not result.get("success"):
return {
"source": "temporal",
"available": False,
"error": result.get("error", "Unknown error fetching workflow history."),
"events": [],
}
return {
"source": "temporal",
"available": True,
"events": result["events"],
"total": result["total"],
"next_page_token": result["next_page_token"],
"archived": result["archived"],
}
temporal_workflow_history = TemporalWorkflowHistoryTool()
# ======== from tools/temporal_workflows_tool/ ========
"""Temporal workflow executions listing tool."""
from core.tool_framework.base import BaseTool
class TemporalWorkflowsTool(BaseTool):
"""List recent workflow executions with status and failure reason.
After identifying a problem via namespace info (e.g. "8 workflows failed"),
use this tool to see which specific workflows failed, when they started and
closed, what type they are, and which task queue they ran on. The task queue
name from these results feeds into the task queue tool for worker health checks.
"""
name = "temporal_workflows"
source = "temporal"
description = (
"List recent Temporal workflow executions showing workflowId, type, status, "
"taskQueue, and timing. Use after namespace info reveals failures, to identify "
"which specific workflows failed and on which task queues."
)
use_cases = [
"Listing recent workflow executions to find failures",
"Identifying which workflow types are failing",
"Discovering which task queues are involved in failures",
"Getting workflowId and runId for detailed history inspection",
"Correlating workflow failures with infrastructure alerts",
]
requires = ["base_url", "namespace"]
injected_params = ["base_url", "api_key", "namespace"]
input_schema = {
"type": "object",
"properties": {
"base_url": {
"type": "string",
"description": "Temporal server base URL.",
},
"api_key": {
"type": "string",
"default": "",
"description": "Temporal API key. Empty for unauthenticated self-hosted clusters.",
},
"namespace": {
"type": "string",
"default": "default",
"description": "Temporal namespace to query.",
},
"next_page_token": {
"type": "string",
"default": "",
"description": "Pagination token from a previous response to fetch the next page.",
},
},
"required": ["base_url", "namespace"],
}
outputs = {
"executions": "List of workflow executions with workflowId, type, status, taskQueue, and timing",
"total": "Number of executions returned in this page",
"next_page_token": "Token for fetching the next page of results",
}
def is_available(self, sources: dict[str, Any]) -> bool:
temporal = sources.get("temporal", {})
return bool(temporal.get("base_url"))
def extract_params(self, sources: dict[str, Any]) -> dict[str, Any]:
temporal = sources.get("temporal", {})
return {
"base_url": temporal.get("base_url", ""),
"api_key": temporal.get("api_key", ""),
"namespace": temporal.get("namespace", "default"),
}
def run(
self,
base_url: str,
api_key: str = "",
namespace: str = "default",
next_page_token: str = "",
**_kwargs: Any,
) -> dict[str, Any]:
if not base_url:
return {
"source": "temporal",
"available": False,
"error": "base_url is required to connect to Temporal.",
"executions": [],
}
config = TemporalConfig(base_url=base_url, api_key=api_key, namespace=namespace)
with TemporalClient(config) as client:
token = next_page_token if next_page_token else None
result = client.list_workflow_executions(next_page_token=token)
if not result.get("success"):
return {
"source": "temporal",
"available": False,
"error": result.get("error", "Unknown error listing workflow executions."),
"executions": [],
}
return {
"source": "temporal",
"available": True,
"executions": result["executions"],
"total": result["total"],
"next_page_token": result["next_page_token"],
}
temporal_workflows = TemporalWorkflowsTool()