roadmodel 0.2.1__tar.gz → 0.2.2__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.
Files changed (32) hide show
  1. {roadmodel-0.2.1 → roadmodel-0.2.2}/PKG-INFO +1 -1
  2. {roadmodel-0.2.1 → roadmodel-0.2.2}/pyproject.toml +1 -1
  3. {roadmodel-0.2.1 → roadmodel-0.2.2}/src/roadmodel/__init__.py +1 -1
  4. {roadmodel-0.2.1 → roadmodel-0.2.2}/src/roadmodel/recommend.py +14 -2
  5. {roadmodel-0.2.1 → roadmodel-0.2.2}/.gitignore +0 -0
  6. {roadmodel-0.2.1 → roadmodel-0.2.2}/LICENSE +0 -0
  7. {roadmodel-0.2.1 → roadmodel-0.2.2}/NOTICE +0 -0
  8. {roadmodel-0.2.1 → roadmodel-0.2.2}/README.md +0 -0
  9. {roadmodel-0.2.1 → roadmodel-0.2.2}/docs/catalog.json +0 -0
  10. {roadmodel-0.2.1 → roadmodel-0.2.2}/docs/model-selector.txt +0 -0
  11. {roadmodel-0.2.1 → roadmodel-0.2.2}/docs/model-tier-cost-scale.md +0 -0
  12. {roadmodel-0.2.1 → roadmodel-0.2.2}/docs/templates/phase-roadmap-template.md +0 -0
  13. {roadmodel-0.2.1 → roadmodel-0.2.2}/docs/user-context.example.md +0 -0
  14. {roadmodel-0.2.1 → roadmodel-0.2.2}/hatch_build.py +0 -0
  15. {roadmodel-0.2.1 → roadmodel-0.2.2}/infra/README.md +0 -0
  16. {roadmodel-0.2.1 → roadmodel-0.2.2}/infra/supabase/README.md +0 -0
  17. {roadmodel-0.2.1 → roadmodel-0.2.2}/roadmodel/data/catalog.json +0 -0
  18. {roadmodel-0.2.1 → roadmodel-0.2.2}/roadmodel/data/model-selector.txt +0 -0
  19. {roadmodel-0.2.1 → roadmodel-0.2.2}/roadmodel/data/model-tier-cost-scale.md +0 -0
  20. {roadmodel-0.2.1 → roadmodel-0.2.2}/roadmodel/data/phase-roadmap-template.md +0 -0
  21. {roadmodel-0.2.1 → roadmodel-0.2.2}/roadmodel/data/user-context.example.md +0 -0
  22. {roadmodel-0.2.1 → roadmodel-0.2.2}/src/roadmodel/__main__.py +0 -0
  23. {roadmodel-0.2.1 → roadmodel-0.2.2}/src/roadmodel/cli.py +0 -0
  24. {roadmodel-0.2.1 → roadmodel-0.2.2}/src/roadmodel/config.py +0 -0
  25. {roadmodel-0.2.1 → roadmodel-0.2.2}/src/roadmodel/cost.py +0 -0
  26. {roadmodel-0.2.1 → roadmodel-0.2.2}/src/roadmodel/errors.py +0 -0
  27. {roadmodel-0.2.1 → roadmodel-0.2.2}/src/roadmodel/mcp_server.py +0 -0
  28. {roadmodel-0.2.1 → roadmodel-0.2.2}/src/roadmodel/providers/__init__.py +0 -0
  29. {roadmodel-0.2.1 → roadmodel-0.2.2}/src/roadmodel/providers/anthropic.py +0 -0
  30. {roadmodel-0.2.1 → roadmodel-0.2.2}/src/roadmodel/providers/google.py +0 -0
  31. {roadmodel-0.2.1 → roadmodel-0.2.2}/src/roadmodel/providers/openai.py +0 -0
  32. {roadmodel-0.2.1 → roadmodel-0.2.2}/src/roadmodel/user_context.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: roadmodel
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: BYO-key CLI that recommends the right AI model, platform, and settings for a prompt.
5
5
  Project-URL: Homepage, https://roadmodel.ai
6
6
  Project-URL: Repository, https://github.com/nathanramoscfa/roadmodel
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "roadmodel"
7
- version = "0.2.1"
7
+ version = "0.2.2"
8
8
  description = "BYO-key CLI that recommends the right AI model, platform, and settings for a prompt."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -1,2 +1,2 @@
1
1
  # src/roadmodel/__init__.py
2
- __version__ = "0.2.1"
2
+ __version__ = "0.2.2"
@@ -24,12 +24,19 @@ BUNDLED_USER_CONTEXT_TEMPLATE_PATH: Traversable = (
24
24
 
25
25
  _REQUIRED_KEYS: Final = ("model", "platform", "max_mode", "thinking", "conversation", "rationale")
26
26
 
27
+ # ORCHESTRATION is optional in the response block: the bundled selector
28
+ # emits it on Claude Code surfaces (Ultracode), and not at all elsewhere.
29
+ # Pre-orchestration responses (and any provider that omits the line) must
30
+ # still parse, so the line is wrapped in a non-capturing optional group.
31
+ # The captured value is intentionally not propagated into the parsed dict
32
+ # yet — surfacing it via recommend_structured is a separate change.
27
33
  _RESPONSE_BLOCK_RE: Final = re.compile(
28
34
  r"(?:^\s*PROMPT:\s*[^\n]*\n\s*)*"
29
35
  r"MODEL:\s*(?P<model>[^\n]+)\s*\n"
30
36
  r"PLATFORM:\s*(?P<platform>[^\n]+)\s*\n"
31
37
  r"MAX\s+MODE:\s*(?P<max_mode>[^\n]+)\s*\n"
32
38
  r"THINKING:\s*(?P<thinking>[^\n]+)\s*\n"
39
+ r"(?:ORCHESTRATION:\s*(?P<orchestration>[^\n]+)\s*\n)?"
33
40
  r"CONVERSATION:\s*(?P<conversation>[^\n]+)\s*\n"
34
41
  r"RATIONALE:\s*(?P<rationale>.+?)(?=\n\s*(?:PROMPT:|MODEL:)|\Z)",
35
42
  flags=re.IGNORECASE | re.MULTILINE | re.DOTALL,
@@ -100,9 +107,14 @@ def parse_response(text: str) -> dict[str, str]:
100
107
 
101
108
  regex_match = _RESPONSE_BLOCK_RE.search(text)
102
109
  if regex_match:
103
- parsed_block = {key: value.strip() for key, value in regex_match.groupdict().items()}
110
+ # The ORCHESTRATION group is optional and captures None when absent;
111
+ # coerce None → "" so .strip() doesn't crash. orchestration is
112
+ # consumed silently — not yet surfaced via the returned dict.
113
+ parsed_block = {
114
+ key: (value.strip() if value else "") for key, value in regex_match.groupdict().items()
115
+ }
104
116
  if all(parsed_block.get(key) for key in _REQUIRED_KEYS):
105
- return parsed_block
117
+ return {key: parsed_block[key] for key in _REQUIRED_KEYS}
106
118
 
107
119
  raise MalformedResponseError(text)
108
120
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes