codespy-ai 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 (68) hide show
  1. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/PKG-INFO +1 -1
  2. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/pyproject.toml +1 -1
  3. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/__init__.py +1 -1
  4. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/config.py +16 -25
  5. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/config_llm.py +40 -1
  6. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/LICENSE +0 -0
  7. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/README.md +0 -0
  8. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/agents/__init__.py +0 -0
  9. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/agents/cost_tracker.py +0 -0
  10. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/agents/dspy_config.py +0 -0
  11. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/agents/reviewer/__init__.py +0 -0
  12. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/agents/reviewer/models.py +0 -0
  13. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/agents/reviewer/modules/__init__.py +0 -0
  14. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/agents/reviewer/modules/code_and_doc_reviewer.py +0 -0
  15. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/agents/reviewer/modules/deduplicator.py +0 -0
  16. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/agents/reviewer/modules/helpers.py +0 -0
  17. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/agents/reviewer/modules/scope_identifier.py +0 -0
  18. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/agents/reviewer/modules/supply_chain_auditor.py +0 -0
  19. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/agents/reviewer/reporters/__init__.py +0 -0
  20. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/agents/reviewer/reporters/base.py +0 -0
  21. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/agents/reviewer/reporters/git.py +0 -0
  22. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/agents/reviewer/reporters/stdout.py +0 -0
  23. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/agents/reviewer/reviewer.py +0 -0
  24. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/cli.py +0 -0
  25. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/config_dspy.py +0 -0
  26. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/config_git.py +0 -0
  27. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/config_io.py +0 -0
  28. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/__init__.py +0 -0
  29. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/cyber/__init__.py +0 -0
  30. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/cyber/osv/__init__.py +0 -0
  31. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/cyber/osv/client.py +0 -0
  32. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/cyber/osv/models.py +0 -0
  33. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/cyber/osv/server.py +0 -0
  34. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/filesystem/__init__.py +0 -0
  35. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/filesystem/client.py +0 -0
  36. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/filesystem/models.py +0 -0
  37. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/filesystem/server.py +0 -0
  38. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/git/__init__.py +0 -0
  39. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/git/base.py +0 -0
  40. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/git/client.py +0 -0
  41. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/git/github_client.py +0 -0
  42. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/git/gitlab_client.py +0 -0
  43. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/git/models.py +0 -0
  44. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/git/server.py +0 -0
  45. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/mcp_utils.py +0 -0
  46. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/parsers/__init__.py +0 -0
  47. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/parsers/ripgrep/__init__.py +0 -0
  48. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/parsers/ripgrep/client.py +0 -0
  49. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/parsers/ripgrep/server.py +0 -0
  50. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/parsers/treesitter/__init__.py +0 -0
  51. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/parsers/treesitter/base_extractor.py +0 -0
  52. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/parsers/treesitter/extractors/__init__.py +0 -0
  53. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/parsers/treesitter/extractors/go.py +0 -0
  54. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/parsers/treesitter/extractors/java.py +0 -0
  55. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/parsers/treesitter/extractors/javascript.py +0 -0
  56. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/parsers/treesitter/extractors/kotlin.py +0 -0
  57. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/parsers/treesitter/extractors/objc.py +0 -0
  58. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/parsers/treesitter/extractors/python.py +0 -0
  59. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/parsers/treesitter/extractors/rust.py +0 -0
  60. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/parsers/treesitter/extractors/swift.py +0 -0
  61. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/parsers/treesitter/extractors/terraform.py +0 -0
  62. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/parsers/treesitter/models.py +0 -0
  63. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/parsers/treesitter/parser.py +0 -0
  64. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/parsers/treesitter/server.py +0 -0
  65. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/web/__init__.py +0 -0
  66. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/web/client.py +0 -0
  67. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/web/models.py +0 -0
  68. {codespy_ai-0.2.1 → codespy_ai-0.2.2}/src/codespy/tools/web/server.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codespy-ai
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: Code review agent powered by DSPy
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "codespy-ai"
3
- version = "0.2.1"
3
+ version = "0.2.2"
4
4
  description = "Code review agent powered by DSPy"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -1,3 +1,3 @@
1
1
  """codespy - Code review agent powered by DSPy."""
2
2
 
3
- __version__ = "0.2.1"
3
+ __version__ = "0.2.2"
@@ -330,32 +330,23 @@ class Settings(BaseSettings):
330
330
 
331
331
  @model_validator(mode="after")
332
332
  def sync_llm_settings(self) -> "Settings":
