@qa-gentic/stlc-agents 1.0.25 → 1.0.27

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.
Files changed (50) hide show
  1. package/package.json +1 -1
  2. package/skills/generate-test-cases/SKILL.md +5 -0
  3. package/src/cli/cmd-cost.js +61 -30
  4. package/src/cli/cmd-init.js +88 -8
  5. package/src/stlc_agents/__pycache__/__init__.cpython-314.pyc +0 -0
  6. package/src/stlc_agents/agent_gherkin_generator/__pycache__/__init__.cpython-314.pyc +0 -0
  7. package/src/stlc_agents/agent_gherkin_generator/__pycache__/server.cpython-314.pyc +0 -0
  8. package/src/stlc_agents/agent_gherkin_generator/tools/__pycache__/__init__.cpython-314.pyc +0 -0
  9. package/src/stlc_agents/agent_gherkin_generator/tools/__pycache__/ado_gherkin.cpython-314.pyc +0 -0
  10. package/src/stlc_agents/agent_helix_writer/__pycache__/__init__.cpython-314.pyc +0 -0
  11. package/src/stlc_agents/agent_helix_writer/__pycache__/server.cpython-314.pyc +0 -0
  12. package/src/stlc_agents/agent_helix_writer/server.py +41 -6
  13. package/src/stlc_agents/agent_helix_writer/tools/__pycache__/__init__.cpython-314.pyc +0 -0
  14. package/src/stlc_agents/agent_helix_writer/tools/__pycache__/boilerplate.cpython-314.pyc +0 -0
  15. package/src/stlc_agents/agent_helix_writer/tools/__pycache__/helix_write.cpython-314.pyc +0 -0
  16. package/src/stlc_agents/agent_playwright_generator/__pycache__/__init__.cpython-314.pyc +0 -0
  17. package/src/stlc_agents/agent_playwright_generator/__pycache__/server.cpython-314.pyc +0 -0
  18. package/src/stlc_agents/agent_playwright_generator/server.py +419 -213
  19. package/src/stlc_agents/agent_playwright_generator/tools/__pycache__/__init__.cpython-314.pyc +0 -0
  20. package/src/stlc_agents/agent_playwright_generator/tools/__pycache__/ado_attach.cpython-314.pyc +0 -0
  21. package/src/stlc_agents/agent_test_case_manager/__pycache__/__init__.cpython-314.pyc +0 -0
  22. package/src/stlc_agents/agent_test_case_manager/__pycache__/server.cpython-314.pyc +0 -0
  23. package/src/stlc_agents/agent_test_case_manager/server.py +12 -0
  24. package/src/stlc_agents/agent_test_case_manager/tools/__pycache__/__init__.cpython-314.pyc +0 -0
  25. package/src/stlc_agents/agent_test_case_manager/tools/__pycache__/ado_workitem.cpython-314.pyc +0 -0
  26. package/src/stlc_agents/agent_test_case_manager/tools/ado_workitem.py +65 -1
  27. package/src/stlc_agents/shared/__pycache__/__init__.cpython-314.pyc +0 -0
  28. package/src/stlc_agents/shared/__pycache__/auth.cpython-314.pyc +0 -0
  29. package/src/stlc_agents/shared/__pycache__/cost_tracker.cpython-314.pyc +0 -0
  30. package/src/stlc_agents/shared/__pycache__/pricing.cpython-314.pyc +0 -0
  31. package/src/stlc_agents/shared/cost_tracker.py +378 -70
  32. package/src/stlc_agents/shared/pricing.py +115 -24
  33. package/src/stlc_agents/webhook_orchestrator/__init__.py +0 -0
  34. package/src/stlc_agents/webhook_orchestrator/agent_runner.py +599 -0
  35. package/src/stlc_agents/webhook_orchestrator/main.py +43 -0
  36. package/src/stlc_agents/webhook_orchestrator/models.py +63 -0
  37. package/src/stlc_agents/webhook_orchestrator/orchestrator.py +103 -0
  38. package/src/stlc_agents/webhook_orchestrator/pipelines/__init__.py +0 -0
  39. package/src/stlc_agents/webhook_orchestrator/pipelines/_base.py +57 -0
  40. package/src/stlc_agents/webhook_orchestrator/pipelines/ado_test_cases.py +55 -0
  41. package/src/stlc_agents/webhook_orchestrator/pipelines/full_pipeline.py +202 -0
  42. package/src/stlc_agents/webhook_orchestrator/pipelines/gherkin_playwright.py +156 -0
  43. package/src/stlc_agents/webhook_orchestrator/pipelines/jira_test_cases.py +48 -0
  44. package/src/stlc_agents/webhook_orchestrator/webhook_bridge.py +368 -0
  45. package/src/stlc_agents/agent_gherkin_generator/__pycache__/server.cpython-310.pyc +0 -0
  46. package/src/stlc_agents/agent_helix_writer/__pycache__/server.cpython-310.pyc +0 -0
  47. package/src/stlc_agents/agent_jira_manager/__pycache__/server.cpython-310.pyc +0 -0
  48. package/src/stlc_agents/agent_test_case_manager/__pycache__/server.cpython-310.pyc +0 -0
  49. package/src/stlc_agents/shared/__pycache__/cost_tracker.cpython-310.pyc +0 -0
  50. 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
- Models this repo actually calls:
8
- - claude-sonnet-4-20250514 (LocatorHealer AI Vision, default)
9
- - gpt-4o (LocatorHealer AI Vision, copilot provider)
10
- + whatever coding agent the user runs (Claude / Copilot / Cursor / Windsurf)
11
- the user declares this via STLC_CODING_AGENT_MODEL env var.
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 / 1_000_000) * self.input_per_mtok
38
- + (output_tokens / 1_000_000) * self.output_per_mtok
39
- + (cache_write_tokens/ 1_000_000) * self.cache_write_per_mtok
40
- + (cache_read_tokens / 1_000_000) * self.cache_read_per_mtok
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
- ModelPricing("claude-sonnet-4-20250514", "Claude Sonnet 4", "anthropic", 3.00, 15.00, 3.75, 0.30),
47
- ModelPricing("claude-sonnet-4-6", "Claude Sonnet 4.6", "anthropic", 3.00, 15.00, 3.75, 0.30),
48
- ModelPricing("claude-haiku-4-5-20251001","Claude Haiku 4.5", "anthropic", 1.00, 5.00, 1.25, 0.10),
49
- ModelPricing("claude-opus-4-6", "Claude Opus 4.6", "anthropic", 5.00, 25.00, 6.25, 0.50),
50
- ModelPricing("claude-opus-4-7", "Claude Opus 4.7", "anthropic", 5.00, 25.00, 6.25, 0.50),
51
- # ── OpenAI / Copilot ──────────────────────────────────────────────────
52
- ModelPricing("gpt-4o", "GPT-4o", "openai", 2.50, 10.00, 0.00, 0.00),
53
- ModelPricing("gpt-4o-mini", "GPT-4o Mini", "openai", 0.15, 0.60, 0.00, 0.00),
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
- """Exact match first, then longest substring match."""
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
- # Substring: "claude-sonnet-4-20250514" ⊇ "sonnet-4"
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)