power-loop 0.7.0__tar.gz → 0.7.2__tar.gz

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.
Files changed (63) hide show
  1. {power_loop-0.7.0 → power_loop-0.7.2}/PKG-INFO +32 -1
  2. {power_loop-0.7.0 → power_loop-0.7.2}/README.md +31 -0
  3. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/__init__.py +3 -2
  4. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/agent/stateful_loop.py +18 -2
  5. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/tools/__init__.py +3 -3
  6. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop.egg-info/PKG-INFO +32 -1
  7. {power_loop-0.7.0 → power_loop-0.7.2}/LICENSE +0 -0
  8. {power_loop-0.7.0 → power_loop-0.7.2}/llm_client/__init__.py +0 -0
  9. {power_loop-0.7.0 → power_loop-0.7.2}/llm_client/anthropic_factory.py +0 -0
  10. {power_loop-0.7.0 → power_loop-0.7.2}/llm_client/capabilities.py +0 -0
  11. {power_loop-0.7.0 → power_loop-0.7.2}/llm_client/interface.py +0 -0
  12. {power_loop-0.7.0 → power_loop-0.7.2}/llm_client/llm_factory.py +0 -0
  13. {power_loop-0.7.0 → power_loop-0.7.2}/llm_client/llm_tooling.py +0 -0
  14. {power_loop-0.7.0 → power_loop-0.7.2}/llm_client/llm_utils.py +0 -0
  15. {power_loop-0.7.0 → power_loop-0.7.2}/llm_client/multimodal.py +0 -0
  16. {power_loop-0.7.0 → power_loop-0.7.2}/llm_client/qwen_image.py +0 -0
  17. {power_loop-0.7.0 → power_loop-0.7.2}/llm_client/web_search.py +0 -0
  18. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/agent/__init__.py +0 -0
  19. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/agent/follow_up.py +0 -0
  20. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/agent/sink.py +0 -0
  21. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/agent/system_prompt.py +0 -0
  22. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/agent/types.py +0 -0
  23. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/contracts/__init__.py +0 -0
  24. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/contracts/errors.py +0 -0
  25. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/contracts/event_payloads.py +0 -0
  26. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/contracts/events.py +0 -0
  27. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/contracts/handlers.py +0 -0
  28. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/contracts/hook_contexts.py +0 -0
  29. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/contracts/hooks.py +0 -0
  30. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/contracts/messages.py +0 -0
  31. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/contracts/protocols.py +0 -0
  32. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/contracts/tools.py +0 -0
  33. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/core/agent_context.py +0 -0
  34. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/core/events.py +0 -0
  35. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/core/hooks.py +0 -0
  36. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/core/phase.py +0 -0
  37. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/core/pipeline.py +0 -0
  38. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/core/runner.py +0 -0
  39. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/core/state.py +0 -0
  40. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/runtime/budget.py +0 -0
  41. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/runtime/cancellation.py +0 -0
  42. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/runtime/compact.py +0 -0
  43. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/runtime/env.py +0 -0
  44. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/runtime/exec_backend.py +0 -0
  45. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/runtime/human_input.py +0 -0
  46. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/runtime/memory.py +0 -0
  47. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/runtime/provider.py +0 -0
  48. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/runtime/retry.py +0 -0
  49. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/runtime/runtime_state.py +0 -0
  50. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/runtime/session_store.py +0 -0
  51. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/runtime/skills.py +0 -0
  52. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/runtime/spec.py +0 -0
  53. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/runtime/structured.py +0 -0
  54. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/tools/default_manifest.py +0 -0
  55. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/tools/default_tools.py +0 -0
  56. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/tools/registry.py +0 -0
  57. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop/tools/spawn_agent.py +0 -0
  58. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop.egg-info/SOURCES.txt +0 -0
  59. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop.egg-info/dependency_links.txt +0 -0
  60. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop.egg-info/requires.txt +0 -0
  61. {power_loop-0.7.0 → power_loop-0.7.2}/power_loop.egg-info/top_level.txt +0 -0
  62. {power_loop-0.7.0 → power_loop-0.7.2}/pyproject.toml +0 -0
  63. {power_loop-0.7.0 → power_loop-0.7.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: power-loop
3
- Version: 0.7.0
3
+ Version: 0.7.2
4
4
  Summary: Embeddable agent execution kernel — LLM loop, hooks, events, tools, dynamic sub-agents.
5
5
  Author-email: zhangran <zhangran24@126.com>
6
6
  License: MIT
@@ -125,6 +125,37 @@ See [Getting Started](docs/en/getting-started.md) for the complete first run.
125
125
  | Pluggable cross-session memory | [Memory](docs/en/user-guide/memory.md) |
126
126
  | Provider configuration | [Providers](docs/en/user-guide/providers.md) |
127
127
 
128
+ ### Per-call overrides
129
+
130
+ Build one loop and reuse it across callers; restrict tools or swap the system
131
+ prompt **per `send`** without rebuilding (the model only *sees* the allowed
132
+ tools). Ideal for multi-tenant hosts.
133
+
134
+ ```python
135
+ # loop registered with all tools; this run exposes only "get_weather"
136
+ await loop.send("…", session_id=sid, tools=["get_weather"])
137
+
138
+ # per-run system prompt override (precedence: per-call > session > config)
139
+ await loop.send("…", session_id=sid, system_prompt="You are a terse bot.")
140
+ ```
141
+
142
+ The same overrides are available on `send_sync()`. When `follow_up()` is idle
143
+ and falls back to a new send, it accepts them too. A follow-up queued into an
144
+ already running call keeps that call's active tool and prompt policy.
145
+
146
+ For a multi-tenant host that reuses one registry across workspaces, build an
147
+ **unbound** registry and supply the workspace at invocation time:
148
+
149
+ ```python
150
+ from power_loop import RuntimeEnv, create_default_tool_registry, runtime_env_context
151
+
152
+ registry = create_default_tool_registry(preset="core", bind=False)
153
+ with runtime_env_context(RuntimeEnv(workspace_dir=tenant_workspace)):
154
+ result = await registry.invoke_async("read_file", {"path": "README.md"})
155
+ ```
156
+
157
+ See [`examples/23_per_send_overrides.py`](examples/23_per_send_overrides.py).
158
+
128
159
  ## Public API
129
160
 
130
161
  Stable imports are re-exported from `power_loop`:
@@ -88,6 +88,37 @@ See [Getting Started](docs/en/getting-started.md) for the complete first run.
88
88
  | Pluggable cross-session memory | [Memory](docs/en/user-guide/memory.md) |
89
89
  | Provider configuration | [Providers](docs/en/user-guide/providers.md) |
90
90
 
91
+ ### Per-call overrides
92
+
93
+ Build one loop and reuse it across callers; restrict tools or swap the system
94
+ prompt **per `send`** without rebuilding (the model only *sees* the allowed
95
+ tools). Ideal for multi-tenant hosts.
96
+
97
+ ```python
98
+ # loop registered with all tools; this run exposes only "get_weather"
99
+ await loop.send("…", session_id=sid, tools=["get_weather"])
100
+
101
+ # per-run system prompt override (precedence: per-call > session > config)
102
+ await loop.send("…", session_id=sid, system_prompt="You are a terse bot.")
103
+ ```
104
+
105
+ The same overrides are available on `send_sync()`. When `follow_up()` is idle
106
+ and falls back to a new send, it accepts them too. A follow-up queued into an
107
+ already running call keeps that call's active tool and prompt policy.
108
+
109
+ For a multi-tenant host that reuses one registry across workspaces, build an
110
+ **unbound** registry and supply the workspace at invocation time:
111
+
112
+ ```python
113
+ from power_loop import RuntimeEnv, create_default_tool_registry, runtime_env_context
114
+
115
+ registry = create_default_tool_registry(preset="core", bind=False)
116
+ with runtime_env_context(RuntimeEnv(workspace_dir=tenant_workspace)):
117
+ result = await registry.invoke_async("read_file", {"path": "README.md"})
118
+ ```
119
+
120
+ See [`examples/23_per_send_overrides.py`](examples/23_per_send_overrides.py).
121
+
91
122
  ## Public API
92
123
 
93
124
  Stable imports are re-exported from `power_loop`:
@@ -22,7 +22,7 @@ Stability tiers
22
22
  无版本承诺,可随时变更或删除。
23
23
  """
24
24
 
25
- __version__ = "0.7.0"
25
+ __version__ = "0.7.2"
26
26
 
27
27
  from power_loop.agent.follow_up import FollowUpQueued
28
28
  from power_loop.agent.sink import MessageSink, NullSink, SQLiteSink
@@ -116,7 +116,7 @@ from power_loop.core.pipeline import AgentPipeline
116
116
  from power_loop.core.runner import AgentRunner
117
117
  from power_loop.runtime.budget import estimate_text_tokens, estimate_tokens, trim_history
118
118
  from power_loop.runtime.cancellation import CancellationLike, CancellationToken
119
- from power_loop.runtime.env import RuntimeEnv, RuntimeEnvError
119
+ from power_loop.runtime.env import RuntimeEnv, RuntimeEnvError, runtime_env_context
120
120
  from power_loop.runtime.exec_backend import (
121
121
  DEFAULT_SHELL_BACKEND,
122
122
  LocalShellBackend,
@@ -244,6 +244,7 @@ __all__ = [
244
244
  "CancellationLike",
245
245
  "RuntimeEnv",
246
246
  "RuntimeEnvError",
247
+ "runtime_env_context",
247
248
  "ShellBackend",
248
249
  "LocalShellBackend",
249
250
  "DEFAULT_SHELL_BACKEND",
@@ -196,9 +196,17 @@ class StatefulAgentLoop:
196
196
  session_id: str,
197
197
  *,
198
198
  stop_event: CancellationLike = None,
199
+ tools: Sequence[str] | ToolRegistry | None = None,
200
+ system_prompt: str | None = None,
199
201
  ) -> StatefulResult | FollowUpQueued:
200
202
  return asyncio.run(
201
- self.follow_up(user_input, session_id, stop_event=stop_event)
203
+ self.follow_up(
204
+ user_input,
205
+ session_id,
206
+ stop_event=stop_event,
207
+ tools=tools,
208
+ system_prompt=system_prompt,
209
+ )
202
210
  )
203
211
 
204
212
  def send_sync(
@@ -207,9 +215,17 @@ class StatefulAgentLoop:
207
215
  session_id: str,
208
216
  *,
209
217
  stop_event: CancellationLike = None,
218
+ tools: Sequence[str] | ToolRegistry | None = None,
219
+ system_prompt: str | None = None,
210
220
  ) -> StatefulResult:
211
221
  return asyncio.run(
212
- self.send(user_input, session_id, stop_event=stop_event)
222
+ self.send(
223
+ user_input,
224
+ session_id,
225
+ stop_event=stop_event,
226
+ tools=tools,
227
+ system_prompt=system_prompt,
228
+ )
213
229
  )
214
230
 
215
231
  async def resume(
@@ -50,6 +50,9 @@ def create_default_tool_registry(
50
50
  If omitted, ``POWER_LOOP_HOME`` is used when present.
51
51
  skills_dir: Optional default skills directory for ``load_skill``.
52
52
  If omitted, ``POWER_LOOP_SKILLS_DIR`` is used when present.
53
+ bind: When true (default), bind handlers to one ``RuntimeEnv`` now.
54
+ When false, return handlers that resolve the current
55
+ ``runtime_env_context`` at invocation time.
53
56
 
54
57
  Examples::
55
58
 
@@ -68,9 +71,6 @@ def create_default_tool_registry(
68
71
  workspace_dir="/path/to/project",
69
72
  )
70
73
  """
71
- from power_loop.tools.default_manifest import get_tool_definitions
72
- from power_loop.tools.default_tools import DEFAULT_TOOL_HANDLERS
73
-
74
74
  definitions = get_tool_definitions(preset=preset, include=include, exclude=exclude)
75
75
  if not bind:
76
76
  # Unbound: handlers read the current RuntimeEnv at call time; the caller
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: power-loop
3
- Version: 0.7.0
3
+ Version: 0.7.2
4
4
  Summary: Embeddable agent execution kernel — LLM loop, hooks, events, tools, dynamic sub-agents.
5
5
  Author-email: zhangran <zhangran24@126.com>
6
6
  License: MIT
@@ -125,6 +125,37 @@ See [Getting Started](docs/en/getting-started.md) for the complete first run.
125
125
  | Pluggable cross-session memory | [Memory](docs/en/user-guide/memory.md) |
126
126
  | Provider configuration | [Providers](docs/en/user-guide/providers.md) |
127
127
 
128
+ ### Per-call overrides
129
+
130
+ Build one loop and reuse it across callers; restrict tools or swap the system
131
+ prompt **per `send`** without rebuilding (the model only *sees* the allowed
132
+ tools). Ideal for multi-tenant hosts.
133
+
134
+ ```python
135
+ # loop registered with all tools; this run exposes only "get_weather"
136
+ await loop.send("…", session_id=sid, tools=["get_weather"])
137
+
138
+ # per-run system prompt override (precedence: per-call > session > config)
139
+ await loop.send("…", session_id=sid, system_prompt="You are a terse bot.")
140
+ ```
141
+
142
+ The same overrides are available on `send_sync()`. When `follow_up()` is idle
143
+ and falls back to a new send, it accepts them too. A follow-up queued into an
144
+ already running call keeps that call's active tool and prompt policy.
145
+
146
+ For a multi-tenant host that reuses one registry across workspaces, build an
147
+ **unbound** registry and supply the workspace at invocation time:
148
+
149
+ ```python
150
+ from power_loop import RuntimeEnv, create_default_tool_registry, runtime_env_context
151
+
152
+ registry = create_default_tool_registry(preset="core", bind=False)
153
+ with runtime_env_context(RuntimeEnv(workspace_dir=tenant_workspace)):
154
+ result = await registry.invoke_async("read_file", {"path": "README.md"})
155
+ ```
156
+
157
+ See [`examples/23_per_send_overrides.py`](examples/23_per_send_overrides.py).
158
+
128
159
  ## Public API
129
160
 
130
161
  Stable imports are re-exported from `power_loop`:
File without changes
File without changes
File without changes