333
- """Sync LLM settings between nested and flat fields."""
334
- # Sync from nested to flat
335
- if self.llm.openai_api_key:
336
- self.openai_api_key = self.llm.openai_api_key
337
- if self.llm.anthropic_api_key:
338
- self.anthropic_api_key = self.llm.anthropic_api_key
339
- if self.llm.gemini_api_key:
340
- self.gemini_api_key = self.llm.gemini_api_key
341
- if self.llm.aws_region:
342
- self.aws_region = self.llm.aws_region
343
- if self.llm.aws_access_key_id:
344
- self.aws_access_key_id = self.llm.aws_access_key_id
345
- if self.llm.aws_secret_access_key:
346
- self.aws_secret_access_key = self.llm.aws_secret_access_key
347
-
348
- # Sync from flat to nested
349
- if self.openai_api_key and not self.llm.openai_api_key:
350
- self.llm.openai_api_key = self.openai_api_key
351
- if self.anthropic_api_key and not self.llm.anthropic_api_key:
352
- self.llm.anthropic_api_key = self.anthropic_api_key
353
- if self.gemini_api_key and not self.llm.gemini_api_key:
354
- self.llm.gemini_api_key = self.gemini_api_key
355
-
356
- # Sync prompt caching setting
357
- self.enable_prompt_caching = self.llm.enable_prompt_caching
333
+ """Sync LLM settings between nested and flat fields.
358
334
 
335
+ Delegates to LLMConfig.sync_from_flat which enforces:
336
+ env vars (flat fields from pydantic-settings) > YAML/nested > defaults.
337
+ """
338
+ merged = self.llm.sync_from_flat(
339
+ openai_api_key=self.openai_api_key,
340
+ anthropic_api_key=self.anthropic_api_key,
341
+ gemini_api_key=self.gemini_api_key,
342
+ aws_region=self.aws_region,
343
+ aws_access_key_id=self.aws_access_key_id,
344
+ aws_secret_access_key=self.aws_secret_access_key,
345
+ )
346
+ # Propagate merged values back to flat fields
347
+ for field, value in merged.items():
348
+ if value is not None:
349
+ setattr(self, field, value)
359
350
  return self
360
351
 
361
352
  @model_validator(mode="after")
@@ -268,4 +268,43 @@ class LLMConfig(BaseModel):
268
268
  azure_api_version: str | None = None
269
269
 
270
270
  # Enable provider-side prompt caching (Anthropic, OpenAI, Bedrock, etc.)
271
- enable_prompt_caching: bool = True
271
+ enable_prompt_caching: bool = True
272
+
273
+ def sync_from_flat(
274
+ self,
275
+ *,
276
+ openai_api_key: str | None = None,
277
+ anthropic_api_key: str | None = None,
278
+ gemini_api_key: str | None = None,
279
+ aws_region: str | None = None,
280
+ aws_access_key_id: str | None = None,
281
+ aws_secret_access_key: str | None = None,
282
+ ) -> dict[str, object]:
283
+ """Sync flat settings into this LLMConfig and return values to propagate back.
284
+
285
+ Priority: flat fields (from env vars via pydantic-settings) > nested defaults.
286
+ Returns dict of field values that should be set on the parent Settings.
287
+ """
288
+ # Step 1: Flat → nested (env vars win over nested defaults)
289
+ if openai_api_key:
290
+ self.openai_api_key = openai_api_key
291
+ if anthropic_api_key:
292
+ self.anthropic_api_key = anthropic_api_key
293
+ if gemini_api_key:
294
+ self.gemini_api_key = gemini_api_key
295
+ if aws_region:
296
+ self.aws_region = aws_region
297
+ if aws_access_key_id:
298
+ self.aws_access_key_id = aws_access_key_id
299
+ if aws_secret_access_key:
300
+ self.aws_secret_access_key = aws_secret_access_key
301
+
302
+ # Step 2: Return merged values (nested fills gaps where flat is not set)
303
+ return {
304
+ "openai_api_key": openai_api_key or self.openai_api_key,
305
+ "anthropic_api_key": anthropic_api_key or self.anthropic_api_key,
306
+ "gemini_api_key": gemini_api_key or self.gemini_api_key,
307
+ "aws_access_key_id": aws_access_key_id or self.aws_access_key_id,
308
+ "aws_secret_access_key": aws_secret_access_key or self.aws_secret_access_key,
309
+ "enable_prompt_caching": self.enable_prompt_caching,
310
+ }
File without changes
File without changes