dispatch_agents 0.12.2__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.
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/PKG-INFO +1 -1
- dispatch_agents-0.13.1/RELEASE_NOTES.md +2 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/__init__.py +3 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/config.py +161 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/integrations/github/__init__.py +31 -13
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/hello_world/uv.lock +50 -49
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/pyproject.toml +2 -1
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_config.py +240 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_github_integration.py +384 -429
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_github_schema_compliance.py +93 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/uv.lock +367 -328
- dispatch_agents-0.12.2/RELEASE_NOTES.md +0 -1
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/.claude-plugin/marketplace.json +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/.github/scripts/change_scope.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/.github/scripts/ci_git.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/.github/scripts/version_policy.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/.github/tests/test_change_scope.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/.github/tests/test_ci_git.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/.github/tests/test_version_policy.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/.github/workflows/ci-reusable.yml +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/.github/workflows/feature-branch.yml +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/.github/workflows/release.yml +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/.github/workflows/version-policy-reusable.yml +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/.gitignore +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/CONTRIBUTING.md +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/LICENSE +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/LICENSE-3rdparty.csv +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/NOTICE +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/README.md +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/agentservice/__init__.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/agentservice/py.typed +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/agentservice/v1/__init__.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/agentservice/v1/message_pb2.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/agentservice/v1/message_pb2.pyi +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/agentservice/v1/message_pb2_grpc.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/agentservice/v1/request_response_pb2.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/agentservice/v1/request_response_pb2.pyi +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/agentservice/v1/request_response_pb2_grpc.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/agentservice/v1/service_pb2.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/agentservice/v1/service_pb2.pyi +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/agentservice/v1/service_pb2_grpc.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/agent_service.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/contrib/__init__.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/contrib/claude/__init__.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/contrib/openai/__init__.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/events.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/grpc_server.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/instrument.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/integrations/__init__.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/integrations/github/README.md +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/integrations/github/client.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/invocation.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/llm.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/llm_langchain.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/logging_config.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/mcp.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/memory.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/models.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/proxy/__init__.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/proxy/server.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/proxy/sse_utils.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/py.typed +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/resources.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/version.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/README.md +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/company-researcher/.gitignore +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/company-researcher/AGENTS.md +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/company-researcher/README.md +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/company-researcher/agent.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/company-researcher/dispatch.yaml +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/company-researcher/pyproject.toml +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/company-researcher/uv.lock +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/conversational-agent/README.md +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/conversational-agent/agent.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/conversational-agent/dispatch.yaml +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/conversational-agent/pyproject.toml +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/daily-digest/README.md +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/daily-digest/agent.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/daily-digest/dispatch.yaml +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/daily-digest/pyproject.toml +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/deep-research/README.md +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/deep-research/agent.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/deep-research/configuration.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/deep-research/deep_researcher.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/deep-research/dispatch.yaml +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/deep-research/prompts.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/deep-research/pyproject.toml +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/deep-research/state.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/deep-research/tools.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/hello_world/.gitignore +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/hello_world/AGENTS.md +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/hello_world/agent.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/hello_world/dispatch.yaml +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/hello_world/pyproject.toml +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/hello_world/test_agent.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/knowledge-base-query/.env.example +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/knowledge-base-query/.gitignore +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/knowledge-base-query/AGENTS.md +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/knowledge-base-query/agent.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/knowledge-base-query/dispatch.yaml +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/knowledge-base-query/pyproject.toml +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/multi-framework/README.md +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/multi-framework/agent.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/multi-framework/dispatch.yaml +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/multi-framework/pyproject.toml +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/pyproject.toml +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/uv.lock +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/weather-assistant/.gitignore +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/weather-assistant/AGENTS.md +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/weather-assistant/agent.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/weather-assistant/dispatch.yaml +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/weather-assistant/pyproject.toml +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/weather-assistant/uv.lock +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/weather-service/.gitignore +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/weather-service/AGENTS.md +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/weather-service/agent.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/weather-service/dispatch.yaml +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/weather-service/pyproject.toml +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/examples/weather-service/uv.lock +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/internal/py.typed +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/plugins/README.md +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/__init__.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/e2e_claude_mcp_proxy.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/schemas/README.md +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/schemas/octokit-webhooks.json +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_agent_service.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_agent_uid.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_contrib_claude.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_contrib_openai.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_dev_mode_isolation.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_extra_headers.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_fn_decorator.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_github_client.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_grpc_server.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_init.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_instrument.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_llm_langchain.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_llm_logging.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_logging_config.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_mcp.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_memory.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_proxy_e2e.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_proxy_server.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_resources.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_sse_utils.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_trace_context.py +0 -0
- {dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/tests/test_typed_events.py +0 -0
|
@@ -162,6 +162,7 @@ def _dev_mode_audit_hook(event: str, args: tuple) -> None:
|
|
|
162
162
|
|
|
163
163
|
|
|
164
164
|
from .agent_service import AgentServiceClient
|
|
165
|
+
from .config import _runtime as config
|
|
165
166
|
from .events import (
|
|
166
167
|
HANDLER_METADATA,
|
|
167
168
|
REGISTERED_HANDLERS,
|
|
@@ -208,6 +209,8 @@ from .models import (
|
|
|
208
209
|
)
|
|
209
210
|
|
|
210
211
|
__all__ = [
|
|
212
|
+
# runtime config
|
|
213
|
+
"config",
|
|
211
214
|
# storage and dev mode isolation
|
|
212
215
|
"get_data_dir",
|
|
213
216
|
"DisallowedWriteError",
|
|
@@ -500,6 +500,49 @@ class DispatchConfig(BaseModel):
|
|
|
500
500
|
raise ValueError(f"All env values must be strings. {examples}")
|
|
501
501
|
return v
|
|
502
502
|
|
|
503
|
+
vars: dict[str, Any] | None = Field(
|
|
504
|
+
default=None,
|
|
505
|
+
description="Configuration variables accessible at runtime via dispatch_agents.config.vars. "
|
|
506
|
+
"Unlike env, these are NOT injected as environment variables. "
|
|
507
|
+
"Supports any YAML-serializable type. Use {value: <any>, description: <str>} "
|
|
508
|
+
"to attach descriptions for the UI.",
|
|
509
|
+
)
|
|
510
|
+
|
|
511
|
+
@field_validator("vars", mode="before")
|
|
512
|
+
@classmethod
|
|
513
|
+
def _validate_vars(cls, v: dict | None) -> dict[str, Any] | None:
|
|
514
|
+
"""Validate vars format.
|
|
515
|
+
|
|
516
|
+
Non-dict values (str, int, float, bool, list, None) are allowed as-is.
|
|
517
|
+
Dict values must use the described-var shape:
|
|
518
|
+
``{value: <any>, description?: <str>}``. Other dicts are rejected
|
|
519
|
+
because ``value`` and ``description`` are reserved keywords — silently
|
|
520
|
+
treating arbitrary dicts as plain values would let a caller
|
|
521
|
+
accidentally collide with the described-var schema.
|
|
522
|
+
"""
|
|
523
|
+
if not v or not isinstance(v, dict):
|
|
524
|
+
return v
|
|
525
|
+
_DESCRIBED_KEYS = {"value", "description"}
|
|
526
|
+
for key, val in v.items():
|
|
527
|
+
if not isinstance(val, dict):
|
|
528
|
+
continue
|
|
529
|
+
if "value" not in val:
|
|
530
|
+
raise ValueError(
|
|
531
|
+
f"Var '{key}' is a dict without a 'value' key. Dict values "
|
|
532
|
+
"must use the described-var shape "
|
|
533
|
+
"{value: <any>, description?: <str>}. To store structured "
|
|
534
|
+
"data, nest it under 'value'."
|
|
535
|
+
)
|
|
536
|
+
extra = set(val.keys()) - _DESCRIBED_KEYS
|
|
537
|
+
if extra:
|
|
538
|
+
raise ValueError(
|
|
539
|
+
f"Var '{key}' has unexpected keys {sorted(extra)}. Dict "
|
|
540
|
+
"values may only use the described-var shape "
|
|
541
|
+
"{value: <any>, description?: <str>}. To store structured "
|
|
542
|
+
"data, nest it under 'value'."
|
|
543
|
+
)
|
|
544
|
+
return v
|
|
545
|
+
|
|
503
546
|
secrets: list[SecretConfig] | None = Field(
|
|
504
547
|
default=None,
|
|
505
548
|
description="Secrets to inject as environment variables",
|
|
@@ -573,10 +616,14 @@ class DispatchConfig(BaseModel):
|
|
|
573
616
|
result["local_dependencies"] = self.local_dependencies
|
|
574
617
|
if self.env:
|
|
575
618
|
result["env"] = dict(self.env)
|
|
619
|
+
if self.vars:
|
|
620
|
+
result["vars"] = dict(self.vars)
|
|
576
621
|
if self.secrets:
|
|
577
622
|
result["secrets"] = [
|
|
578
623
|
{"name": s.name, "secret_id": s.secret_id} for s in self.secrets
|
|
579
624
|
]
|
|
625
|
+
if self.mcp_servers:
|
|
626
|
+
result["mcp_servers"] = [{"server": m.server} for m in self.mcp_servers]
|
|
580
627
|
if self.volumes:
|
|
581
628
|
result["volumes"] = [
|
|
582
629
|
{"name": v.name, "mountPath": v.mount_path, "mode": v.mode.value}
|
|
@@ -602,3 +649,117 @@ class DispatchConfig(BaseModel):
|
|
|
602
649
|
return result
|
|
603
650
|
|
|
604
651
|
model_config = {"populate_by_name": True}
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
# ---------------------------------------------------------------------------
|
|
655
|
+
# Runtime config singleton
|
|
656
|
+
# ---------------------------------------------------------------------------
|
|
657
|
+
|
|
658
|
+
import functools as _functools
|
|
659
|
+
|
|
660
|
+
_DISPATCH_YAML_PATH = "/app/dispatch.yaml"
|
|
661
|
+
|
|
662
|
+
|
|
663
|
+
@_functools.lru_cache(maxsize=1)
|
|
664
|
+
def _load_runtime_config() -> "DispatchConfig":
|
|
665
|
+
"""Load dispatch.yaml once and cache the parsed DispatchConfig.
|
|
666
|
+
|
|
667
|
+
Falls back to an empty DispatchConfig when the file is absent
|
|
668
|
+
(dev mode or non-containerized runs). Namespace and agent_name
|
|
669
|
+
additionally fall back to DISPATCH_NAMESPACE / DISPATCH_AGENT_NAME
|
|
670
|
+
env vars so local ``dispatch agent dev`` runs work transparently.
|
|
671
|
+
"""
|
|
672
|
+
import yaml as _yaml
|
|
673
|
+
|
|
674
|
+
path = os.environ.get("DISPATCH_CONFIG_PATH", _DISPATCH_YAML_PATH)
|
|
675
|
+
raw: dict = {}
|
|
676
|
+
if os.path.exists(path):
|
|
677
|
+
with open(path, encoding="utf-8") as f:
|
|
678
|
+
raw = _yaml.safe_load(f) or {}
|
|
679
|
+
|
|
680
|
+
cfg = DispatchConfig.model_validate(raw)
|
|
681
|
+
|
|
682
|
+
# Env-var fallbacks for identity fields used outside containers
|
|
683
|
+
updates: dict[str, Any] = {}
|
|
684
|
+
if cfg.namespace is None:
|
|
685
|
+
ns = os.environ.get("DISPATCH_NAMESPACE")
|
|
686
|
+
if ns:
|
|
687
|
+
updates["namespace"] = ns
|
|
688
|
+
if cfg.agent_name is None:
|
|
689
|
+
name = os.environ.get("DISPATCH_AGENT_NAME")
|
|
690
|
+
if name:
|
|
691
|
+
updates["agent_name"] = name
|
|
692
|
+
if updates:
|
|
693
|
+
cfg = cfg.model_copy(update=updates)
|
|
694
|
+
|
|
695
|
+
return cfg
|
|
696
|
+
|
|
697
|
+
|
|
698
|
+
_DESCRIBED_VAR_KEYS = frozenset({"value", "description"})
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
def _is_described_var(val: Any) -> bool:
|
|
702
|
+
"""Check if a value is a described var ({value, description}) vs a plain dict."""
|
|
703
|
+
return (
|
|
704
|
+
isinstance(val, dict)
|
|
705
|
+
and "value" in val
|
|
706
|
+
and set(val.keys()) <= _DESCRIBED_VAR_KEYS
|
|
707
|
+
)
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
def _unwrap_vars(raw: dict[str, Any] | None) -> dict[str, Any]:
|
|
711
|
+
"""Unwrap described vars ({value, description}) to plain values.
|
|
712
|
+
|
|
713
|
+
Plain dicts (with keys outside {value, description}) are passed through as-is.
|
|
714
|
+
"""
|
|
715
|
+
if not raw:
|
|
716
|
+
return {}
|
|
717
|
+
result: dict[str, Any] = {}
|
|
718
|
+
for key, val in raw.items():
|
|
719
|
+
if _is_described_var(val):
|
|
720
|
+
result[key] = val["value"]
|
|
721
|
+
else:
|
|
722
|
+
result[key] = val
|
|
723
|
+
return result
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+
def _extract_var_descriptions(raw: dict[str, Any] | None) -> dict[str, str]:
|
|
727
|
+
"""Extract description strings from described vars."""
|
|
728
|
+
if not raw:
|
|
729
|
+
return {}
|
|
730
|
+
result: dict[str, str] = {}
|
|
731
|
+
for key, val in raw.items():
|
|
732
|
+
if _is_described_var(val) and "description" in val:
|
|
733
|
+
result[key] = val["description"]
|
|
734
|
+
return result
|
|
735
|
+
|
|
736
|
+
|
|
737
|
+
class _RuntimeConfig:
|
|
738
|
+
"""Proxy that exposes dispatch.yaml fields at runtime.
|
|
739
|
+
|
|
740
|
+
Usage::
|
|
741
|
+
|
|
742
|
+
from dispatch_agents import config
|
|
743
|
+
|
|
744
|
+
config.namespace # str | None
|
|
745
|
+
config.agent_name # str | None
|
|
746
|
+
config.vars["temperature"] # 0.7 (unwrapped)
|
|
747
|
+
config.vars.get("missing") # None
|
|
748
|
+
config.vars_descriptions["max_turns"] # "Maximum agent turns"
|
|
749
|
+
"""
|
|
750
|
+
|
|
751
|
+
@property
|
|
752
|
+
def vars(self) -> dict[str, Any]:
|
|
753
|
+
"""Return unwrapped vars dict (described vars return just the value)."""
|
|
754
|
+
return _unwrap_vars(_load_runtime_config().vars)
|
|
755
|
+
|
|
756
|
+
@property
|
|
757
|
+
def vars_descriptions(self) -> dict[str, str]:
|
|
758
|
+
"""Return descriptions for vars that have them."""
|
|
759
|
+
return _extract_var_descriptions(_load_runtime_config().vars)
|
|
760
|
+
|
|
761
|
+
def __getattr__(self, name: str) -> Any:
|
|
762
|
+
return getattr(_load_runtime_config(), name)
|
|
763
|
+
|
|
764
|
+
|
|
765
|
+
_runtime = _RuntimeConfig()
|
{dispatch_agents-0.12.2 → dispatch_agents-0.13.1}/dispatch_agents/integrations/github/__init__.py
RENAMED
|
@@ -83,9 +83,9 @@ GitHub Topics:
|
|
|
83
83
|
|
|
84
84
|
from __future__ import annotations
|
|
85
85
|
|
|
86
|
-
from typing import Any, ClassVar, Literal
|
|
86
|
+
from typing import Any, ClassVar, Literal, Self
|
|
87
87
|
|
|
88
|
-
from pydantic import ConfigDict, Field
|
|
88
|
+
from pydantic import ConfigDict, Field, StrictInt, model_validator
|
|
89
89
|
|
|
90
90
|
from dispatch_agents.events import BasePayload
|
|
91
91
|
from dispatch_agents.integrations.github.client import GitHubAppToken
|
|
@@ -209,12 +209,12 @@ class GitHubRepository(GitHubModel):
|
|
|
209
209
|
description: str | None = Field(default=None, description="Repository description")
|
|
210
210
|
fork: bool = Field(default=False, description="Whether this is a fork")
|
|
211
211
|
url: str | None = Field(default=None, description="API URL")
|
|
212
|
-
created_at:
|
|
213
|
-
|
|
212
|
+
created_at: StrictInt | str = Field(
|
|
213
|
+
description="Creation timestamp (Unix epoch int or ISO8601 string)",
|
|
214
214
|
)
|
|
215
215
|
updated_at: str | None = Field(default=None, description="ISO8601 update timestamp")
|
|
216
|
-
pushed_at: str | None = Field(
|
|
217
|
-
|
|
216
|
+
pushed_at: StrictInt | str | None = Field(
|
|
217
|
+
description="Last push timestamp (Unix epoch int, ISO8601 string, or null)",
|
|
218
218
|
)
|
|
219
219
|
homepage: str | None = Field(default=None, description="Homepage URL")
|
|
220
220
|
size: int = Field(default=0, description="Repository size in KB")
|
|
@@ -490,7 +490,7 @@ class GitHubCommitUser(GitHubModel):
|
|
|
490
490
|
"""Git user information (author/committer)."""
|
|
491
491
|
|
|
492
492
|
name: str = Field(description="Git user name")
|
|
493
|
-
email: str = Field(description="Git user email")
|
|
493
|
+
email: str | None = Field(description="Git user email")
|
|
494
494
|
username: str | None = Field(default=None, description="GitHub username if linked")
|
|
495
495
|
date: str | None = Field(default=None, description="ISO8601 timestamp")
|
|
496
496
|
|
|
@@ -906,20 +906,38 @@ class PullRequestUnassigned(PullRequestBase):
|
|
|
906
906
|
assignee: GitHubUser = Field(description="User who was unassigned")
|
|
907
907
|
|
|
908
908
|
|
|
909
|
-
class
|
|
909
|
+
class PullRequestReviewTargetBase(PullRequestBase):
|
|
910
|
+
"""Base payload for pull_request review target events."""
|
|
911
|
+
|
|
912
|
+
requested_reviewer: GitHubUser | None = Field(
|
|
913
|
+
default=None,
|
|
914
|
+
description="User requested for review (absent when a team is requested)",
|
|
915
|
+
)
|
|
916
|
+
requested_team: GitHubTeam | None = Field(
|
|
917
|
+
default=None,
|
|
918
|
+
description="Team requested for review (absent when a user is requested)",
|
|
919
|
+
)
|
|
920
|
+
|
|
921
|
+
@model_validator(mode="after")
|
|
922
|
+
def validate_review_target(self) -> Self:
|
|
923
|
+
"""Require exactly one review target field."""
|
|
924
|
+
if (self.requested_reviewer is None) == (self.requested_team is None):
|
|
925
|
+
raise ValueError(
|
|
926
|
+
"Exactly one of requested_reviewer or requested_team must be provided"
|
|
927
|
+
)
|
|
928
|
+
return self
|
|
929
|
+
|
|
930
|
+
|
|
931
|
+
class PullRequestReviewRequested(PullRequestReviewTargetBase):
|
|
910
932
|
"""Payload for github.pull_request.review_requested events."""
|
|
911
933
|
|
|
912
934
|
_dispatch_topic: ClassVar[str] = "github.pull_request.review_requested"
|
|
913
|
-
requested_reviewer: GitHubUser = Field(description="User requested for review")
|
|
914
935
|
|
|
915
936
|
|
|
916
|
-
class PullRequestReviewRequestRemoved(
|
|
937
|
+
class PullRequestReviewRequestRemoved(PullRequestReviewTargetBase):
|
|
917
938
|
"""Payload for github.pull_request.review_request_removed events."""
|
|
918
939
|
|
|
919
940
|
_dispatch_topic: ClassVar[str] = "github.pull_request.review_request_removed"
|
|
920
|
-
requested_reviewer: GitHubUser = Field(
|
|
921
|
-
description="User whose review request was removed"
|
|
922
|
-
)
|
|
923
941
|
|
|
924
942
|
|
|
925
943
|
class PullRequestReadyForReview(PullRequestBase):
|