llm-codegen-research 2.16__tar.gz → 2.17__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 (48) hide show
  1. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/PKG-INFO +2 -1
  2. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/pyproject.toml +1 -0
  3. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/__init__.py +4 -0
  4. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/llm/__init__.py +4 -0
  5. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/llm/clients/__init__.py +11 -1
  6. llm_codegen_research-2.17/src/llm_cgr/llm/clients/google.py +106 -0
  7. llm_codegen_research-2.17/src/llm_cgr/llm/clients/qwen.py +90 -0
  8. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_codegen_research.egg-info/PKG-INFO +2 -1
  9. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_codegen_research.egg-info/SOURCES.txt +2 -0
  10. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_codegen_research.egg-info/requires.txt +1 -0
  11. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/LICENSE +0 -0
  12. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/README.md +0 -0
  13. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/setup.cfg +0 -0
  14. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/analyse/__init__.py +0 -0
  15. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/analyse/classes.py +0 -0
  16. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/analyse/languages/__init__.py +0 -0
  17. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/analyse/languages/code_data.py +0 -0
  18. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/analyse/languages/javascript.py +0 -0
  19. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/analyse/languages/python.py +0 -0
  20. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/analyse/languages/rust.py +0 -0
  21. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/analyse/regexes.py +0 -0
  22. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/decorators.py +0 -0
  23. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/defaults.py +0 -0
  24. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/enums.py +0 -0
  25. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/json_utils.py +0 -0
  26. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/llm/clients/anthropic.py +0 -0
  27. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/llm/clients/base.py +0 -0
  28. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/llm/clients/deepseek.py +0 -0
  29. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/llm/clients/mistral.py +0 -0
  30. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/llm/clients/nscale.py +0 -0
  31. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/llm/clients/openai.py +0 -0
  32. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/llm/clients/openai_tool.py +0 -0
  33. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/llm/clients/protocol.py +0 -0
  34. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/llm/clients/together.py +0 -0
  35. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/llm/generate.py +0 -0
  36. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/llm/prompts.py +0 -0
  37. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/py.typed +0 -0
  38. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/scripts/test_cuda.py +0 -0
  39. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_cgr/timeout.py +0 -0
  40. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_codegen_research.egg-info/dependency_links.txt +0 -0
  41. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_codegen_research.egg-info/entry_points.txt +0 -0
  42. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/src/llm_codegen_research.egg-info/top_level.txt +0 -0
  43. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/tests/test_enums.py +0 -0
  44. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/tests/test_json_utils.py +0 -0
  45. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/tests/test_llm_api.py +0 -0
  46. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/tests/test_llm_local.py +0 -0
  47. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/tests/test_llm_tool.py +0 -0
  48. {llm_codegen_research-2.16 → llm_codegen_research-2.17}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: llm-codegen-research
3
- Version: 2.16
3
+ Version: 2.17
4
4
  Summary: Useful classes and methods for researching code-generation by LLMs.
5
5
  Author-email: Lukas Twist <itsluketwist@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/itsluketwist/llm-codegen-research
@@ -13,6 +13,7 @@ License-File: LICENSE
13
13
  Requires-Dist: esprima
14
14
  Provides-Extra: api
15
15
  Requires-Dist: anthropic; extra == "api"
16
+ Requires-Dist: google-genai; extra == "api"
16
17
  Requires-Dist: mistralai; extra == "api"
17
18
  Requires-Dist: openai; extra == "api"
18
19
  Requires-Dist: together; extra == "api"
