power-loop 7.1.0__tar.gz → 7.2.0__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 (124) hide show
  1. {power_loop-7.1.0 → power_loop-7.2.0}/PKG-INFO +1 -1
  2. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/__init__.py +1 -1
  3. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/_vendor/llm_client/interface.py +4 -0
  4. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/_vendor/llm_client/llm_factory.py +9 -0
  5. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/contracts/event_payloads.py +7 -0
  6. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/core/pipeline.py +17 -0
  7. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop.egg-info/PKG-INFO +1 -1
  8. {power_loop-7.1.0 → power_loop-7.2.0}/LICENSE +0 -0
  9. {power_loop-7.1.0 → power_loop-7.2.0}/README.md +0 -0
  10. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/_vendor/__init__.py +0 -0
  11. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/_vendor/llm_client/__init__.py +0 -0
  12. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/_vendor/llm_client/anthropic_factory.py +0 -0
  13. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/_vendor/llm_client/attempt_scope.py +0 -0
  14. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/_vendor/llm_client/capabilities.py +0 -0
  15. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/_vendor/llm_client/llm_tooling.py +0 -0
  16. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/_vendor/llm_client/llm_utils.py +0 -0
  17. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/_vendor/llm_client/multimodal.py +0 -0
  18. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/_vendor/llm_client/proxy_fallback.py +0 -0
  19. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/agent/__init__.py +0 -0
  20. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/agent/follow_up.py +0 -0
  21. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/agent/sink.py +0 -0
  22. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/agent/stateful_loop.py +0 -0
  23. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/agent/system_prompt.py +0 -0
  24. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/agent/types.py +0 -0
  25. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/contracts/__init__.py +0 -0
  26. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/contracts/context_policy.py +0 -0
  27. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/contracts/errors.py +0 -0
  28. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/contracts/events.py +0 -0
  29. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/contracts/handlers.py +0 -0
  30. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/contracts/hook_contexts.py +0 -0
  31. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/contracts/hooks.py +0 -0
  32. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/contracts/messages.py +0 -0
  33. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/contracts/protocols.py +0 -0
  34. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/contracts/tools.py +0 -0
  35. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/contrib/__init__.py +0 -0
  36. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/contrib/_redact.py +0 -0
  37. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/contrib/jsonl_sink.py +0 -0
  38. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/contrib/logging_sink.py +0 -0
  39. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/contrib/mcp.py +0 -0
  40. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/contrib/metrics_sink.py +0 -0
  41. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/contrib/otel_sink.py +0 -0
  42. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/core/agent_context.py +0 -0
  43. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/core/events.py +0 -0
  44. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/core/hooks.py +0 -0
  45. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/core/phase.py +0 -0
  46. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/core/runner.py +0 -0
  47. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/core/state.py +0 -0
  48. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/py.typed +0 -0
  49. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/background.py +0 -0
  50. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/bash_capture.py +0 -0
  51. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/blackboard.py +0 -0
  52. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/budget.py +0 -0
  53. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/cancellation.py +0 -0
  54. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/capability_probe.py +0 -0
  55. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/compact.py +0 -0
  56. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/context_worker.py +0 -0
  57. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/env.py +0 -0
  58. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/exec_backend.py +0 -0
  59. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/fold.py +0 -0
  60. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/fold_adapter.py +0 -0
  61. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/history_projector.py +0 -0
  62. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/history_sanitize.py +0 -0
  63. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/human_input.py +0 -0
  64. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/image_recall.py +0 -0
  65. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/lineage.py +0 -0
  66. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/memory.py +0 -0
  67. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/notes.py +0 -0
  68. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/provider.py +0 -0
  69. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/representation.py +0 -0
  70. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/retry.py +0 -0
  71. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/runtime_state.py +0 -0
  72. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/session_store.py +0 -0
  73. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/skills.py +0 -0
  74. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/spec.py +0 -0
  75. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/steer.py +0 -0
  76. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/stop_policy.py +0 -0
  77. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/store/__init__.py +0 -0
  78. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/store/backends/__init__.py +0 -0
  79. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/store/backends/mysql.py +0 -0
  80. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/store/backends/postgres.py +0 -0
  81. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/store/backends/sqlite.py +0 -0
  82. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/store/capabilities.py +0 -0
  83. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/store/context_cache.py +0 -0
  84. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/store/db.py +0 -0
  85. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/store/dialect.py +0 -0
  86. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/store/factory.py +0 -0
  87. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/store/schema.py +0 -0
  88. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/store/store.py +0 -0
  89. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/store/types.py +0 -0
  90. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/structured.py +0 -0
  91. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/stub_provider.py +0 -0
  92. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/timers.py +0 -0
  93. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/todos.py +0 -0
  94. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/tool_archive.py +0 -0
  95. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/tool_context.py +0 -0
  96. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/tool_truncation.py +0 -0
  97. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/runtime/usage_estimate.py +0 -0
  98. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/tools/__init__.py +0 -0
  99. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/tools/blackboard.py +0 -0
  100. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/tools/command_policy.py +0 -0
  101. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/tools/command_rules.py +0 -0
  102. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/tools/default_manifest.py +0 -0
  103. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/tools/default_tools.py +0 -0
  104. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/tools/registry.py +0 -0
  105. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/tools/spawn_agent.py +0 -0
  106. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/workflow/__init__.py +0 -0
  107. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/workflow/admission.py +0 -0
  108. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/workflow/api.py +0 -0
  109. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/workflow/engine.py +0 -0
  110. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/workflow/introspect.py +0 -0
  111. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/workflow/journal.py +0 -0
  112. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/workflow/result.py +0 -0
  113. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/workflow/resume.py +0 -0
  114. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/workflow/runner.py +0 -0
  115. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/workflow/spec.py +0 -0
  116. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/workflow/subprocess_executor.py +0 -0
  117. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/workflow/tool.py +0 -0
  118. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop/workflow/worker.py +0 -0
  119. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop.egg-info/SOURCES.txt +0 -0
  120. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop.egg-info/dependency_links.txt +0 -0
  121. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop.egg-info/requires.txt +0 -0
  122. {power_loop-7.1.0 → power_loop-7.2.0}/power_loop.egg-info/top_level.txt +0 -0
  123. {power_loop-7.1.0 → power_loop-7.2.0}/pyproject.toml +0 -0
  124. {power_loop-7.1.0 → power_loop-7.2.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: power-loop
3
- Version: 7.1.0
3
+ Version: 7.2.0
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
@@ -15,7 +15,7 @@ Stability tiers
15
15
  无版本承诺,可随时变更或删除。
16
16
  """
17
17
 
18
- __version__ = "7.1.0"
18
+ __version__ = "7.2.0"
19
19
 
20
20
  # Public LLM contract (SDK-free) re-exported so callers (e.g. writing llm.* hooks or
21
21
  # a custom LLMService) don't reach into the internal vendored transport package (H3.4).
@@ -204,6 +204,10 @@ class LLMTokenUsage:
204
204
  accepted_tokens: int | None = None
205
205
  rejected_tokens: int | None = None
206
206
 
207
+ #: Charge the provider itself reported for this call (e.g. OpenRouter's ``usage.cost``), in the
208
+ #: provider's billing currency. ``None`` = not reported; hosts then price tokens themselves.
209
+ cost: float | None = None
210
+
207
211
  def as_dict(self) -> dict[str, int | None]:
208
212
  return dict(self.__dict__)
209
213
 
@@ -419,6 +419,14 @@ class OpenAICompatibleChatLLMService(LLMService):
419
419
  return raw
420
420
 
421
421
  def _usage_obj(self, usage: Any = None) -> LLMTokenUsage:
422
+ def _cost_or_none(v: Any) -> float | None:
423
+ if isinstance(v, bool) or not isinstance(v, (int, float, str)):
424
+ return None
425
+ try:
426
+ return float(v)
427
+ except ValueError:
428
+ return None
429
+
422
430
  d = self._last_usage if usage is None else self._usage_dict_from_any(usage)
423
431
 
424
432
  def _int_or_none(v: Any) -> int | None:
@@ -448,6 +456,7 @@ class OpenAICompatibleChatLLMService(LLMService):
448
456
  reasoning_tokens=_int_or_none(d.get("reasoning_tokens")),
449
457
  accepted_tokens=_int_or_none(d.get("accepted_tokens")),
450
458
  rejected_tokens=_int_or_none(d.get("rejected_tokens")),
459
+ cost=_cost_or_none(d.get("cost")),
451
460
  )
452
461
 
453
462
  async def _with_retries(self, fn, *, method: str) -> Any:
@@ -80,6 +80,13 @@ class LlmCallCompletedPayload(BaseEventPayload):
80
80
  #: ``ok`` · ``error`` · ``timeout`` · ``aborted`` (the attempt's task was cancelled: a retry
81
81
  #: deadline, steering, a stop).
82
82
  outcome: str = "ok"
83
+ #: 7.2: which endpoint served the call (the transport's base URL) — hosts price per connection,
84
+ #: and one model name can be served by several providers at different prices.
85
+ endpoint: str = ""
86
+ #: 7.2: charge the provider reported for this call (``LLMTokenUsage.cost``), ``None`` if not reported.
87
+ provider_cost: float | None = None
88
+ #: 7.2: image input tokens, when the provider splits them out (``None`` = not reported).
89
+ prompt_image_tokens: int | None = None
83
90
 
84
91
 
85
92
  @dataclass
@@ -202,6 +202,19 @@ def _maybe_compact_accepts_context(func: Any) -> bool:
202
202
 
203
203
  # ── Utility functions (unchanged from old agent.py) ──
204
204
 
205
+ def _llm_endpoint(llm: Any) -> str:
206
+ """The base URL that serves this LLM (unwrapping retry / proxy wrappers), or ""."""
207
+ for _ in range(5):
208
+ if llm is None:
209
+ break
210
+ cfg = getattr(llm, "_cfg", None) or getattr(llm, "config", None)
211
+ url = getattr(cfg, "base_url", None)
212
+ if url:
213
+ return str(url)
214
+ llm = getattr(llm, "inner", None) or getattr(llm, "_inner", None) or getattr(llm, "llm", None)
215
+ return ""
216
+
217
+
205
218
  def _truncate_result(output: Any, limit: int | None = RESULT_MAX_CHARS) -> str:
206
219
  """Cap a tool result before it enters history and the audit log (None = no cap). Keeps the
207
220
  head and the tail: errors and summaries are usually at the end."""
@@ -1333,6 +1346,7 @@ class AgentPipeline:
1333
1346
  success=False, error_type=type(exc).__name__,
1334
1347
  prompt_tokens=p_est, completion_tokens=c_est,
1335
1348
  total_tokens=p_est + c_est, estimated=True, outcome=outcome,
1349
+ endpoint=_llm_endpoint(self.llm),
1336
1350
  ),
1337
1351
  round_index=round_index, stream_id="main",
1338
1352
  )
@@ -1364,6 +1378,9 @@ class AgentPipeline:
1364
1378
  prompt_cached_tokens=getattr(usage, "prompt_cached_tokens", None),
1365
1379
  prompt_cache_miss_tokens=getattr(usage, "prompt_cache_miss_tokens", None),
1366
1380
  estimated=estimated,
1381
+ endpoint=_llm_endpoint(self.llm),
1382
+ provider_cost=getattr(usage, "cost", None),
1383
+ prompt_image_tokens=getattr(usage, "prompt_image_tokens", None),
1367
1384
  ),
1368
1385
  round_index=round_index, stream_id="main",
1369
1386
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: power-loop
3
- Version: 7.1.0
3
+ Version: 7.2.0
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
File without changes
File without changes
File without changes
File without changes