llmir 0.0.1__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 ADDED
@@ -0,0 +1,17 @@
1
+ from .chunks import AIChunk, AIChunkText, AIChunkFile, AIChunkImageURL, AIChunkToolCall
2
+ from .roles import AIRoles
3
+ from .messages import AIMessage, AIMessageToolResponse
4
+ from .tools import Tool
5
+
6
+ __all__ = [
7
+ "AIChunk",
8
+ "AIChunkText",
9
+ "AIChunkFile",
10
+ "AIChunkImageURL",
11
+ "AIChunkToolCall",
12
+ "AIRoles",
13
+ "AIMessage",
14
+ "AIMessageToolResponse",
15
+
16
+ "Tool",
17
+ ]
@@ -0,0 +1,10 @@
1
+ from .openai import to_openai, OpenAIMessage, OpenAIMessageToolResponse, OpenAIContent, OpenAITextContent, OpenAIImageURLContent
2
+
3
+ __all__ = [
4
+ "to_openai",
5
+ "OpenAIMessage",
6
+ "OpenAIMessageToolResponse",
7
+ "OpenAIContent",
8
+ "OpenAITextContent",
9
+ "OpenAIImageURLContent",
10
+ ]
@@ -0,0 +1,89 @@
1
+ from typing import TypedDict, Literal, Union
2
+
3
+ from ..messages import AIMessage, AIMessageToolResponse
4
+ from ..chunks import AIChunk, AIChunkText, AIChunkImageURL, AIChunkFile
5
+ import base64
6
+
7
+
8
+ class OpenAITextContent(TypedDict):
9
+ type: Literal["text"]
10
+ text: str
11
+
12
+
13
+ class OpenAIImageURLContent(TypedDict):
14
+ type: Literal["image_url"]
15
+ image_url: dict[str, str]
16
+
17
+ OpenAIContent = Union[OpenAITextContent, OpenAIImageURLContent]
18
+
19
+
20
+ class OpenAIMessage(TypedDict):
21
+ role: str
22
+ content: list[OpenAIContent]
23
+
24
+ class OpenAIMessageToolResponse(OpenAIMessage):
25
+ tool_call_id: str
26
+ name: str
27
+
28
+
29
+ def to_openai(messages: list[AIMessage]) -> list[OpenAIMessage]:
30
+
31
+
32
+ result: list[OpenAIMessage] = []
33
+ for message in messages:
34
+ role = message.role.value
35
+ if isinstance(message, AIMessageToolResponse):
36
+ result.append(
37
+ OpenAIMessageToolResponse(
38
+ role=role,
39
+ tool_call_id=message.id,
40
+ name=message.name,
41
+ content=[
42
+ chunk_to_openai(chunk) for chunk in message.chunks
43
+ ]
44
+ )
45
+ )
46
+ else:
47
+ result.append(OpenAIMessage(
48
+ role= role,
49
+ content= [
50
+ chunk_to_openai(chunk) for chunk in message.chunks
51
+ ]
52
+ ))
53
+ return result
54
+
55
+
56
+ def chunk_to_openai(chunk: AIChunk) -> OpenAIContent:
57
+
58
+ match chunk:
59
+ case AIChunkText():
60
+ return OpenAITextContent(
61
+ type="text",
62
+ text=chunk.text,
63
+ )
64
+ case AIChunkImageURL():
65
+ return OpenAIImageURLContent(
66
+ type="image_url",
67
+ image_url={
68
+ "url": chunk.url,
69
+ }
70
+ )
71
+ case AIChunkFile():
72
+ if chunk.mimetype.startswith("image/"):
73
+ base64_data = base64.b64encode(chunk.bytes).decode('utf-8')
74
+ return OpenAIImageURLContent(
75
+ type= "image_url",
76
+ image_url= {
77
+ "url": f"data:{chunk.mimetype};base64,{base64_data}",
78
+ }
79
+ )
80
+ elif chunk.mimetype == ("text/plain"):
81
+ text = chunk.bytes.decode(encoding="utf-8")
82
+ return OpenAITextContent(
83
+ type="text",
84
+ text=text
85
+ )
86
+ else:
87
+ raise ValueError(f"Unsupported file type for OpenAI: {chunk.mimetype}")
88
+ case _:
89
+ raise ValueError(f"Unsupported chunk type: {type(chunk)}")
llmir/chunks.py ADDED
@@ -0,0 +1,26 @@
1
+ from typing import Union, Literal
2
+ from pydantic import BaseModel
3
+ from .rich_repr import RichReprMixin
4
+
5
+ class AIChunkText(RichReprMixin, BaseModel):
6
+ type: Literal["text"] = "text"
7
+ text: str
8
+
9
+ class AIChunkFile(RichReprMixin, BaseModel):
10
+ type: Literal["file"] = "file"
11
+ name: str
12
+ mimetype: str
13
+ bytes: bytes
14
+
15
+ class AIChunkImageURL(RichReprMixin, BaseModel):
16
+ type: Literal["image"] = "image"
17
+ url: str
18
+
19
+ class AIChunkToolCall(RichReprMixin, BaseModel):
20
+ type: Literal["tool_call"] = "tool_call"
21
+ id: str
22
+ name: str
23
+ arguments: dict[str, object]
24
+
25
+
26
+ AIChunk = Union[AIChunkText, AIChunkFile, AIChunkImageURL, AIChunkToolCall]
llmir/messages.py ADDED
@@ -0,0 +1,18 @@
1
+ from pydantic import BaseModel, Field
2
+
3
+ from .chunks import AIChunk
4
+ from .roles import AIRoles
5
+
6
+
7
+ class AIMessage(BaseModel):
8
+
9
+ role: AIRoles
10
+ chunks: list[AIChunk] = Field(default_factory=list[AIChunk])
11
+
12
+ class AIMessageToolResponse(AIMessage):
13
+
14
+ id: str
15
+ name: str
16
+ role: AIRoles = AIRoles.TOOL
17
+
18
+
llmir/py.typed ADDED
File without changes
llmir/rich_repr.py ADDED
@@ -0,0 +1,20 @@
1
+ from pydantic import BaseModel, Field
2
+
3
+ class RichReprMixin(BaseModel):
4
+
5
+ MAX_CHARS_PER_VALUE: int = Field(default=2000, exclude=True)
6
+
7
+ def __rich_repr__(self):
8
+
9
+ for name, field_info in self.__class__.model_fields.items():
10
+
11
+ if field_info.exclude:
12
+ continue
13
+
14
+ value = getattr(self, name)
15
+ length = len(str(value))
16
+
17
+ if length > self.MAX_CHARS_PER_VALUE:
18
+ yield name, f"<object of length: {len(str(value))}>"
19
+ else:
20
+ yield name, value
llmir/roles.py ADDED
@@ -0,0 +1,9 @@
1
+ from enum import StrEnum
2
+
3
+
4
+ class AIRoles(StrEnum):
5
+
6
+ USER = "user"
7
+ MODEL = "assistant"
8
+ SYSTEM = "system"
9
+ TOOL = "tool"
llmir/tools.py ADDED
@@ -0,0 +1,8 @@
1
+ from pydantic import BaseModel
2
+ from typing import Any
3
+
4
+ class Tool(BaseModel):
5
+ name: str
6
+ description: str
7
+ input_schema: dict[str, Any]
8
+
@@ -0,0 +1,7 @@
1
+ Metadata-Version: 2.4
2
+ Name: llmir
3
+ Version: 0.0.1
4
+ Summary: Core message and tool IR for LLM pipelines
5
+ Author: Mathis Siebert
6
+ Requires-Python: >=3.11
7
+ Requires-Dist: pydantic>=2.0
@@ -0,0 +1,13 @@
1
+ llmir/__init__.py,sha256=mxV4TWB8xrR8qa3y5gfQZn-YfKRQTYWsPVvyeIjz7js,381
2
+ llmir/chunks.py,sha256=lnN7-3kjYalM6YO0v4ZM2-SYDNZDFfrergj3KEzcv0o,658
3
+ llmir/messages.py,sha256=G_F_gLGvBqzPZbni0iaWAMYG3-cDPJCeLJL2-9ZcAqI,311
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=_DRbBWhTYUdSEsdCTyn-FraqCQ5Ke2XRnHotJHAWyGM,2644
10
+ llmir-0.0.1.dist-info/METADATA,sha256=Oh-jOxYnQTw17bXZWhkJ3T8fENnEhUIUPCG-UiT_EZg,177
11
+ llmir-0.0.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
12
+ llmir-0.0.1.dist-info/top_level.txt,sha256=fm538OsNUSYa_71IPztSSN2PBCvcbaD5PmUIzaO5hQs,6
13
+ llmir-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ llmir