agentrun-sdk 0.1.2__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.

Potentially problematic release.


This version of agentrun-sdk might be problematic. Click here for more details.

Files changed (115) hide show
  1. agentrun_operation_sdk/cli/__init__.py +1 -0
  2. agentrun_operation_sdk/cli/cli.py +19 -0
  3. agentrun_operation_sdk/cli/common.py +21 -0
  4. agentrun_operation_sdk/cli/runtime/__init__.py +1 -0
  5. agentrun_operation_sdk/cli/runtime/commands.py +203 -0
  6. agentrun_operation_sdk/client/client.py +75 -0
  7. agentrun_operation_sdk/operations/runtime/__init__.py +8 -0
  8. agentrun_operation_sdk/operations/runtime/configure.py +101 -0
  9. agentrun_operation_sdk/operations/runtime/launch.py +82 -0
  10. agentrun_operation_sdk/operations/runtime/models.py +31 -0
  11. agentrun_operation_sdk/services/runtime.py +152 -0
  12. agentrun_operation_sdk/utils/logging_config.py +72 -0
  13. agentrun_operation_sdk/utils/runtime/config.py +94 -0
  14. agentrun_operation_sdk/utils/runtime/container.py +280 -0
  15. agentrun_operation_sdk/utils/runtime/entrypoint.py +203 -0
  16. agentrun_operation_sdk/utils/runtime/schema.py +56 -0
  17. agentrun_sdk/__init__.py +7 -0
  18. agentrun_sdk/agent/__init__.py +25 -0
  19. agentrun_sdk/agent/agent.py +696 -0
  20. agentrun_sdk/agent/agent_result.py +46 -0
  21. agentrun_sdk/agent/conversation_manager/__init__.py +26 -0
  22. agentrun_sdk/agent/conversation_manager/conversation_manager.py +88 -0
  23. agentrun_sdk/agent/conversation_manager/null_conversation_manager.py +46 -0
  24. agentrun_sdk/agent/conversation_manager/sliding_window_conversation_manager.py +179 -0
  25. agentrun_sdk/agent/conversation_manager/summarizing_conversation_manager.py +252 -0
  26. agentrun_sdk/agent/state.py +97 -0
  27. agentrun_sdk/event_loop/__init__.py +9 -0
  28. agentrun_sdk/event_loop/event_loop.py +499 -0
  29. agentrun_sdk/event_loop/streaming.py +319 -0
  30. agentrun_sdk/experimental/__init__.py +4 -0
  31. agentrun_sdk/experimental/hooks/__init__.py +15 -0
  32. agentrun_sdk/experimental/hooks/events.py +123 -0
  33. agentrun_sdk/handlers/__init__.py +10 -0
  34. agentrun_sdk/handlers/callback_handler.py +70 -0
  35. agentrun_sdk/hooks/__init__.py +49 -0
  36. agentrun_sdk/hooks/events.py +80 -0
  37. agentrun_sdk/hooks/registry.py +247 -0
  38. agentrun_sdk/models/__init__.py +10 -0
  39. agentrun_sdk/models/anthropic.py +432 -0
  40. agentrun_sdk/models/bedrock.py +649 -0
  41. agentrun_sdk/models/litellm.py +225 -0
  42. agentrun_sdk/models/llamaapi.py +438 -0
  43. agentrun_sdk/models/mistral.py +539 -0
  44. agentrun_sdk/models/model.py +95 -0
  45. agentrun_sdk/models/ollama.py +357 -0
  46. agentrun_sdk/models/openai.py +436 -0
  47. agentrun_sdk/models/sagemaker.py +598 -0
  48. agentrun_sdk/models/writer.py +449 -0
  49. agentrun_sdk/multiagent/__init__.py +22 -0
  50. agentrun_sdk/multiagent/a2a/__init__.py +15 -0
  51. agentrun_sdk/multiagent/a2a/executor.py +148 -0
  52. agentrun_sdk/multiagent/a2a/server.py +252 -0
  53. agentrun_sdk/multiagent/base.py +92 -0
  54. agentrun_sdk/multiagent/graph.py +555 -0
  55. agentrun_sdk/multiagent/swarm.py +656 -0
  56. agentrun_sdk/py.typed +1 -0
  57. agentrun_sdk/session/__init__.py +18 -0
  58. agentrun_sdk/session/file_session_manager.py +216 -0
  59. agentrun_sdk/session/repository_session_manager.py +152 -0
  60. agentrun_sdk/session/s3_session_manager.py +272 -0
  61. agentrun_sdk/session/session_manager.py +73 -0
  62. agentrun_sdk/session/session_repository.py +51 -0
  63. agentrun_sdk/telemetry/__init__.py +21 -0
  64. agentrun_sdk/telemetry/config.py +194 -0
  65. agentrun_sdk/telemetry/metrics.py +476 -0
  66. agentrun_sdk/telemetry/metrics_constants.py +15 -0
  67. agentrun_sdk/telemetry/tracer.py +563 -0
  68. agentrun_sdk/tools/__init__.py +17 -0
  69. agentrun_sdk/tools/decorator.py +569 -0
  70. agentrun_sdk/tools/executor.py +137 -0
  71. agentrun_sdk/tools/loader.py +152 -0
  72. agentrun_sdk/tools/mcp/__init__.py +13 -0
  73. agentrun_sdk/tools/mcp/mcp_agent_tool.py +99 -0
  74. agentrun_sdk/tools/mcp/mcp_client.py +423 -0
  75. agentrun_sdk/tools/mcp/mcp_instrumentation.py +322 -0
  76. agentrun_sdk/tools/mcp/mcp_types.py +63 -0
  77. agentrun_sdk/tools/registry.py +607 -0
  78. agentrun_sdk/tools/structured_output.py +421 -0
  79. agentrun_sdk/tools/tools.py +217 -0
  80. agentrun_sdk/tools/watcher.py +136 -0
  81. agentrun_sdk/types/__init__.py +5 -0
  82. agentrun_sdk/types/collections.py +23 -0
  83. agentrun_sdk/types/content.py +188 -0
  84. agentrun_sdk/types/event_loop.py +48 -0
  85. agentrun_sdk/types/exceptions.py +81 -0
  86. agentrun_sdk/types/guardrails.py +254 -0
  87. agentrun_sdk/types/media.py +89 -0
  88. agentrun_sdk/types/session.py +152 -0
  89. agentrun_sdk/types/streaming.py +201 -0
  90. agentrun_sdk/types/tools.py +258 -0
  91. agentrun_sdk/types/traces.py +5 -0
  92. agentrun_sdk-0.1.2.dist-info/METADATA +51 -0
  93. agentrun_sdk-0.1.2.dist-info/RECORD +115 -0
  94. agentrun_sdk-0.1.2.dist-info/WHEEL +5 -0
  95. agentrun_sdk-0.1.2.dist-info/entry_points.txt +2 -0
  96. agentrun_sdk-0.1.2.dist-info/top_level.txt +3 -0
  97. agentrun_wrapper/__init__.py +11 -0
  98. agentrun_wrapper/_utils/__init__.py +6 -0
  99. agentrun_wrapper/_utils/endpoints.py +16 -0
  100. agentrun_wrapper/identity/__init__.py +5 -0
  101. agentrun_wrapper/identity/auth.py +211 -0
  102. agentrun_wrapper/memory/__init__.py +6 -0
  103. agentrun_wrapper/memory/client.py +1697 -0
  104. agentrun_wrapper/memory/constants.py +103 -0
  105. agentrun_wrapper/memory/controlplane.py +626 -0
  106. agentrun_wrapper/py.typed +1 -0
  107. agentrun_wrapper/runtime/__init__.py +13 -0
  108. agentrun_wrapper/runtime/app.py +473 -0
  109. agentrun_wrapper/runtime/context.py +34 -0
  110. agentrun_wrapper/runtime/models.py +25 -0
  111. agentrun_wrapper/services/__init__.py +1 -0
  112. agentrun_wrapper/services/identity.py +192 -0
  113. agentrun_wrapper/tools/__init__.py +6 -0
  114. agentrun_wrapper/tools/browser_client.py +325 -0
  115. agentrun_wrapper/tools/code_interpreter_client.py +186 -0
