pal-runtime 0.1.0__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.
- pal/__init__.py +159 -0
- pal/agent.py +234 -0
- pal/client.py +2246 -0
- pal/errors.py +62 -0
- pal/integrations/__init__.py +5 -0
- pal/integrations/deepagents_sandbox.py +169 -0
- pal/integrations/runtime_client.py +116 -0
- pal/runtime/__init__.py +25 -0
- pal/runtime/context.py +127 -0
- pal/runtime/llm_client.py +203 -0
- pal/runtime/memory_client.py +128 -0
- pal/runtime/runner.py +149 -0
- pal/runtime/runtime.py +53 -0
- pal/runtime/step_runtime.py +146 -0
- pal/runtime/tool_client.py +109 -0
- pal/step.py +209 -0
- pal/tools.py +109 -0
- pal/types.py +786 -0
- pal_runtime-0.1.0.dist-info/METADATA +373 -0
- pal_runtime-0.1.0.dist-info/RECORD +24 -0
- pal_runtime-0.1.0.dist-info/WHEEL +5 -0
- pal_runtime-0.1.0.dist-info/entry_points.txt +2 -0
- pal_runtime-0.1.0.dist-info/licenses/LICENSE +202 -0
- pal_runtime-0.1.0.dist-info/top_level.txt +1 -0
pal/__init__.py
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""PAL Python SDK — build production AI agents with durable execution.
|
|
2
|
+
|
|
3
|
+
Quick start::
|
|
4
|
+
|
|
5
|
+
from pal import agent, step
|
|
6
|
+
|
|
7
|
+
@agent("hello-world", model="auto")
|
|
8
|
+
async def hello(input: dict, ctx):
|
|
9
|
+
greeting = await step("greet", lambda: ctx.llm.complete(
|
|
10
|
+
prompt=f"Say hello to {input['name']}",
|
|
11
|
+
capability="chat-small",
|
|
12
|
+
))
|
|
13
|
+
return {"greeting": greeting}
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from pal.agent import PalAgent, agent, get_agent, list_agents
|
|
17
|
+
from pal.client import PalClient
|
|
18
|
+
from pal.errors import (
|
|
19
|
+
PalApiError,
|
|
20
|
+
PalError,
|
|
21
|
+
PalLlmError,
|
|
22
|
+
PalPolicyDeniedError,
|
|
23
|
+
PalPolicyVersionConflictError,
|
|
24
|
+
PalStepError,
|
|
25
|
+
PalTimeoutError,
|
|
26
|
+
PalValidationError,
|
|
27
|
+
)
|
|
28
|
+
from pal.step import step, step_map, step_race, step_signal, step_sleep
|
|
29
|
+
from pal.tools import tool
|
|
30
|
+
from pal.types import (
|
|
31
|
+
AgentConfig,
|
|
32
|
+
AgentContext,
|
|
33
|
+
AgentInfo,
|
|
34
|
+
ApprovalRequest,
|
|
35
|
+
AskOptions,
|
|
36
|
+
BuiltContext,
|
|
37
|
+
Capability,
|
|
38
|
+
CompactionConfig,
|
|
39
|
+
ConnectorAction,
|
|
40
|
+
ConnectorInfo,
|
|
41
|
+
ConnectorResult,
|
|
42
|
+
ContextBudget,
|
|
43
|
+
ContextBuildOpts,
|
|
44
|
+
ContextConfig,
|
|
45
|
+
GuardrailConfig,
|
|
46
|
+
IsolationClass,
|
|
47
|
+
IsolationConfig,
|
|
48
|
+
LlmClient,
|
|
49
|
+
LlmJsonOptions,
|
|
50
|
+
LlmOptions,
|
|
51
|
+
LlmStreamOptions,
|
|
52
|
+
MemoryClient,
|
|
53
|
+
MemoryConfig,
|
|
54
|
+
MemoryEntry,
|
|
55
|
+
MemoryTier,
|
|
56
|
+
Message,
|
|
57
|
+
MessageRole,
|
|
58
|
+
NotifyOptions,
|
|
59
|
+
OptimizeTarget,
|
|
60
|
+
OptimizeWeights,
|
|
61
|
+
PrivacyLevel,
|
|
62
|
+
RecallConfig,
|
|
63
|
+
ResourceLimits,
|
|
64
|
+
RetryPolicy,
|
|
65
|
+
RouteStrategy,
|
|
66
|
+
Run,
|
|
67
|
+
RunError,
|
|
68
|
+
RunStatus,
|
|
69
|
+
Session,
|
|
70
|
+
SessionConfig,
|
|
71
|
+
SessionMessage,
|
|
72
|
+
StepOptions,
|
|
73
|
+
StreamEvent,
|
|
74
|
+
StreamEventKind,
|
|
75
|
+
ToolCallMessage,
|
|
76
|
+
ToolClient,
|
|
77
|
+
ToolDef,
|
|
78
|
+
TriggerKind,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
__version__ = "0.1.0"
|
|
82
|
+
|
|
83
|
+
__all__ = [
|
|
84
|
+
# Agent definition
|
|
85
|
+
"agent",
|
|
86
|
+
"PalAgent",
|
|
87
|
+
"get_agent",
|
|
88
|
+
"list_agents",
|
|
89
|
+
# Step primitives
|
|
90
|
+
"step",
|
|
91
|
+
"step_map",
|
|
92
|
+
"step_race",
|
|
93
|
+
"step_sleep",
|
|
94
|
+
"step_signal",
|
|
95
|
+
# Client
|
|
96
|
+
"PalClient",
|
|
97
|
+
# Tools
|
|
98
|
+
"tool",
|
|
99
|
+
# Errors
|
|
100
|
+
"PalError",
|
|
101
|
+
"PalApiError",
|
|
102
|
+
"PalPolicyDeniedError",
|
|
103
|
+
"PalPolicyVersionConflictError",
|
|
104
|
+
"PalStepError",
|
|
105
|
+
"PalLlmError",
|
|
106
|
+
"PalTimeoutError",
|
|
107
|
+
"PalValidationError",
|
|
108
|
+
# Types — enums
|
|
109
|
+
"Capability",
|
|
110
|
+
"OptimizeTarget",
|
|
111
|
+
"RunStatus",
|
|
112
|
+
"TriggerKind",
|
|
113
|
+
"IsolationClass",
|
|
114
|
+
"MemoryTier",
|
|
115
|
+
"StreamEventKind",
|
|
116
|
+
"MessageRole",
|
|
117
|
+
"PrivacyLevel",
|
|
118
|
+
"RouteStrategy",
|
|
119
|
+
# Types — models
|
|
120
|
+
"AgentConfig",
|
|
121
|
+
"AgentContext",
|
|
122
|
+
"AgentInfo",
|
|
123
|
+
"Message",
|
|
124
|
+
"ToolCallMessage",
|
|
125
|
+
"ToolDef",
|
|
126
|
+
"RetryPolicy",
|
|
127
|
+
"StepOptions",
|
|
128
|
+
"MemoryConfig",
|
|
129
|
+
"ResourceLimits",
|
|
130
|
+
"IsolationConfig",
|
|
131
|
+
"RunError",
|
|
132
|
+
"Run",
|
|
133
|
+
"StreamEvent",
|
|
134
|
+
"MemoryEntry",
|
|
135
|
+
"ApprovalRequest",
|
|
136
|
+
"AskOptions",
|
|
137
|
+
"NotifyOptions",
|
|
138
|
+
"OptimizeWeights",
|
|
139
|
+
"ContextBudget",
|
|
140
|
+
"CompactionConfig",
|
|
141
|
+
"RecallConfig",
|
|
142
|
+
"ContextConfig",
|
|
143
|
+
"ContextBuildOpts",
|
|
144
|
+
"BuiltContext",
|
|
145
|
+
"LlmOptions",
|
|
146
|
+
"LlmJsonOptions",
|
|
147
|
+
"LlmStreamOptions",
|
|
148
|
+
"SessionConfig",
|
|
149
|
+
"GuardrailConfig",
|
|
150
|
+
"Session",
|
|
151
|
+
"SessionMessage",
|
|
152
|
+
"ConnectorAction",
|
|
153
|
+
"ConnectorInfo",
|
|
154
|
+
"ConnectorResult",
|
|
155
|
+
# Types — clients/interfaces
|
|
156
|
+
"LlmClient",
|
|
157
|
+
"ToolClient",
|
|
158
|
+
"MemoryClient",
|
|
159
|
+
]
|
pal/agent.py
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
"""Agent definition — decorator and class-based patterns (Google ADK-inspired).
|
|
2
|
+
|
|
3
|
+
Usage (decorator)::
|
|
4
|
+
|
|
5
|
+
@agent("my-agent", model="auto")
|
|
6
|
+
async def my_agent(input: dict, ctx: AgentContext) -> dict:
|
|
7
|
+
result = await step("greet", lambda: ctx.llm.complete(prompt="Hello"))
|
|
8
|
+
return {"greeting": result}
|
|
9
|
+
|
|
10
|
+
Usage (class-based)::
|
|
11
|
+
|
|
12
|
+
class MyAgent(PalAgent):
|
|
13
|
+
name = "my-agent"
|
|
14
|
+
model = "auto"
|
|
15
|
+
|
|
16
|
+
async def run(self, input: dict, ctx: AgentContext) -> dict:
|
|
17
|
+
...
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import re
|
|
23
|
+
from typing import Any, Awaitable, Callable
|
|
24
|
+
|
|
25
|
+
from pal.errors import PalValidationError
|
|
26
|
+
from pal.types import (
|
|
27
|
+
AgentConfig,
|
|
28
|
+
AgentContext,
|
|
29
|
+
Capability,
|
|
30
|
+
IsolationConfig,
|
|
31
|
+
MemoryConfig,
|
|
32
|
+
ResourceLimits,
|
|
33
|
+
ToolDef,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
_NAME_RE = re.compile(r"^[a-z0-9-]{1,63}$")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _validate_name(name: str) -> None:
|
|
40
|
+
if not _NAME_RE.match(name):
|
|
41
|
+
raise PalValidationError(f'Agent name must match [a-z0-9-]{{1,63}}, got: "{name}"')
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# ---------------------------------------------------------------------------
|
|
45
|
+
# Registered agent — the object returned by the @agent decorator
|
|
46
|
+
# ---------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class RegisteredAgent:
|
|
50
|
+
"""Wrapper around a user-defined agent function plus its config.
|
|
51
|
+
|
|
52
|
+
This is the object stored in the module-level registry and loaded by the
|
|
53
|
+
runner at startup.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
def __init__(
|
|
57
|
+
self,
|
|
58
|
+
config: AgentConfig,
|
|
59
|
+
fn: Callable[[dict[str, Any], AgentContext], Awaitable[Any]],
|
|
60
|
+
) -> None:
|
|
61
|
+
self.config = config
|
|
62
|
+
self._fn = fn
|
|
63
|
+
# Preserve the original function metadata for introspection
|
|
64
|
+
self.__name__ = getattr(fn, "__name__", config.name)
|
|
65
|
+
self.__doc__ = getattr(fn, "__doc__", None)
|
|
66
|
+
|
|
67
|
+
async def run(self, input: dict[str, Any], ctx: AgentContext) -> Any:
|
|
68
|
+
return await self._fn(input, ctx)
|
|
69
|
+
|
|
70
|
+
def __repr__(self) -> str:
|
|
71
|
+
return f"<RegisteredAgent name={self.config.name!r} version={self.config.version!r}>"
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# ---------------------------------------------------------------------------
|
|
75
|
+
# Module-level registry — simple dict mapping name -> RegisteredAgent
|
|
76
|
+
# ---------------------------------------------------------------------------
|
|
77
|
+
|
|
78
|
+
_registry: dict[str, RegisteredAgent] = {}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def get_agent(name: str) -> RegisteredAgent | None:
|
|
82
|
+
"""Retrieve a registered agent by name."""
|
|
83
|
+
return _registry.get(name)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def list_agents() -> list[RegisteredAgent]:
|
|
87
|
+
"""Return all registered agents."""
|
|
88
|
+
return list(_registry.values())
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
# ---------------------------------------------------------------------------
|
|
92
|
+
# @agent decorator
|
|
93
|
+
# ---------------------------------------------------------------------------
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def agent(
|
|
97
|
+
name: str,
|
|
98
|
+
*,
|
|
99
|
+
version: str = "0.1.0",
|
|
100
|
+
model: Capability | str = "auto",
|
|
101
|
+
description: str = "",
|
|
102
|
+
tools: list[ToolDef] | None = None,
|
|
103
|
+
memory: list[MemoryConfig] | None = None,
|
|
104
|
+
limits: ResourceLimits | dict[str, Any] | None = None,
|
|
105
|
+
isolation: IsolationConfig | dict[str, Any] | None = None,
|
|
106
|
+
labels: dict[str, str] | None = None,
|
|
107
|
+
) -> Callable[
|
|
108
|
+
[Callable[[dict[str, Any], AgentContext], Awaitable[Any]]],
|
|
109
|
+
RegisteredAgent,
|
|
110
|
+
]:
|
|
111
|
+
"""Decorator that creates and registers a PAL agent.
|
|
112
|
+
|
|
113
|
+
Parameters
|
|
114
|
+
----------
|
|
115
|
+
name:
|
|
116
|
+
DNS-compatible identifier ([a-z0-9-]{1,63}).
|
|
117
|
+
version:
|
|
118
|
+
Semver string, defaults to ``"0.1.0"``.
|
|
119
|
+
model:
|
|
120
|
+
Default model capability for LLM calls. ``"auto"`` lets the
|
|
121
|
+
model router decide.
|
|
122
|
+
description:
|
|
123
|
+
Human-readable description.
|
|
124
|
+
tools:
|
|
125
|
+
Built-in tool definitions to make available.
|
|
126
|
+
memory:
|
|
127
|
+
Memory configurations for the agent.
|
|
128
|
+
limits:
|
|
129
|
+
Resource limits (CPU, memory, GPU, timeout, cost, tokens, steps).
|
|
130
|
+
isolation:
|
|
131
|
+
Isolation class for the agent's runtime environment.
|
|
132
|
+
labels:
|
|
133
|
+
Arbitrary key-value labels.
|
|
134
|
+
|
|
135
|
+
Returns a :class:`RegisteredAgent` instance that wraps the decorated
|
|
136
|
+
function and holds its :class:`AgentConfig`.
|
|
137
|
+
"""
|
|
138
|
+
_validate_name(name)
|
|
139
|
+
|
|
140
|
+
# Coerce convenience dicts into typed models
|
|
141
|
+
if isinstance(limits, dict):
|
|
142
|
+
limits = ResourceLimits(**limits)
|
|
143
|
+
if isinstance(isolation, dict):
|
|
144
|
+
isolation = IsolationConfig(**isolation)
|
|
145
|
+
|
|
146
|
+
config = AgentConfig(
|
|
147
|
+
name=name,
|
|
148
|
+
version=version,
|
|
149
|
+
model=model,
|
|
150
|
+
description=description,
|
|
151
|
+
tools=tools,
|
|
152
|
+
memory=memory,
|
|
153
|
+
limits=limits,
|
|
154
|
+
isolation=isolation,
|
|
155
|
+
labels=labels or {},
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
def decorator(
|
|
159
|
+
fn: Callable[[dict[str, Any], AgentContext], Awaitable[Any]],
|
|
160
|
+
) -> RegisteredAgent:
|
|
161
|
+
if not callable(fn):
|
|
162
|
+
raise PalValidationError("Agent must wrap a callable")
|
|
163
|
+
|
|
164
|
+
registered = RegisteredAgent(config, fn)
|
|
165
|
+
_registry[name] = registered
|
|
166
|
+
return registered
|
|
167
|
+
|
|
168
|
+
return decorator
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
# ---------------------------------------------------------------------------
|
|
172
|
+
# Class-based agent (Google ADK style)
|
|
173
|
+
# ---------------------------------------------------------------------------
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
class PalAgent:
|
|
177
|
+
"""Base class for class-based agent definitions.
|
|
178
|
+
|
|
179
|
+
Subclass and override ``run``. Class attributes map to ``AgentConfig``
|
|
180
|
+
fields::
|
|
181
|
+
|
|
182
|
+
class Greeter(PalAgent):
|
|
183
|
+
name = "greeter"
|
|
184
|
+
version = "1.0.0"
|
|
185
|
+
model = "chat-small"
|
|
186
|
+
description = "A friendly greeter"
|
|
187
|
+
|
|
188
|
+
async def run(self, input: dict, ctx: AgentContext) -> dict:
|
|
189
|
+
greeting = await ctx.llm.complete(prompt=f"Hello {input['name']}")
|
|
190
|
+
return {"greeting": greeting}
|
|
191
|
+
"""
|
|
192
|
+
|
|
193
|
+
name: str = ""
|
|
194
|
+
version: str = "0.1.0"
|
|
195
|
+
model: Capability | str = "auto"
|
|
196
|
+
description: str = ""
|
|
197
|
+
tools: list[ToolDef] | None = None
|
|
198
|
+
memory: list[MemoryConfig] | None = None
|
|
199
|
+
limits: ResourceLimits | None = None
|
|
200
|
+
isolation: IsolationConfig | None = None
|
|
201
|
+
labels: dict[str, str] = {}
|
|
202
|
+
|
|
203
|
+
def __init_subclass__(cls, **kwargs: Any) -> None:
|
|
204
|
+
super().__init_subclass__(**kwargs)
|
|
205
|
+
# Only register concrete subclasses that define a name
|
|
206
|
+
if cls.name:
|
|
207
|
+
_validate_name(cls.name)
|
|
208
|
+
config = AgentConfig(
|
|
209
|
+
name=cls.name,
|
|
210
|
+
version=cls.version,
|
|
211
|
+
model=cls.model,
|
|
212
|
+
description=cls.description,
|
|
213
|
+
tools=cls.tools,
|
|
214
|
+
memory=cls.memory,
|
|
215
|
+
limits=cls.limits,
|
|
216
|
+
isolation=cls.isolation,
|
|
217
|
+
labels=cls.labels or {},
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
# Create a RegisteredAgent that delegates to an instance of the class
|
|
221
|
+
instance = cls()
|
|
222
|
+
registered = RegisteredAgent(config, instance._dispatch)
|
|
223
|
+
_registry[cls.name] = registered
|
|
224
|
+
# Store a reference so the class can be used directly too
|
|
225
|
+
cls._registered = registered # type: ignore[attr-defined]
|
|
226
|
+
|
|
227
|
+
async def _dispatch(self, input: dict[str, Any], ctx: AgentContext) -> Any:
|
|
228
|
+
return await self.run(input, ctx)
|
|
229
|
+
|
|
230
|
+
async def run(self, input: dict[str, Any], ctx: AgentContext) -> Any:
|
|
231
|
+
raise NotImplementedError("Subclass must implement run()")
|
|
232
|
+
|
|
233
|
+
async def init(self) -> None:
|
|
234
|
+
"""Optional init hook called once before the first run."""
|