thoughtflow 0.0.1__py3-none-any.whl → 0.0.3__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.
thoughtflow/message.py ADDED
@@ -0,0 +1,140 @@
1
+ """
2
+ Message schema for ThoughtFlow.
3
+
4
+ Messages are the universal currency across providers. ThoughtFlow keeps
5
+ messages provider-agnostic, minimal, and stable.
6
+
7
+ Typical structure:
8
+ msg_list = [
9
+ {"role": "system", "content": "You are a helpful assistant."},
10
+ {"role": "user", "content": "Hello!"},
11
+ ]
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from dataclasses import dataclass, field
17
+ from typing import Any, Literal, TypeAlias
18
+
19
+
20
+ # Type aliases for clarity
21
+ Role: TypeAlias = Literal["system", "user", "assistant", "tool"]
22
+ MessageDict: TypeAlias = dict[str, Any]
23
+ MessageList: TypeAlias = list[MessageDict]
24
+
25
+
26
+ @dataclass
27
+ class Message:
28
+ """A single message in a conversation.
29
+
30
+ This is an optional structured representation. You can also use
31
+ plain dicts - ThoughtFlow accepts both.
32
+
33
+ Attributes:
34
+ role: The role of the message sender (system, user, assistant, tool).
35
+ content: The text content of the message.
36
+ name: Optional name for the sender (useful for multi-agent scenarios).
37
+ tool_call_id: Optional ID linking to a tool call (for tool responses).
38
+ metadata: Optional metadata dict for extensions.
39
+
40
+ Example:
41
+ >>> msg = Message(role="user", content="Hello!")
42
+ >>> msg.to_dict()
43
+ {'role': 'user', 'content': 'Hello!'}
44
+ """
45
+
46
+ role: Role
47
+ content: str
48
+ name: str | None = None
49
+ tool_call_id: str | None = None
50
+ metadata: dict[str, Any] = field(default_factory=dict)
51
+
52
+ def to_dict(self) -> MessageDict:
53
+ """Convert to a provider-compatible dict.
54
+
55
+ Returns:
56
+ Dict with role, content, and optional fields.
57
+ """
58
+ result: MessageDict = {
59
+ "role": self.role,
60
+ "content": self.content,
61
+ }
62
+ if self.name:
63
+ result["name"] = self.name
64
+ if self.tool_call_id:
65
+ result["tool_call_id"] = self.tool_call_id
66
+ return result
67
+
68
+ @classmethod
69
+ def from_dict(cls, data: MessageDict) -> Message:
70
+ """Create a Message from a dict.
71
+
72
+ Args:
73
+ data: Dict with at least 'role' and 'content' keys.
74
+
75
+ Returns:
76
+ A Message instance.
77
+ """
78
+ return cls(
79
+ role=data["role"],
80
+ content=data["content"],
81
+ name=data.get("name"),
82
+ tool_call_id=data.get("tool_call_id"),
83
+ metadata=data.get("metadata", {}),
84
+ )
85
+
86
+ @classmethod
87
+ def system(cls, content: str) -> Message:
88
+ """Create a system message.
89
+
90
+ Args:
91
+ content: The system prompt content.
92
+
93
+ Returns:
94
+ A Message with role='system'.
95
+ """
96
+ return cls(role="system", content=content)
97
+
98
+ @classmethod
99
+ def user(cls, content: str) -> Message:
100
+ """Create a user message.
101
+
102
+ Args:
103
+ content: The user's message content.
104
+
105
+ Returns:
106
+ A Message with role='user'.
107
+ """
108
+ return cls(role="user", content=content)
109
+
110
+ @classmethod
111
+ def assistant(cls, content: str) -> Message:
112
+ """Create an assistant message.
113
+
114
+ Args:
115
+ content: The assistant's response content.
116
+
117
+ Returns:
118
+ A Message with role='assistant'.
119
+ """
120
+ return cls(role="assistant", content=content)
121
+
122
+
123
+ def normalize_messages(messages: list[Message | MessageDict]) -> MessageList:
124
+ """Normalize a list of messages to dicts.
125
+
126
+ Accepts both Message objects and dicts, returning a uniform list of dicts.
127
+
128
+ Args:
129
+ messages: List of Message objects or dicts.
130
+
131
+ Returns:
132
+ List of message dicts.
133
+ """
134
+ result: MessageList = []
135
+ for msg in messages:
136
+ if isinstance(msg, Message):
137
+ result.append(msg.to_dict())
138
+ else:
139
+ result.append(msg)
140
+ return result
thoughtflow/py.typed ADDED
@@ -0,0 +1,2 @@
1
+ # PEP 561 marker file
2
+ # This file indicates that the package supports type checking