@qa-gentic/stlc-agents 1.0.25 → 1.0.26
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.
- package/package.json +1 -1
- package/skills/generate-test-cases/SKILL.md +5 -0
- package/src/cli/cmd-cost.js +61 -30
- package/src/cli/cmd-init.js +88 -8
- package/src/stlc_agents/__pycache__/__init__.cpython-314.pyc +0 -0
- package/src/stlc_agents/agent_gherkin_generator/__pycache__/__init__.cpython-314.pyc +0 -0
- package/src/stlc_agents/agent_gherkin_generator/__pycache__/server.cpython-314.pyc +0 -0
- package/src/stlc_agents/agent_gherkin_generator/tools/__pycache__/__init__.cpython-314.pyc +0 -0
- package/src/stlc_agents/agent_gherkin_generator/tools/__pycache__/ado_gherkin.cpython-314.pyc +0 -0
- package/src/stlc_agents/agent_helix_writer/__pycache__/__init__.cpython-314.pyc +0 -0
- package/src/stlc_agents/agent_helix_writer/__pycache__/server.cpython-314.pyc +0 -0
- package/src/stlc_agents/agent_helix_writer/server.py +41 -6
- package/src/stlc_agents/agent_helix_writer/tools/__pycache__/__init__.cpython-314.pyc +0 -0
- package/src/stlc_agents/agent_helix_writer/tools/__pycache__/boilerplate.cpython-314.pyc +0 -0
- package/src/stlc_agents/agent_helix_writer/tools/__pycache__/helix_write.cpython-314.pyc +0 -0
- package/src/stlc_agents/agent_playwright_generator/__pycache__/__init__.cpython-314.pyc +0 -0
- package/src/stlc_agents/agent_playwright_generator/__pycache__/server.cpython-314.pyc +0 -0
- package/src/stlc_agents/agent_playwright_generator/server.py +419 -213
- package/src/stlc_agents/agent_playwright_generator/tools/__pycache__/__init__.cpython-314.pyc +0 -0
- package/src/stlc_agents/agent_playwright_generator/tools/__pycache__/ado_attach.cpython-314.pyc +0 -0
- package/src/stlc_agents/agent_test_case_manager/__pycache__/__init__.cpython-314.pyc +0 -0
- package/src/stlc_agents/agent_test_case_manager/__pycache__/server.cpython-314.pyc +0 -0
- package/src/stlc_agents/agent_test_case_manager/server.py +12 -0
- package/src/stlc_agents/agent_test_case_manager/tools/__pycache__/__init__.cpython-314.pyc +0 -0
- package/src/stlc_agents/agent_test_case_manager/tools/__pycache__/ado_workitem.cpython-314.pyc +0 -0
- package/src/stlc_agents/agent_test_case_manager/tools/ado_workitem.py +65 -1
- package/src/stlc_agents/shared/__pycache__/__init__.cpython-314.pyc +0 -0
- package/src/stlc_agents/shared/__pycache__/auth.cpython-314.pyc +0 -0
- package/src/stlc_agents/shared/__pycache__/cost_tracker.cpython-314.pyc +0 -0
- package/src/stlc_agents/shared/__pycache__/pricing.cpython-314.pyc +0 -0
- package/src/stlc_agents/shared/cost_tracker.py +378 -70
- package/src/stlc_agents/shared/pricing.py +115 -24
- package/src/stlc_agents/webhook_orchestrator/__init__.py +0 -0
- package/src/stlc_agents/webhook_orchestrator/agent_runner.py +599 -0
- package/src/stlc_agents/webhook_orchestrator/main.py +43 -0
- package/src/stlc_agents/webhook_orchestrator/models.py +63 -0
- package/src/stlc_agents/webhook_orchestrator/orchestrator.py +103 -0
- package/src/stlc_agents/webhook_orchestrator/pipelines/__init__.py +0 -0
- package/src/stlc_agents/webhook_orchestrator/pipelines/_base.py +57 -0
- package/src/stlc_agents/webhook_orchestrator/pipelines/ado_test_cases.py +55 -0
- package/src/stlc_agents/webhook_orchestrator/pipelines/full_pipeline.py +202 -0
- package/src/stlc_agents/webhook_orchestrator/pipelines/gherkin_playwright.py +156 -0
- package/src/stlc_agents/webhook_orchestrator/pipelines/jira_test_cases.py +48 -0
- package/src/stlc_agents/webhook_orchestrator/webhook_bridge.py +368 -0
- package/src/stlc_agents/agent_gherkin_generator/__pycache__/server.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_helix_writer/__pycache__/server.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_jira_manager/__pycache__/server.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_test_case_manager/__pycache__/server.cpython-310.pyc +0 -0
- package/src/stlc_agents/shared/__pycache__/cost_tracker.cpython-310.pyc +0 -0
- package/src/stlc_agents/shared/__pycache__/pricing.cpython-310.pyc +0 -0
|
@@ -2,13 +2,28 @@
|
|
|
2
2
|
pricing.py — Model pricing registry for stlc-agents cost tracking.
|
|
3
3
|
|
|
4
4
|
Prices: USD per million tokens (MTok).
|
|
5
|
-
Source: Anthropic official docs, April 2026.
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
Sources (verified April 2026):
|
|
7
|
+
Anthropic — https://docs.anthropic.com/en/docs/about-claude/models/overview
|
|
8
|
+
cache_write = 5-min TTL rate; cache_read = 0.1× input rate
|
|
9
|
+
OpenAI — https://openai.com/api/pricing (standard tier)
|
|
10
|
+
columns: [model, input, cached_input, output]
|
|
11
|
+
no cache_write fee (caching is automatic)
|
|
12
|
+
xAI — https://docs.x.ai/docs/models
|
|
13
|
+
DeepSeek — https://api-docs.deepseek.com/quick_start/pricing
|
|
14
|
+
cache_read = cache-hit input rate (10× cheaper than cache miss)
|
|
15
|
+
|
|
16
|
+
Column layout for ModelPricing:
|
|
17
|
+
input_per_mtok — uncached input tokens (full rate)
|
|
18
|
+
output_per_mtok — output / completion tokens
|
|
19
|
+
cache_write_per_mtok — Anthropic only: tokens written into the prompt cache
|
|
20
|
+
cache_read_per_mtok — tokens served from cache (cheaper rate)
|
|
21
|
+
|
|
22
|
+
For OpenAI the API returns prompt_tokens (total) and
|
|
23
|
+
prompt_tokens_details.cached_tokens (the subset from cache).
|
|
24
|
+
Split them before calling cost():
|
|
25
|
+
uncached = prompt_tokens - cached_tokens → input_tokens arg
|
|
26
|
+
cached = cached_tokens → cache_read_tokens arg
|
|
12
27
|
"""
|
|
13
28
|
|
|
14
29
|
from __future__ import annotations
|
|
@@ -21,9 +36,9 @@ class ModelPricing:
|
|
|
21
36
|
model_id: str
|
|
22
37
|
display_name: str
|
|
23
38
|
provider: str
|
|
24
|
-
input_per_mtok: float # USD / 1M input tokens
|
|
39
|
+
input_per_mtok: float # USD / 1M input tokens (uncached)
|
|
25
40
|
output_per_mtok: float # USD / 1M output tokens
|
|
26
|
-
cache_write_per_mtok: float # USD / 1M cache-write tokens
|
|
41
|
+
cache_write_per_mtok: float # USD / 1M cache-write tokens (Anthropic only)
|
|
27
42
|
cache_read_per_mtok: float # USD / 1M cache-read tokens
|
|
28
43
|
|
|
29
44
|
def cost(
|
|
@@ -34,39 +49,115 @@ class ModelPricing:
|
|
|
34
49
|
cache_read_tokens: int = 0,
|
|
35
50
|
) -> float:
|
|
36
51
|
return (
|
|
37
|
-
(input_tokens
|
|
38
|
-
+ (output_tokens
|
|
39
|
-
+ (cache_write_tokens/ 1_000_000) * self.cache_write_per_mtok
|
|
40
|
-
+ (cache_read_tokens
|
|
52
|
+
(input_tokens / 1_000_000) * self.input_per_mtok
|
|
53
|
+
+ (output_tokens / 1_000_000) * self.output_per_mtok
|
|
54
|
+
+ (cache_write_tokens / 1_000_000) * self.cache_write_per_mtok
|
|
55
|
+
+ (cache_read_tokens / 1_000_000) * self.cache_read_per_mtok
|
|
41
56
|
)
|
|
42
57
|
|
|
43
58
|
|
|
44
59
|
_REGISTRY: list[ModelPricing] = [
|
|
45
|
-
# ── Anthropic
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
ModelPricing("claude-
|
|
49
|
-
ModelPricing("claude-
|
|
50
|
-
ModelPricing("claude-
|
|
51
|
-
|
|
52
|
-
ModelPricing("
|
|
53
|
-
|
|
60
|
+
# ── Anthropic ─────────────────────────────────────────────────────────────
|
|
61
|
+
# Source: https://docs.anthropic.com/en/docs/about-claude/models/overview
|
|
62
|
+
# input / output / cache_write(5min) / cache_read
|
|
63
|
+
ModelPricing("claude-sonnet-4-20250514", "Claude Sonnet 4", "anthropic", 3.00, 15.00, 3.75, 0.30),
|
|
64
|
+
ModelPricing("claude-sonnet-4-6", "Claude Sonnet 4.6", "anthropic", 3.00, 15.00, 3.75, 0.30),
|
|
65
|
+
ModelPricing("claude-haiku-4-5-20251001","Claude Haiku 4.5", "anthropic", 1.00, 5.00, 1.25, 0.10),
|
|
66
|
+
ModelPricing("claude-opus-4-6", "Claude Opus 4.6", "anthropic", 5.00, 25.00, 6.25, 0.50),
|
|
67
|
+
ModelPricing("claude-opus-4-7", "Claude Opus 4.7", "anthropic", 5.00, 25.00, 6.25, 0.50),
|
|
68
|
+
|
|
69
|
+
# ── OpenAI / Copilot ──────────────────────────────────────────────────────
|
|
70
|
+
# Source: https://openai.com/api/pricing (standard tier, April 2026)
|
|
71
|
+
# input / output / cache_write(n/a=0) / cache_read
|
|
72
|
+
# GPT-5.x flagship
|
|
73
|
+
ModelPricing("gpt-5.4", "GPT-5.4", "openai", 2.50, 15.00, 0.00, 0.250),
|
|
74
|
+
ModelPricing("gpt-5.4-mini", "GPT-5.4 Mini", "openai", 0.75, 4.50, 0.00, 0.075),
|
|
75
|
+
ModelPricing("gpt-5.4-nano", "GPT-5.4 Nano", "openai", 0.20, 1.25, 0.00, 0.020),
|
|
76
|
+
ModelPricing("gpt-5.2", "GPT-5.2", "openai", 1.75, 14.00, 0.00, 0.175),
|
|
77
|
+
ModelPricing("gpt-5.1", "GPT-5.1", "openai", 1.25, 10.00, 0.00, 0.125),
|
|
78
|
+
ModelPricing("gpt-5", "GPT-5", "openai", 1.25, 10.00, 0.00, 0.125),
|
|
79
|
+
ModelPricing("gpt-5-mini", "GPT-5 Mini", "openai", 0.25, 2.00, 0.00, 0.025),
|
|
80
|
+
ModelPricing("gpt-5-nano", "GPT-5 Nano", "openai", 0.05, 0.40, 0.00, 0.005),
|
|
81
|
+
# GPT-4.1 family
|
|
82
|
+
ModelPricing("gpt-4.1", "GPT-4.1", "openai", 2.00, 8.00, 0.00, 0.500),
|
|
83
|
+
ModelPricing("gpt-4.1-mini", "GPT-4.1 Mini", "openai", 0.40, 1.60, 0.00, 0.100),
|
|
84
|
+
ModelPricing("gpt-4.1-nano", "GPT-4.1 Nano", "openai", 0.10, 0.40, 0.00, 0.025),
|
|
85
|
+
# GPT-4o family
|
|
86
|
+
ModelPricing("gpt-4o", "GPT-4o", "openai", 2.50, 10.00, 0.00, 1.250),
|
|
87
|
+
ModelPricing("gpt-4o-mini", "GPT-4o Mini", "openai", 0.15, 0.60, 0.00, 0.075),
|
|
88
|
+
# o-series reasoning models
|
|
89
|
+
ModelPricing("o1", "o1", "openai", 15.00, 60.00, 0.00, 7.500),
|
|
90
|
+
ModelPricing("o1-mini", "o1 mini", "openai", 1.10, 4.40, 0.00, 0.550),
|
|
91
|
+
ModelPricing("o3", "o3", "openai", 2.00, 8.00, 0.00, 0.500),
|
|
92
|
+
ModelPricing("o3-mini", "o3 mini", "openai", 1.10, 4.40, 0.00, 0.550),
|
|
93
|
+
ModelPricing("o4-mini", "o4 mini", "openai", 1.10, 4.40, 0.00, 0.275),
|
|
94
|
+
|
|
95
|
+
# ── xAI ───────────────────────────────────────────────────────────────────
|
|
96
|
+
# Source: https://docs.x.ai/docs/models
|
|
97
|
+
ModelPricing("grok-4", "Grok 4", "xai", 2.00, 6.00, 0.00, 0.00),
|
|
98
|
+
ModelPricing("grok-4-fast", "Grok 4 Fast", "xai", 0.20, 0.50, 0.00, 0.00),
|
|
99
|
+
ModelPricing("grok-3", "Grok 3", "xai", 3.00, 15.00, 0.00, 0.00),
|
|
100
|
+
ModelPricing("grok-3-mini", "Grok 3 Mini", "xai", 0.30, 0.50, 0.00, 0.00),
|
|
101
|
+
|
|
102
|
+
# ── DeepSeek ──────────────────────────────────────────────────────────────
|
|
103
|
+
# Source: https://api-docs.deepseek.com/quick_start/pricing
|
|
104
|
+
# cache_read = cache-hit input rate ($0.028), cache_write not charged separately
|
|
105
|
+
ModelPricing("deepseek-chat", "DeepSeek V3", "deepseek", 0.28, 0.42, 0.00, 0.028),
|
|
106
|
+
ModelPricing("deepseek-reasoner", "DeepSeek R1", "deepseek", 0.28, 0.42, 0.00, 0.028),
|
|
107
|
+
ModelPricing("deepseek-r1", "DeepSeek R1 (alt)", "deepseek", 0.28, 0.42, 0.00, 0.028),
|
|
108
|
+
|
|
109
|
+
# ── Local / Ollama / LM Studio ────────────────────────────────────────────
|
|
110
|
+
ModelPricing("llama3.2", "Llama 3.2", "ollama", 0.00, 0.00, 0.00, 0.00),
|
|
111
|
+
ModelPricing("llama3.1", "Llama 3.1", "ollama", 0.00, 0.00, 0.00, 0.00),
|
|
112
|
+
ModelPricing("local-model", "Local Model", "lm-studio", 0.00, 0.00, 0.00, 0.00),
|
|
54
113
|
]
|
|
55
114
|
|
|
56
115
|
_by_id: dict[str, ModelPricing] = {p.model_id: p for p in _REGISTRY}
|
|
57
116
|
|
|
58
117
|
|
|
59
118
|
def get_pricing(model_id: str) -> Optional[ModelPricing]:
|
|
60
|
-
"""
|
|
119
|
+
"""
|
|
120
|
+
Exact match → substring match → family fallback.
|
|
121
|
+
|
|
122
|
+
The family fallback ensures unknown/future model names (e.g. gpt-6, claude-sonnet-5)
|
|
123
|
+
always return a pricing estimate rather than None, so cost never shows as $0.000000
|
|
124
|
+
simply because a new model name isn't in the registry yet.
|
|
125
|
+
"""
|
|
61
126
|
key = model_id.lower().strip()
|
|
62
127
|
if key in _by_id:
|
|
63
128
|
return _by_id[key]
|
|
64
|
-
|
|
129
|
+
|
|
130
|
+
# Substring: "claude-sonnet-4-20250514" ⊇ "sonnet-4", "gpt-5" ⊆ "gpt-5.4"
|
|
65
131
|
for p in _REGISTRY:
|
|
66
132
|
if key in p.model_id or p.model_id in key:
|
|
67
133
|
return p
|
|
134
|
+
|
|
135
|
+
# Family fallback — same-family estimate for unknown/future model versions
|
|
136
|
+
if "claude" in key:
|
|
137
|
+
return _by_id.get("claude-sonnet-4-6")
|
|
138
|
+
if "gpt-5" in key:
|
|
139
|
+
return _by_id.get("gpt-5")
|
|
140
|
+
if "gpt-4.1" in key:
|
|
141
|
+
return _by_id.get("gpt-4.1")
|
|
142
|
+
if any(k in key for k in ("gpt-4o", "gpt-4", "gpt")) or key in ("gpt",):
|
|
143
|
+
return _by_id.get("gpt-4o")
|
|
144
|
+
if key.startswith("o1") or "/o1" in key or key == "o1":
|
|
145
|
+
return _by_id.get("o1")
|
|
146
|
+
if key.startswith("o3") or "/o3" in key or key == "o3":
|
|
147
|
+
return _by_id.get("o3")
|
|
148
|
+
if key.startswith("o4") or "/o4" in key or key == "o4":
|
|
149
|
+
return _by_id.get("o4-mini")
|
|
150
|
+
if "grok-4" in key:
|
|
151
|
+
return _by_id.get("grok-4")
|
|
152
|
+
if "grok" in key:
|
|
153
|
+
return _by_id.get("grok-3")
|
|
154
|
+
if "deepseek" in key:
|
|
155
|
+
return _by_id.get("deepseek-chat")
|
|
156
|
+
if any(k in key for k in ("llama", "mistral", "qwen", "gemma", "phi")):
|
|
157
|
+
return _by_id.get("local-model")
|
|
158
|
+
|
|
68
159
|
return None
|
|
69
160
|
|
|
70
161
|
|
|
71
162
|
def list_models() -> list[ModelPricing]:
|
|
72
|
-
return list(_REGISTRY)
|
|
163
|
+
return list(_REGISTRY)
|
|
File without changes
|