llmir 0.0.4__py3-none-any.whl → 0.0.6__py3-none-any.whl

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.
llmir/__init__.py CHANGED
@@ -1,10 +1,10 @@
1
- from .chunks import AIChunk, AIChunkText, AIChunkFile, AIChunkImageURL, AIChunkToolCall
1
+ from .chunks import AIChunks, AIChunkText, AIChunkFile, AIChunkImageURL, AIChunkToolCall
2
2
  from .roles import AIRoles
3
3
  from .messages import AIMessages, AIMessage, AIMessageToolResponse
4
4
  from .tools import Tool
5
5
 
6
6
  __all__ = [
7
- "AIChunk",
7
+ "AIChunks",
8
8
  "AIChunkText",
9
9
  "AIChunkFile",
10
10
  "AIChunkImageURL",
llmir/adapter/__init__.py CHANGED
@@ -1,10 +1,13 @@
1
- from .openai import to_openai, OpenAIMessage, OpenAIMessageToolResponse, OpenAIContent, OpenAITextContent, OpenAIImageURLContent
1
+ from .openai import to_openai, OpenAIMessage, OpenAIMessageToolResponse, OpenAIContents, OpenAITextContent, OpenAIImageURLContent, OpenAIImageURLURL, OpenAIToolCallContent, OpenAIToolCallFunction
2
2
 
3
3
  __all__ = [
4
4
  "to_openai",
5
5
  "OpenAIMessage",
6
6
  "OpenAIMessageToolResponse",
7
- "OpenAIContent",
7
+ "OpenAIContents",
8
8
  "OpenAITextContent",
9
9
  "OpenAIImageURLContent",
10
+ "OpenAIImageURLURL",
11
+ "OpenAIToolCallContent",
12
+ "OpenAIToolCallFunction",
10
13
  ]
llmir/adapter/openai.py CHANGED
@@ -1,48 +1,86 @@
1
- from typing import TypedDict, Literal, Union
1
+ from typing import TypedDict, Literal
2
2
 
3
3
  from ..messages import AIMessages, AIMessageToolResponse
4
- from ..chunks import AIChunk, AIChunkText, AIChunkImageURL, AIChunkFile
4
+ from ..chunks import AIChunks, AIChunkText, AIChunkImageURL, AIChunkFile, AIChunkToolCall
5
5
  import base64
6
+ import json
6
7
 
7
8
 
8
9
  class OpenAITextContent(TypedDict):
9
10
  type: Literal["text"]
10
11
  text: str
11
12
 
13
+ class OpenAIImageURLURL(TypedDict):
14
+ url: str
12
15
 
13
16
  class OpenAIImageURLContent(TypedDict):
14
17
  type: Literal["image_url"]
15
- image_url: dict[str, str]
18
+ image_url: OpenAIImageURLURL
16
19
 
17
- OpenAIContent = Union[OpenAITextContent, OpenAIImageURLContent]
20
+
21
+ class OpenAIToolCallFunction(TypedDict):
22
+ name: str
23
+ arguments: str
24
+
25
+ class OpenAIToolCallContent(TypedDict):
26
+ id: str
27
+ type: Literal["function"]
28
+ function: OpenAIToolCallFunction
29
+
30
+
31
+
32
+ OpenAIContents = OpenAITextContent | OpenAIImageURLContent | OpenAIToolCallContent
18
33
 
19
34
 
20
35
  class OpenAIMessage(TypedDict):
21
36
  role: str
22
- content: list[OpenAIContent]
37
+ content: list[OpenAIContents]
23
38
 
24
- class OpenAIMessageToolResponse(OpenAIMessage):
39
+ class OpenAIMessageToolResponse(TypedDict):
40
+ role: Literal["tool"]
25
41
  tool_call_id: str
26
42
  name: str
43
+ content: str
27
44
 
28
45
 
29
- def to_openai(messages: list[AIMessages]) -> list[OpenAIMessage]:
46
+ OpenAIMessages = OpenAIMessage | OpenAIMessageToolResponse
47
+
48
+
49
+
50
+ def to_openai(messages: list[AIMessages]) -> list[OpenAIMessages]:
30
51
 
31
52
 
32
- result: list[OpenAIMessage] = []
53
+ result: list[OpenAIMessages] = []
33
54
  for message in messages:
34
55
  role = message.role.value
35
56
  if isinstance(message, AIMessageToolResponse):
57
+ assert(role == "tool")
58
+ text: str = ""
59
+ media_chunks: list[AIChunkFile | AIChunkImageURL] = []
60
+ for chunk in message.chunks:
61
+ if isinstance(chunk, AIChunkText):
62
+ text += chunk.text
63
+ elif isinstance(chunk, AIChunkImageURL) or isinstance(chunk, AIChunkFile):
64
+ media_chunks.append(chunk)
65
+ else:
66
+ raise Exception(f"Invalid chunk type for Tool Response: {chunk.type}")
36
67
  result.append(
37
68
  OpenAIMessageToolResponse(
38
69
  role=role,
39
70
  tool_call_id=message.id,
40
71
  name=message.name,
41
- content=[
42
- chunk_to_openai(chunk) for chunk in message.chunks
43
- ]
72
+ content=text,
44
73
  )
45
74
  )
75
+ if media_chunks:
76
+ result.append(
77
+ OpenAIMessage(
78
+ role="user", # Hacky, but what else to circumvent API limitations in a broadly compatible way?
79
+ content=[
80
+ chunk_to_openai(chunk) for chunk in media_chunks
81
+ ]
82
+ )
83
+ )
46
84
  else:
47
85
  result.append(OpenAIMessage(
48
86
  role= role,
@@ -53,7 +91,7 @@ def to_openai(messages: list[AIMessages]) -> list[OpenAIMessage]:
53
91
  return result
54
92
 
55
93
 
56
- def chunk_to_openai(chunk: AIChunk) -> OpenAIContent:
94
+ def chunk_to_openai(chunk: AIChunks) -> OpenAIContents:
57
95
 
58
96
  match chunk:
59
97
  case AIChunkText():
@@ -77,7 +115,7 @@ def chunk_to_openai(chunk: AIChunk) -> OpenAIContent:
77
115
  "url": f"data:{chunk.mimetype};base64,{base64_data}",
78
116
  }
79
117
  )
80
- elif chunk.mimetype == ("text/plain"):
118
+ elif chunk.mimetype == "text/plain":
81
119
  text = chunk.bytes.decode(encoding="utf-8")
82
120
  return OpenAITextContent(
83
121
  type="text",
@@ -85,5 +123,14 @@ def chunk_to_openai(chunk: AIChunk) -> OpenAIContent:
85
123
  )
86
124
  else:
87
125
  raise ValueError(f"Unsupported file type for OpenAI: {chunk.mimetype}")
126
+ case AIChunkToolCall():
127
+ return OpenAIToolCallContent(
128
+ id=chunk.id,
129
+ type="function",
130
+ function=OpenAIToolCallFunction(
131
+ name=chunk.name,
132
+ arguments=json.dumps(chunk.arguments)
133
+ )
134
+ )
88
135
  case _:
89
136
  raise ValueError(f"Unsupported chunk type: {type(chunk)}")
llmir/chunks.py CHANGED
@@ -23,4 +23,4 @@ class AIChunkToolCall(RichReprMixin, BaseModel):
23
23
  arguments: dict[str, object]
24
24
 
25
25
 
26
- AIChunk = Union[AIChunkText, AIChunkFile, AIChunkImageURL, AIChunkToolCall]
26
+ AIChunks = Union[AIChunkText, AIChunkFile, AIChunkImageURL, AIChunkToolCall]
llmir/messages.py CHANGED
@@ -1,17 +1,17 @@
1
1
  from pydantic import BaseModel, Field
2
2
  from typing import Literal
3
- from .chunks import AIChunk
3
+ from .chunks import AIChunks
4
4
  from .roles import AIRoles
5
5
 
6
6
  class AIMessage(BaseModel):
7
7
 
8
8
  role: Literal[AIRoles.USER, AIRoles.MODEL, AIRoles.SYSTEM]
9
- chunks: list[AIChunk] = Field(default_factory=list[AIChunk])
9
+ chunks: list[AIChunks] = Field(default_factory=list[AIChunks])
10
10
 
11
11
  class AIMessageToolResponse(BaseModel):
12
12
 
13
13
  role: Literal[AIRoles.TOOL] = AIRoles.TOOL
14
- chunks: list[AIChunk] = Field(default_factory=list[AIChunk])
14
+ chunks: list[AIChunks] = Field(default_factory=list[AIChunks])
15
15
  id: str
16
16
  name: str
17
17
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: llmir
3
- Version: 0.0.4
3
+ Version: 0.0.6
4
4
  Summary: Core message and tool IR for LLM pipelines
5
5
  Author: Mathis Siebert
6
6
  Requires-Python: >=3.11
@@ -0,0 +1,13 @@
1
+ llmir/__init__.py,sha256=jUDuJiDXZiCql3oa1OBa_4GJHpoGGU1VnEXkVTOF_uQ,413
2
+ llmir/chunks.py,sha256=0FaZzh3RgztLjac_1tubE2VBfZO98Qlcx4-WJ4dUd3M,659
3
+ llmir/messages.py,sha256=tEthCrSE5XUux5S1MMIm2i-_4zwQKbJ2KUYZ51UDN9c,510
4
+ llmir/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ llmir/rich_repr.py,sha256=ZGAfpcPkYJSUpFdir8B1MoORVFBSzVckCrRHVVkJIj4,559
6
+ llmir/roles.py,sha256=B9PmxTHAb8XoiA9en_J1yIP19woddzx4SRUz5XkUxFc,133
7
+ llmir/tools.py,sha256=fpkC3IafHqZJnwo7imtHdkTdGLBHQuR6DtdztXZrlWg,147
8
+ llmir/adapter/__init__.py,sha256=vAEFRB5TvlXbIapU-P61OhgVq7-HYmAIrabRY1EVpIA,441
9
+ llmir/adapter/openai.py,sha256=PdQzxDvFs3ivjy0NS_kWm-NAOKR75e_3VDHEnpDaZY4,4167
10
+ llmir-0.0.6.dist-info/METADATA,sha256=X-_VXw-UrIxgo-QUn4fX269gGaXN1Cre5kxHAq4iwbs,177
11
+ llmir-0.0.6.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
12
+ llmir-0.0.6.dist-info/top_level.txt,sha256=fm538OsNUSYa_71IPztSSN2PBCvcbaD5PmUIzaO5hQs,6
13
+ llmir-0.0.6.dist-info/RECORD,,
@@ -1,13 +0,0 @@
1
- llmir/__init__.py,sha256=CxdIqErvDMHNP7n7VO4PAsm-WzytCgYKyGEGHEd5B_s,411
2
- llmir/chunks.py,sha256=lnN7-3kjYalM6YO0v4ZM2-SYDNZDFfrergj3KEzcv0o,658
3
- llmir/messages.py,sha256=uABQ3xs_DJ0IWWoePl7M5YqAcpUWyT2vtokz_OuqkJQ,505
4
- llmir/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- llmir/rich_repr.py,sha256=ZGAfpcPkYJSUpFdir8B1MoORVFBSzVckCrRHVVkJIj4,559
6
- llmir/roles.py,sha256=B9PmxTHAb8XoiA9en_J1yIP19woddzx4SRUz5XkUxFc,133
7
- llmir/tools.py,sha256=fpkC3IafHqZJnwo7imtHdkTdGLBHQuR6DtdztXZrlWg,147
8
- llmir/adapter/__init__.py,sha256=2DKTM3v35_UPVTKiseo6rtIHj_P2OdUgxhNY_PKs5K8,289
9
- llmir/adapter/openai.py,sha256=IIuSi7qqSpn2Pp1_w9FapsuBzTv_mm02KT65ZDHb3b0,2646
10
- llmir-0.0.4.dist-info/METADATA,sha256=MzIDDljrYRNKU_PALFuKskEbT0TsXcl6SbdYsF5FHu8,177
11
- llmir-0.0.4.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
12
- llmir-0.0.4.dist-info/top_level.txt,sha256=fm538OsNUSYa_71IPztSSN2PBCvcbaD5PmUIzaO5hQs,6
13
- llmir-0.0.4.dist-info/RECORD,,
File without changes