HowdenLLM 1.6.2__tar.gz → 1.7.0__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.
@@ -35,6 +35,7 @@ class LLM:
35
35
  provider_and_model: str,
36
36
  template: Template,
37
37
  use_web_search_tool: bool,
38
+ upload_attachment: str|None,
38
39
  system: str = None,
39
40
  name: str = None
40
41
  ):
@@ -53,6 +54,7 @@ class LLM:
53
54
  self.system: str = system
54
55
  self.provider = ProviderFactory.create(self.provider_name)
55
56
  self.use_web_search_tool = use_web_search_tool
57
+ self.upload_attachment = upload_attachment
56
58
  self.hashed = self.compute_hash(self.input_params)
57
59
 
58
60
  self.total_input_tokens = 0
@@ -87,7 +89,7 @@ class LLM:
87
89
  input_tokens = self._count_tokens(input_text)
88
90
 
89
91
  # --- run model ---
90
- output = self.provider.complete(self.system, prompt, self.model, self.use_web_search_tool)
92
+ output = self.provider.complete(self.system, prompt, self.model, self.use_web_search_tool,self.upload_attachment)
91
93
 
92
94
  # --- count output tokens ---
93
95
  output_tokens = self._count_tokens(output)
@@ -3,5 +3,5 @@ from .provider_meta import ProviderMeta
3
3
 
4
4
  class BaseProvider(ABC, metaclass=ProviderMeta):
5
5
  @abstractmethod
6
- def complete(self, system: str, prompt: str, model: str, use_web_search_tool: bool) -> str:
6
+ def complete(self, system: str, prompt: str, model: str, use_web_search_tool: bool, upload_attachment: str|None) -> str:
7
7
  pass
@@ -0,0 +1,42 @@
1
+ from abc import ABC
2
+ from HowdenLLM.providers.base_provider import BaseProvider
3
+ from anthropic import Anthropic
4
+ from .known_providers import KnownProviders
5
+
6
+ class AnthropicProvider(BaseProvider, ABC):
7
+ provider = KnownProviders.Anthropic
8
+
9
+ def __init__(self,client: Anthropic):
10
+ self.client = client
11
+
12
+ def complete(self, system: str, prompt: str, model: str, use_web_search_tool: bool, upload_attachment: str) -> str:
13
+
14
+ if use_web_search_tool:
15
+ tools=[{"type": "web_search_20260209","name": "web_search","max_uses": 5}]
16
+ else:
17
+ tools = []
18
+
19
+ if model in ["claude-opus-4-6","claude-opus-4-5-20251101","claude-sonnet-4-6","claude-sonnet-4-5-20250929"]:
20
+ message = self.client.messages.create(
21
+ model=model,
22
+ system=system,
23
+ messages=[
24
+ {"role": "user","content": prompt}
25
+ ],
26
+ max_tokens=16000,
27
+ temperature=0.0,
28
+ tools=tools,
29
+ stream=False,
30
+ # thinking={"type": "adaptive"},
31
+ # output_config={"effort": "high"}, # or max, medium, low
32
+ )
33
+ else:
34
+ raise Exception(f"Unsupported model: {model}")
35
+
36
+ # print(f"Content: {message}")
37
+ clean_response = "\n".join(
38
+ block.text for block in message.content if block.type == "text"
39
+ )
40
+
41
+
42
+ return clean_response
@@ -1,4 +1,7 @@
1
1
  from abc import ABC
2
+
3
+ from sympy.codegen.ast import continue_
4
+
2
5
  from HowdenLLM.providers.base_provider import BaseProvider
3
6
  from openai import OpenAI
4
7
  from .known_providers import KnownProviders
@@ -9,7 +12,7 @@ class OpenAIProvider(BaseProvider, ABC):
9
12
  def __init__(self,client: OpenAI):
10
13
  self.client = client
11
14
 
12
- def complete(self, system: str, prompt: str, model: str, use_web_search_tool: bool) -> str:
15
+ def complete(self, system: str, prompt: str, model: str, use_web_search_tool: bool, upload_attachment: str|None) -> str:
13
16
 
14
17
  if use_web_search_tool:
15
18
  tools = [
@@ -18,13 +21,29 @@ class OpenAIProvider(BaseProvider, ABC):
18
21
  else:
19
22
  tools = None
20
23
 
24
+ if upload_attachment:
25
+ with open(upload_attachment, "rb") as f:
26
+ uploaded = self.client.files.create(
27
+ file=f,
28
+ purpose="user_data",
29
+ )
30
+ input=[
31
+ {"role": "system", "content": system},
32
+ {"role": "user", "content": [
33
+ {"type": "input_text", "text": prompt},
34
+ {"type": "input_file", "file_id": uploaded.id},
35
+ ]}
36
+ ]
37
+ else:
38
+ input=[
39
+ {"role": "system", "content": system},
40
+ {"role": "user", "content": prompt}
41
+ ]
42
+
21
43
  if model in ["gpt-5", "gpt-5.2", "gpt-5-mini", "gpt-5.4-mini", "gpt-5-nano"]:
22
44
  response = self.client.responses.create(
23
45
  model=model,
24
- input=[
25
- {"role": "system", "content": system},
26
- {"role": "user", "content": prompt}
27
- ],
46
+ input=input,
28
47
  tools=tools,
29
48
  max_output_tokens=16000
30
49
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: HowdenLLM
3
- Version: 1.6.2
3
+ Version: 1.7.0
4
4
  Summary: A simple configuration manager with Pydantic and JSON export.
5
5
  License: MIT
6
6
  Keywords: config,configuration,pydantic,json
@@ -14,7 +14,7 @@ build-backend = "poetry.core.masonry.api"
14
14
 
15
15
  [tool.poetry]
16
16
  name = "HowdenLLM"
17
- version = "1.6.2"
17
+ version = "1.7.0"
18
18
  description = "A simple configuration manager with Pydantic and JSON export."
19
19
  authors = [ "JesperThoftIllemannJ <jesper.jaeger@howdendanmark.dk>",]
20
20
  readme = "README.md"
@@ -1,27 +0,0 @@
1
- from abc import ABC
2
- from HowdenLLM.providers.base_provider import BaseProvider
3
- from anthropic import Anthropic
4
- from .known_providers import KnownProviders
5
-
6
- class AnthropicProvider(BaseProvider, ABC):
7
- provider = KnownProviders.Anthropic
8
-
9
- def __init__(self,client: Anthropic):
10
- self.client = client
11
-
12
- def complete(self, system: str, prompt: str, model: str, use_web_search_tool: bool) -> str:
13
- if model in ["claude-opus-4-6","claude-sonnet-4-6"]:
14
- message = self.client.messages.create(
15
- model=model,
16
- system=system,
17
- messages=[
18
- {"role": "user","content": prompt}
19
- ],
20
- max_tokens=16000,
21
- temperature=0.0
22
-
23
- )
24
- else:
25
- raise Exception(f"Unsupported model: {model}")
26
-
27
- return message.content[0].text
File without changes