ai-dev-workflow 0.1.0__py3-none-any.whl
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.
- ado_mcp.py +49 -0
- ado_provider.py +245 -0
- ai_dev_workflow-0.1.0.dist-info/METADATA +348 -0
- ai_dev_workflow-0.1.0.dist-info/RECORD +20 -0
- ai_dev_workflow-0.1.0.dist-info/WHEEL +5 -0
- ai_dev_workflow-0.1.0.dist-info/entry_points.txt +2 -0
- ai_dev_workflow-0.1.0.dist-info/top_level.txt +15 -0
- ai_provider.py +149 -0
- ai_workflow_cli.py +761 -0
- composite_work_item.py +62 -0
- framework_update.py +145 -0
- github_work_item_provider.py +134 -0
- issue_publisher.py +243 -0
- planning_context.py +151 -0
- setup_context.py +99 -0
- setup_wizard.py +221 -0
- source_connection.py +21 -0
- work_item_provider.py +20 -0
- work_item_registry.py +25 -0
- worker_registry.py +170 -0
ai_provider.py
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"""Provider-neutral AI provider configuration and validation."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from urllib.parse import urlparse
|
|
5
|
+
|
|
6
|
+
PROVIDER_TYPES = {
|
|
7
|
+
"interactive",
|
|
8
|
+
"openai",
|
|
9
|
+
"chatgpt-codex",
|
|
10
|
+
"anthropic",
|
|
11
|
+
"litellm",
|
|
12
|
+
"openai-compatible",
|
|
13
|
+
"local-openai-compatible",
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
AUTH_TYPES = {"none", "chatgpt-oauth", "api-key-env", "bearer-env"}
|
|
17
|
+
|
|
18
|
+
DEFAULT_CAPABILITIES = {
|
|
19
|
+
"interactive": ["planning", "review"],
|
|
20
|
+
"openai": ["planning", "test", "implementation", "review"],
|
|
21
|
+
"chatgpt-codex": ["planning", "test", "implementation", "review"],
|
|
22
|
+
"anthropic": ["planning", "test", "implementation", "review"],
|
|
23
|
+
"litellm": ["planning", "test", "implementation", "review"],
|
|
24
|
+
"openai-compatible": ["planning", "test", "implementation", "review"],
|
|
25
|
+
"local-openai-compatible": ["planning", "test", "implementation", "review"],
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def provider_template(
|
|
30
|
+
provider_type: str,
|
|
31
|
+
*,
|
|
32
|
+
model: str | None = None,
|
|
33
|
+
base_url: str | None = None,
|
|
34
|
+
auth_type: str | None = None,
|
|
35
|
+
env: str | None = None,
|
|
36
|
+
capabilities: list[str] | None = None,
|
|
37
|
+
) -> dict:
|
|
38
|
+
if provider_type not in PROVIDER_TYPES:
|
|
39
|
+
raise ValueError(f"unsupported provider type: {provider_type}")
|
|
40
|
+
|
|
41
|
+
if auth_type is None:
|
|
42
|
+
auth_type = {
|
|
43
|
+
"interactive": "none",
|
|
44
|
+
"chatgpt-codex": "chatgpt-oauth",
|
|
45
|
+
"local-openai-compatible": "none",
|
|
46
|
+
"openai": "api-key-env",
|
|
47
|
+
"anthropic": "api-key-env",
|
|
48
|
+
"litellm": "api-key-env",
|
|
49
|
+
"openai-compatible": "api-key-env",
|
|
50
|
+
}[provider_type]
|
|
51
|
+
|
|
52
|
+
auth = {"type": auth_type}
|
|
53
|
+
if env:
|
|
54
|
+
auth["env"] = env
|
|
55
|
+
|
|
56
|
+
result = {
|
|
57
|
+
"type": provider_type,
|
|
58
|
+
"auth": auth,
|
|
59
|
+
"capabilities": capabilities or list(DEFAULT_CAPABILITIES[provider_type]),
|
|
60
|
+
}
|
|
61
|
+
if model:
|
|
62
|
+
result["model"] = model
|
|
63
|
+
if base_url:
|
|
64
|
+
result["base_url"] = base_url
|
|
65
|
+
return result
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _is_http_url(value: str) -> bool:
|
|
69
|
+
try:
|
|
70
|
+
parsed = urlparse(value)
|
|
71
|
+
return parsed.scheme in ("http", "https") and bool(parsed.netloc)
|
|
72
|
+
except Exception:
|
|
73
|
+
return False
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def validate_provider(provider_id: str, config: dict) -> list[str]:
|
|
77
|
+
errors = []
|
|
78
|
+
provider_type = config.get("type")
|
|
79
|
+
if provider_type not in PROVIDER_TYPES:
|
|
80
|
+
return [f"provider {provider_id}: unsupported type {provider_type!r}"]
|
|
81
|
+
|
|
82
|
+
auth = config.get("auth") or {}
|
|
83
|
+
auth_type = auth.get("type")
|
|
84
|
+
if auth_type not in AUTH_TYPES:
|
|
85
|
+
errors.append(f"provider {provider_id}: unsupported auth type {auth_type!r}")
|
|
86
|
+
if auth_type in ("api-key-env", "bearer-env") and not auth.get("env"):
|
|
87
|
+
errors.append(f"provider {provider_id}: auth env is required for {auth_type}")
|
|
88
|
+
|
|
89
|
+
if provider_type in ("litellm", "openai-compatible", "local-openai-compatible"):
|
|
90
|
+
base_url = config.get("base_url")
|
|
91
|
+
if not base_url or not _is_http_url(base_url):
|
|
92
|
+
errors.append(f"provider {provider_id}: valid base_url is required")
|
|
93
|
+
|
|
94
|
+
capabilities = config.get("capabilities")
|
|
95
|
+
if not isinstance(capabilities, list) or not capabilities:
|
|
96
|
+
errors.append(f"provider {provider_id}: at least one capability is required")
|
|
97
|
+
|
|
98
|
+
return errors
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def validate_provider_registry(providers: dict, agents: dict) -> list[str]:
|
|
102
|
+
errors = []
|
|
103
|
+
for provider_id, cfg in providers.items():
|
|
104
|
+
if not isinstance(cfg, dict):
|
|
105
|
+
errors.append(f"provider {provider_id}: config must be an object")
|
|
106
|
+
continue
|
|
107
|
+
errors.extend(validate_provider(provider_id, cfg))
|
|
108
|
+
|
|
109
|
+
for agent_key, agent in agents.items():
|
|
110
|
+
if not isinstance(agent, dict):
|
|
111
|
+
continue
|
|
112
|
+
provider_id = agent.get("provider")
|
|
113
|
+
if provider_id in (None, "none", "project-defined"):
|
|
114
|
+
continue
|
|
115
|
+
if provider_id not in providers:
|
|
116
|
+
errors.append(f"agent {agent_key}: unknown provider {provider_id}")
|
|
117
|
+
|
|
118
|
+
return errors
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def credential_requirements_for_providers(providers: dict) -> list[dict]:
|
|
122
|
+
result = []
|
|
123
|
+
seen = set()
|
|
124
|
+
for provider_id, cfg in providers.items():
|
|
125
|
+
auth = cfg.get("auth") or {}
|
|
126
|
+
auth_type = auth.get("type")
|
|
127
|
+
key = (provider_id, auth_type, auth.get("env"))
|
|
128
|
+
if key in seen:
|
|
129
|
+
continue
|
|
130
|
+
seen.add(key)
|
|
131
|
+
|
|
132
|
+
if auth_type == "none":
|
|
133
|
+
continue
|
|
134
|
+
if auth_type == "chatgpt-oauth":
|
|
135
|
+
result.append({
|
|
136
|
+
"name": f"{provider_id} ChatGPT sign-in",
|
|
137
|
+
"purpose": "Authenticate this provider using interactive ChatGPT OAuth.",
|
|
138
|
+
"required_for_setup": False,
|
|
139
|
+
"store": "provider/client auth store; never commit tokens",
|
|
140
|
+
})
|
|
141
|
+
elif auth_type in ("api-key-env", "bearer-env"):
|
|
142
|
+
env = auth.get("env")
|
|
143
|
+
result.append({
|
|
144
|
+
"name": env or f"{provider_id} credential",
|
|
145
|
+
"purpose": f"Authenticate AI provider '{provider_id}'.",
|
|
146
|
+
"required_for_setup": False,
|
|
147
|
+
"store": "environment/secret store; never commit",
|
|
148
|
+
})
|
|
149
|
+
return result
|