@@ -0,0 +1,357 @@
1
+ """Ollama model provider.
2
+
3
+ - Docs: https://ollama.com/
4
+ """
5
+
6
+ import json
7
+ import logging
8
+ from typing import Any, AsyncGenerator, Optional, Type, TypeVar, Union, cast
9
+
10
+ import ollama
11
+ from pydantic import BaseModel
12
+ from typing_extensions import TypedDict, Unpack, override
13
+
14
+ from ..types.content import ContentBlock, Messages
15
+ from ..types.streaming import StopReason, StreamEvent
16
+ from ..types.tools import ToolSpec
17
+ from .model import Model
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+ T = TypeVar("T", bound=BaseModel)
22
+
23
+
24
+ class OllamaModel(Model):
25
+ """Ollama model provider implementation.
26
+
27
+ The implementation handles Ollama-specific features such as:
28
+
29
+ - Local model invocation
30
+ - Streaming responses
31
+ - Tool/function calling
32
+ """
33
+
34
+ class OllamaConfig(TypedDict, total=False):
35
+ """Configuration parameters for Ollama models.
36
+
37
+ Attributes:
38
+ additional_args: Any additional arguments to include in the request.
39
+ keep_alive: Controls how long the model will stay loaded into memory following the request (default: "5m").
40
+ max_tokens: Maximum number of tokens to generate in the response.
41
+ model_id: Ollama model ID (e.g., "llama3", "mistral", "phi3").
42
+ options: Additional model parameters (e.g., top_k).
43
+ stop_sequences: List of sequences that will stop generation when encountered.
44
+ temperature: Controls randomness in generation (higher = more random).
45
+ top_p: Controls diversity via nucleus sampling (alternative to temperature).
46
+ """
47
+
48
+ additional_args: Optional[dict[str, Any]]
49
+ keep_alive: Optional[str]
50
+ max_tokens: Optional[int]
51
+ model_id: str
52
+ options: Optional[dict[str, Any]]
53
+ stop_sequences: Optional[list[str]]
54
+ temperature: Optional[float]
55
+ top_p: Optional[float]
56
+
57
+ def __init__(
58
+ self,
59
+ host: Optional[str],
60
+ *,
61
+ ollama_client_args: Optional[dict[str, Any]] = None,
62
+ **model_config: Unpack[OllamaConfig],
63
+ ) -> None:
64
+ """Initialize provider instance.
65
+
66
+ Args:
67
+ host: The address of the Ollama server hosting the model.
68
+ ollama_client_args: Additional arguments for the Ollama client.
69
+ **model_config: Configuration options for the Ollama model.
70
+ """
71
+ self.host = host
72
+ self.client_args = ollama_client_args or {}
73
+ self.config = OllamaModel.OllamaConfig(**model_config)
74
+
75
+ logger.debug("config=<%s> | initializing", self.config)
76
+
77
+ @override
78
+ def update_config(self, **model_config: Unpack[OllamaConfig]) -> None: # type: ignore
79
+ """Update the Ollama Model configuration with the provided arguments.
80
+
81
+ Args:
82
+ **model_config: Configuration overrides.
83
+ """
84
+ self.config.update(model_config)
85
+
86
+ @override
87
+ def get_config(self) -> OllamaConfig:
88
+ """Get the Ollama model configuration.
89
+
90
+ Returns:
91
+ The Ollama model configuration.
92
+ """
93
+ return self.config
94
+
95
+ def _format_request_message_contents(self, role: str, content: ContentBlock) -> list[dict[str, Any]]:
96
+ """Format Ollama compatible message contents.
97
+
98
+ Ollama doesn't support an array of contents, so we must flatten everything into separate message blocks.
99
+
100
+ Args:
101
+ role: E.g., user.
102
+ content: Content block to format.
103
+
104
+ Returns:
105
+ Ollama formatted message contents.
106
+
107
+ Raises:
108
+ TypeError: If the content block type cannot be converted to an Ollama-compatible format.
109
+ """
110
+ if "text" in content:
111
+ return [{"role": role, "content": content["text"]}]
112
+
113
+ if "image" in content:
114
+ return [{"role": role, "images": [content["image"]["source"]["bytes"]]}]
115
+
116
+ if "toolUse" in content:
117
+ return [
118
+ {
119
+ "role": role,
120
+ "tool_calls": [
121
+ {
122
+ "function": {
123
+ "name": content["toolUse"]["toolUseId"],
124
+ "arguments": content["toolUse"]["input"],
125
+ }
126
+ }
127
+ ],
128
+ }
129
+ ]
130
+
131
+ if "toolResult" in content:
132
+ return [
133
+ formatted_tool_result_content
134
+ for tool_result_content in content["toolResult"]["content"]
135
+ for formatted_tool_result_content in self._format_request_message_contents(
136
+ "tool",
137
+ (
138
+ {"text": json.dumps(tool_result_content["json"])}
139
+ if "json" in tool_result_content
140
+ else cast(ContentBlock, tool_result_content)
141
+ ),
142
+ )
143
+ ]
144
+
145
+ raise TypeError(f"content_type=<{next(iter(content))}> | unsupported type")
146
+
147
+ def _format_request_messages(self, messages: Messages, system_prompt: Optional[str] = None) -> list[dict[str, Any]]:
148
+ """Format an Ollama compatible messages array.
149
+
150
+ Args:
151
+ messages: List of message objects to be processed by the model.
152
+ system_prompt: System prompt to provide context to the model.
153
+
154
+ Returns:
155
+ An Ollama compatible messages array.
156
+ """
157
+ system_message = [{"role": "system", "content": system_prompt}] if system_prompt else []
158
+
159
+ return system_message + [
160
+ formatted_message
161
+ for message in messages
162
+ for content in message["content"]
163
+ for formatted_message in self._format_request_message_contents(message["role"], content)
164
+ ]
165
+
166
+ def format_request(
167
+ self, messages: Messages, tool_specs: Optional[list[ToolSpec]] = None, system_prompt: Optional[str] = None
168
+ ) -> dict[str, Any]:
169
+ """Format an Ollama chat streaming request.
170
+
171
+ Args:
172
+ messages: List of message objects to be processed by the model.
173
+ tool_specs: List of tool specifications to make available to the model.
174
+ system_prompt: System prompt to provide context to the model.
175
+
176
+ Returns:
177
+ An Ollama chat streaming request.
178
+
179
+ Raises:
180
+ TypeError: If a message contains a content block type that cannot be converted to an Ollama-compatible
181
+ format.
182
+ """
183
+ return {
184
+ "messages": self._format_request_messages(messages, system_prompt),
185
+ "model": self.config["model_id"],
186
+ "options": {
187
+ **(self.config.get("options") or {}),
188
+ **{
189
+ key: value
190
+ for key, value in [
191
+ ("num_predict", self.config.get("max_tokens")),
192
+ ("temperature", self.config.get("temperature")),
193
+ ("top_p", self.config.get("top_p")),
194
+ ("stop", self.config.get("stop_sequences")),
195
+ ]
196
+ if value is not None
197
+ },
198
+ },
199
+ "stream": True,
200
+ "tools": [
201
+ {
202
+ "type": "function",
203
+ "function": {
204
+ "name": tool_spec["name"],
205
+ "description": tool_spec["description"],
206
+ "parameters": tool_spec["inputSchema"]["json"],
207
+ },
208
+ }
209
+ for tool_spec in tool_specs or []
210
+ ],
211
+ **({"keep_alive": self.config["keep_alive"]} if self.config.get("keep_alive") else {}),
212
+ **(
213
+ self.config["additional_args"]
214
+ if "additional_args" in self.config and self.config["additional_args"] is not None
215
+ else {}
216
+ ),
217
+ }
218
+
219
+ def format_chunk(self, event: dict[str, Any]) -> StreamEvent:
220
+ """Format the Ollama response events into standardized message chunks.
221
+
222
+ Args:
223
+ event: A response event from the Ollama model.
224
+
225
+ Returns:
226
+ The formatted chunk.
227
+
228
+ Raises:
229
+ RuntimeError: If chunk_type is not recognized.
230
+ This error should never be encountered as we control chunk_type in the stream method.
231
+ """
232
+ match event["chunk_type"]:
233
+ case "message_start":
234
+ return {"messageStart": {"role": "assistant"}}
235
+
236
+ case "content_start":
237
+ if event["data_type"] == "text":
238
+ return {"contentBlockStart": {"start": {}}}
239
+
240
+ tool_name = event["data"].function.name
241
+ return {"contentBlockStart": {"start": {"toolUse": {"name": tool_name, "toolUseId": tool_name}}}}
242
+
243
+ case "content_delta":
244
+ if event["data_type"] == "text":
245
+ return {"contentBlockDelta": {"delta": {"text": event["data"]}}}
246
+
247
+ tool_arguments = event["data"].function.arguments
248
+ return {"contentBlockDelta": {"delta": {"toolUse": {"input": json.dumps(tool_arguments)}}}}
249
+
250
+ case "content_stop":
251
+ return {"contentBlockStop": {}}
252
+
253
+ case "message_stop":
254
+ reason: StopReason
255
+ if event["data"] == "tool_use":
256
+ reason = "tool_use"
257
+ elif event["data"] == "length":
258
+ reason = "max_tokens"
259
+ else:
260
+ reason = "end_turn"
261
+
262
+ return {"messageStop": {"stopReason": reason}}
263
+
264
+ case "metadata":
265
+ return {
266
+ "metadata": {
267
+ "usage": {
268
+ "inputTokens": event["data"].eval_count,
269
+ "outputTokens": event["data"].prompt_eval_count,
270
+ "totalTokens": event["data"].eval_count + event["data"].prompt_eval_count,
271
+ },
272
+ "metrics": {
273
+ "latencyMs": event["data"].total_duration / 1e6,
274
+ },
275
+ },
276
+ }
277
+
278
+ case _:
279
+ raise RuntimeError(f"chunk_type=<{event['chunk_type']} | unknown type")
280
+
281
+ @override
282
+ async def stream(
283
+ self,
284
+ messages: Messages,
285
+ tool_specs: Optional[list[ToolSpec]] = None,
286
+ system_prompt: Optional[str] = None,
287
+ **kwargs: Any,
288
+ ) -> AsyncGenerator[StreamEvent, None]:
289
+ """Stream conversation with the Ollama model.
290
+
291
+ Args:
292
+ messages: List of message objects to be processed by the model.
293
+ tool_specs: List of tool specifications to make available to the model.
294
+ system_prompt: System prompt to provide context to the model.
295
+ **kwargs: Additional keyword arguments for future extensibility.
296
+
297
+ Yields:
298
+ Formatted message chunks from the model.
299
+ """
300
+ logger.debug("formatting request")
301
+ request = self.format_request(messages, tool_specs, system_prompt)
302
+ logger.debug("request=<%s>", request)
303
+
304
+ logger.debug("invoking model")
305
+ tool_requested = False
306
+
307
+ client = ollama.AsyncClient(self.host, **self.client_args)
308
+ response = await client.chat(**request)
309
+
310
+ logger.debug("got response from model")
311
+ yield self.format_chunk({"chunk_type": "message_start"})
312
+ yield self.format_chunk({"chunk_type": "content_start", "data_type": "text"})
313
+
314
+ async for event in response:
315
+ for tool_call in event.message.tool_calls or []:
316
+ yield self.format_chunk({"chunk_type": "content_start", "data_type": "tool", "data": tool_call})
317
+ yield self.format_chunk({"chunk_type": "content_delta", "data_type": "tool", "data": tool_call})
318
+ yield self.format_chunk({"chunk_type": "content_stop", "data_type": "tool", "data": tool_call})
319
+ tool_requested = True
320
+
321
+ yield self.format_chunk({"chunk_type": "content_delta", "data_type": "text", "data": event.message.content})
322
+
323
+ yield self.format_chunk({"chunk_type": "content_stop", "data_type": "text"})
324
+ yield self.format_chunk(
325
+ {"chunk_type": "message_stop", "data": "tool_use" if tool_requested else event.done_reason}
326
+ )
327
+ yield self.format_chunk({"chunk_type": "metadata", "data": event})
328
+
329
+ logger.debug("finished streaming response from model")
330
+
331
+ @override
332
+ async def structured_output(
333
+ self, output_model: Type[T], prompt: Messages, system_prompt: Optional[str] = None, **kwargs: Any
334
+ ) -> AsyncGenerator[dict[str, Union[T, Any]], None]:
335
+ """Get structured output from the model.
336
+
337
+ Args:
338
+ output_model: The output model to use for the agent.
339
+ prompt: The prompt messages to use for the agent.
340
+ system_prompt: System prompt to provide context to the model.
341
+ **kwargs: Additional keyword arguments for future extensibility.
342
+
343
+ Yields:
344
+ Model events with the last being the structured output.
345
+ """
346
+ formatted_request = self.format_request(messages=prompt, system_prompt=system_prompt)
347
+ formatted_request["format"] = output_model.model_json_schema()
348
+ formatted_request["stream"] = False
349
+
350
+ client = ollama.AsyncClient(self.host, **self.client_args)
351
+ response = await client.chat(**formatted_request)
352
+
353
+ try:
354
+ content = response.message.content.strip()
355
+ yield {"output": output_model.model_validate_json(content)}
356
+ except Exception as e:
357
+ raise ValueError(f"Failed to parse or load content into model: {e}") from e