@@ -28,6 +28,7 @@ dependencies = [
28
28
  [project.optional-dependencies]
29
29
  api = [
30
30
  "anthropic",
31
+ "google-genai",
31
32
  "mistralai",
32
33
  "openai",
33
34
  "together",
@@ -43,9 +43,11 @@ try:
43
43
  Base_LLM,
44
44
  DeepSeek_LLM,
45
45
  GenerationProtocol,
46
+ Google_LLM,
46
47
  Mistral_LLM,
47
48
  OpenAI_LLM,
48
49
  OpenAI_Tool_LLM,
50
+ Qwen_LLM,
49
51
  TogetherAI_LLM,
50
52
  Tool,
51
53
  generate,
@@ -64,9 +66,11 @@ try:
64
66
  "Base_LLM",
65
67
  "DeepSeek_LLM",
66
68
  "GenerationProtocol",
69
+ "Google_LLM",
67
70
  "Mistral_LLM",
68
71
  "OpenAI_LLM",
69
72
  "OpenAI_Tool_LLM",
73
+ "Qwen_LLM",
70
74
  "Tool",
71
75
  "TogetherAI_LLM",
72
76
  "generate",
@@ -3,9 +3,11 @@ from llm_cgr.llm.clients import (
3
3
  Base_LLM,
4
4
  DeepSeek_LLM,
5
5
  GenerationProtocol,
6
+ Google_LLM,
6
7
  Mistral_LLM,
7
8
  OpenAI_LLM,
8
9
  OpenAI_Tool_LLM,
10
+ Qwen_LLM,
9
11
  TogetherAI_LLM,
10
12
  Tool,
11
13
  get_llm,
@@ -24,9 +26,11 @@ __all__ = [
24
26
  "Base_LLM",
25
27
  "DeepSeek_LLM",
26
28
  "GenerationProtocol",
29
+ "Google_LLM",
27
30
  "Mistral_LLM",
28
31
  "OpenAI_LLM",
29
32
  "OpenAI_Tool_LLM",
33
+ "Qwen_LLM",
30
34
  "Tool",
31
35
  "TogetherAI_LLM",
32
36
  "get_llm",
@@ -3,6 +3,7 @@
3
3
  from llm_cgr.llm.clients.anthropic import Anthropic_LLM
4
4
  from llm_cgr.llm.clients.base import Base_LLM
5
5
  from llm_cgr.llm.clients.deepseek import DeepSeek_LLM
6
+ from llm_cgr.llm.clients.google import Google_LLM
6
7
  from llm_cgr.llm.clients.mistral import Mistral_LLM
7
8
  from llm_cgr.llm.clients.nscale import Nscale_LLM
8
9
  from llm_cgr.llm.clients.openai import OpenAI_LLM
@@ -13,14 +14,17 @@ from llm_cgr.llm.clients.openai_tool import (
13
14
  Tool,
14
15
  )
15
16
  from llm_cgr.llm.clients.protocol import GenerationProtocol
17
+ from llm_cgr.llm.clients.qwen import Qwen_LLM
16
18
  from llm_cgr.llm.clients.together import TogetherAI_LLM
17
19
 
18
20
 
19
21
  PROVIDER_MAP: dict[str, type[Base_LLM]] = {
20
22
  "anthropic": Anthropic_LLM,
21
23
  "deepseek": DeepSeek_LLM,
24
+ "google": Google_LLM,
22
25
  "mistral": Mistral_LLM,
23
26
  "openai": OpenAI_LLM,
27
+ "qwen": Qwen_LLM,
24
28
  "together": TogetherAI_LLM,
25
29
  "nscale": Nscale_LLM,
26
30
  }
@@ -43,7 +47,7 @@ def get_llm(
43
47
 
44
48
  If tools are provided, returns an OpenAI_Tool_LLM instance. Tool calls
45
49
  are currently only supported for OpenAI models. enable_reasoning is only
46
- supported by Anthropic, DeepSeek, Mistral, and TogetherAI models.
50
+ supported by Anthropic, DeepSeek, Google, Mistral, Qwen, and TogetherAI models.
47
51
  """
48
52
  llm_class: type[Base_LLM]
49
53
  if provider is not None:
@@ -56,6 +60,10 @@ def get_llm(
56
60
  llm_class = Mistral_LLM
57
61
  elif "deepseek" in model:
58
62
  llm_class = DeepSeek_LLM
63
+ elif "qwen" in model.lower():
64
+ llm_class = Qwen_LLM
65
+ elif "gemini" in model.lower():
66
+ llm_class = Google_LLM
59
67
  else:
60
68
  llm_class = TogetherAI_LLM
61
69
 
@@ -93,10 +101,12 @@ __all__ = [
93
101
  "Base_LLM",
94
102
  "DeepSeek_LLM",
95
103
  "GenerationProtocol",
104
+ "Google_LLM",
96
105
  "OpenAI_LLM",
97
106
  "OpenAI_Tool_LLM",
98
107
  "TogetherAI_LLM",
99
108
  "Mistral_LLM",
109
+ "Qwen_LLM",
100
110
  "Tool",
101
111
  "get_llm",
102
112
  ]
@@ -0,0 +1,106 @@
1
+ """Class to access LLMs via the Google Gemini API."""
2
+
3
+ import os
4
+ from typing import Any, cast
5
+
6
+ from google import genai
7
+ from google.genai import types
8
+
9
+ from llm_cgr.llm.clients.base import Base_LLM
10
+
11
+
12
+ class Google_LLM(Base_LLM):
13
+ """Class to access LLMs via the Google Gemini API."""
14
+
15
+ def __init__(
16
+ self,
17
+ model: str | None = None,
18
+ system: str | None = None,
19
+ temperature: float | None = None,
20
+ top_p: float | None = None,
21
+ max_tokens: int | None = None,
22
+ enable_reasoning: bool = False,
23
+ ) -> None:
24
+ """
25
+ Initialise the Google client.
26
+
27
+ Requires the GOOGLE_API_KEY environment variable to be set.
28
+ Set enable_reasoning=True to include the model's thinking summary on
29
+ supported models (e.g. gemini-2.5-pro); thinking output is hidden by
30
+ default.
31
+ """
32
+ super().__init__(
33
+ model=model,
34
+ system=system,
35
+ temperature=temperature,
36
+ top_p=top_p,
37
+ max_tokens=max_tokens,
38
+ enable_reasoning=enable_reasoning,
39
+ )
40
+ self._client = genai.Client(
41
+ api_key=os.environ["GOOGLE_API_KEY"],
42
+ )
43
+
44
+ def _build_message(
45
+ self,
46
+ role: str,
47
+ content: str,
48
+ ) -> dict[str, Any]:
49
+ """Build a Gemini model message."""
50
+ # gemini uses "model" rather than "assistant" for past responses
51
+ return {
52
+ "role": "model" if role == "assistant" else "user",
53
+ "parts": [{"text": content}],
54
+ }
55
+
56
+ def _build_input(
57
+ self,
58
+ user: str,
59
+ system: str | None = None,
60
+ ) -> list[dict[str, Any]]:
61
+ """Build the full Gemini model input."""
62
+ # the system prompt is passed separately as part of the request config
63
+ return [self._build_message(role="user", content=user)]
64
+
65
+ def _get_response(
66
+ self,
67
+ model: str,
68
+ input: list[dict[str, Any]],
69
+ system: str | None = None,
70
+ temperature: float | None = None,
71
+ top_p: float | None = None,
72
+ max_tokens: int | None = None,
73
+ ) -> tuple[str, str | None]:
74
+ """Generate a model response from the Google Gemini API."""
75
+ # built-in tools (google search, code execution, url context, etc.) are
76
+ # deliberately left unset, so they remain off by default
77
+ config = types.GenerateContentConfig(
78
+ system_instruction=system or self._system,
79
+ temperature=temperature,
80
+ top_p=top_p,
81
+ max_output_tokens=max_tokens,
82
+ thinking_config=(
83
+ types.ThinkingConfig(include_thoughts=True)
84
+ if self._enable_reasoning
85
+ else None
86
+ ),
87
+ )
88
+ response = self._client.models.generate_content(
89
+ model=model,
90
+ contents=cast(types.ContentListUnionDict, input),
91
+ config=config,
92
+ )
93
+ candidate = response.candidates[0] if response.candidates else None
94
+ content = candidate.content if candidate else None
95
+ parts = (content.parts if content else None) or []
96
+
97
+ # chain-of-thought from thinking-enabled models; None otherwise
98
+ reasoning_parts = [
99
+ part.text for part in parts if part.thought and part.text is not None
100
+ ]
101
+ reasoning = "\n".join(reasoning_parts) if reasoning_parts else None
102
+
103
+ text_parts = [
104
+ part.text for part in parts if not part.thought and part.text is not None
105
+ ]
106
+ return "\n".join(text_parts), reasoning
@@ -0,0 +1,90 @@
1
+ """Class to access LLMs via the Qwen API."""
2
+
3
+ import os
4
+ from typing import Any, cast
5
+
6
+ import openai
7
+ from openai.types.chat import ChatCompletionMessageParam
8
+
9
+ from llm_cgr.llm.clients.base import Base_LLM
10
+
11
+
12
+ class Qwen_LLM(Base_LLM):
13
+ """Class to access LLMs via the Qwen API, using the OpenAI interfaces."""
14
+
15
+ def __init__(
16
+ self,
17
+ model: str | None = None,
18
+ system: str | None = None,
19
+ temperature: float | None = None,
20
+ top_p: float | None = None,
21
+ max_tokens: int | None = None,
22
+ enable_reasoning: bool = False,
23
+ ) -> None:
24
+ """
25
+ Initialise the Qwen client.
26
+
27
+ Requires the QWEN_API_KEY environment variable to be set.
28
+ Set enable_reasoning=True to enable thinking mode on supported models
29
+ (e.g. qwen3-235b-a22b); thinking is off by default.
30
+ """
31
+ super().__init__(
32
+ model=model,
33
+ system=system,
34
+ temperature=temperature,
35
+ top_p=top_p,
36
+ max_tokens=max_tokens,
37
+ enable_reasoning=enable_reasoning,
38
+ )
39
+ self._client = openai.OpenAI(
40
+ api_key=os.environ["QWEN_API_KEY"],
41
+ base_url=os.environ["QWEN_API_URL"],
42
+ )
43
+
44
+ def _build_message(
45
+ self,
46
+ role: str,
47
+ content: str,
48
+ ) -> dict[str, str]:
49
+ """Build an OpenAI model message."""
50
+ return {"role": role, "content": content}
51
+
52
+ def _build_input(
53
+ self,
54
+ user: str,
55
+ system: str | None = None,
56
+ ) -> list[dict[str, Any]]:
57
+ """Build the full OpenAI model input."""
58
+ input = []
59
+ if system:
60
+ input.append(self._build_message(role="system", content=system))
61
+ input.append(self._build_message(role="user", content=user))
62
+ return input
63
+
64
+ def _get_response(
65
+ self,
66
+ model: str,
67
+ input: list[dict[str, Any]],
68
+ system: str | None = None,
69
+ temperature: float | None = None,
70
+ top_p: float | None = None,
71
+ max_tokens: int | None = None,
72
+ ) -> tuple[str, str | None]:
73
+ """Generate a model response from the Qwen API."""
74
+ response = self._client.chat.completions.create(
75
+ messages=cast(list[ChatCompletionMessageParam], input),
76
+ model=model,
77
+ temperature=temperature if temperature is not None else openai.omit,
78
+ top_p=top_p if top_p is not None else openai.omit,
79
+ max_completion_tokens=max_tokens if max_tokens is not None else openai.omit,
80
+ # thinking mode and other dashscope extras (e.g. web search) are left
81
+ # off unless reasoning is explicitly requested
82
+ extra_body={"enable_thinking": True} if self._enable_reasoning else None,
83
+ )
84
+ message = response.choices[0].message
85
+
86
+ # chain-of-thought from thinking-enabled models; None otherwise
87
+ reasoning = getattr(message, "reasoning_content", None)
88
+
89
+ # cast to str as text completions always return string content
90
+ return cast(str, message.content), reasoning
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: llm-codegen-research
3
- Version: 2.16
3
+ Version: 2.17
4
4
  Summary: Useful classes and methods for researching code-generation by LLMs.
5
5
  Author-email: Lukas Twist <itsluketwist@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/itsluketwist/llm-codegen-research
@@ -13,6 +13,7 @@ License-File: LICENSE
13
13
  Requires-Dist: esprima
14
14
  Provides-Extra: api
15
15
  Requires-Dist: anthropic; extra == "api"
16
+ Requires-Dist: google-genai; extra == "api"
16
17
  Requires-Dist: mistralai; extra == "api"
17
18
  Requires-Dist: openai; extra == "api"
18
19
  Requires-Dist: together; extra == "api"
@@ -23,11 +23,13 @@ src/llm_cgr/llm/clients/__init__.py
23
23
  src/llm_cgr/llm/clients/anthropic.py
24
24
  src/llm_cgr/llm/clients/base.py
25
25
  src/llm_cgr/llm/clients/deepseek.py
26
+ src/llm_cgr/llm/clients/google.py
26
27
  src/llm_cgr/llm/clients/mistral.py
27
28
  src/llm_cgr/llm/clients/nscale.py
28
29
  src/llm_cgr/llm/clients/openai.py
29
30
  src/llm_cgr/llm/clients/openai_tool.py
30
31
  src/llm_cgr/llm/clients/protocol.py
32
+ src/llm_cgr/llm/clients/qwen.py
31
33
  src/llm_cgr/llm/clients/together.py
32
34
  src/llm_cgr/scripts/test_cuda.py
33
35
  src/llm_codegen_research.egg-info/PKG-INFO
@@ -2,6 +2,7 @@ esprima
2
2
 
3
3
  [api]
4
4
  anthropic
5
+ google-genai
5
6
  mistralai
6
7
  openai
7
8
  together