power-loop 6.52.0__tar.gz → 6.53.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.
- {power_loop-6.52.0 → power_loop-6.53.0}/PKG-INFO +1 -1
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/__init__.py +1 -1
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/core/pipeline.py +12 -3
- power_loop-6.53.0/power_loop/runtime/bash_capture.py +38 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/tools/default_tools.py +5 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop.egg-info/PKG-INFO +1 -1
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop.egg-info/SOURCES.txt +1 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/LICENSE +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/README.md +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/_vendor/__init__.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/_vendor/llm_client/__init__.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/_vendor/llm_client/anthropic_factory.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/_vendor/llm_client/capabilities.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/_vendor/llm_client/interface.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/_vendor/llm_client/llm_factory.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/_vendor/llm_client/llm_tooling.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/_vendor/llm_client/llm_utils.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/_vendor/llm_client/multimodal.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/_vendor/llm_client/proxy_fallback.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/agent/__init__.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/agent/follow_up.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/agent/sink.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/agent/stateful_loop.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/agent/system_prompt.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/agent/types.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/contracts/__init__.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/contracts/errors.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/contracts/event_payloads.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/contracts/events.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/contracts/handlers.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/contracts/hook_contexts.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/contracts/hooks.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/contracts/messages.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/contracts/protocols.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/contracts/tools.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/contrib/__init__.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/contrib/_redact.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/contrib/jsonl_sink.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/contrib/logging_sink.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/contrib/mcp.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/contrib/metrics_sink.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/contrib/otel_sink.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/core/agent_context.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/core/events.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/core/hooks.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/core/phase.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/core/runner.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/core/state.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/py.typed +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/background.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/blackboard.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/budget.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/cancellation.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/capability_probe.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/compact.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/env.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/exec_backend.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/fold.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/fold_adapter.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/history_projector.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/history_sanitize.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/human_input.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/image_recall.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/memory.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/notes.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/provider.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/representation.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/retry.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/runtime_state.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/session_store.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/skills.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/spec.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/steer.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/stop_policy.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/store/__init__.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/store/backends/__init__.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/store/backends/mysql.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/store/backends/postgres.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/store/backends/sqlite.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/store/capabilities.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/store/db.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/store/dialect.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/store/factory.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/store/schema.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/store/store.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/store/types.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/structured.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/stub_provider.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/timers.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/todos.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/runtime/usage_estimate.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/tools/__init__.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/tools/blackboard.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/tools/command_policy.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/tools/command_rules.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/tools/default_manifest.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/tools/registry.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/tools/spawn_agent.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/workflow/__init__.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/workflow/admission.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/workflow/api.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/workflow/engine.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/workflow/introspect.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/workflow/journal.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/workflow/result.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/workflow/resume.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/workflow/runner.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/workflow/spec.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/workflow/subprocess_executor.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/workflow/tool.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop/workflow/worker.py +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop.egg-info/dependency_links.txt +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop.egg-info/requires.txt +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/power_loop.egg-info/top_level.txt +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/pyproject.toml +0 -0
- {power_loop-6.52.0 → power_loop-6.53.0}/setup.cfg +0 -0
|
@@ -15,7 +15,7 @@ Stability tiers
|
|
|
15
15
|
无版本承诺,可随时变更或删除。
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
__version__ = "6.
|
|
18
|
+
__version__ = "6.53.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).
|
|
@@ -931,6 +931,8 @@ class AgentPipeline:
|
|
|
931
931
|
elif row.get("role") == "tool":
|
|
932
932
|
results[str(row.get("tool_call_id") or "")] = i
|
|
933
933
|
protected = {cid for cid, _, _ in calls[-hot_tail:]} if hot_tail > 0 else set()
|
|
934
|
+
# Optional host protection for individual calls (e.g. bash loading persistent skills).
|
|
935
|
+
protected.update(getattr(self, "_context_protected_call_ids", ()))
|
|
934
936
|
keep = set(self.config.insend_distill_keep_tools or ())
|
|
935
937
|
freed_chars = 0
|
|
936
938
|
for cid, i, j in calls:
|
|
@@ -951,7 +953,8 @@ class AgentPipeline:
|
|
|
951
953
|
except Exception: # a broken projector must not stop the run or starve later calls
|
|
952
954
|
logger.warning("in-send distillation failed for %s", name, exc_info=True)
|
|
953
955
|
continue
|
|
954
|
-
|
|
956
|
+
# recall_send needs the result row; it includes the matching call arguments.
|
|
957
|
+
seq = seqs[ri] if ri < len(seqs) else None
|
|
955
958
|
coord = (f"recall_send(send_index={self.send_index}, seq={seq})"
|
|
956
959
|
if self.send_index is not None and seq is not None else "recall_send")
|
|
957
960
|
new_content = f"{self._DISTILL_MARK}{self.send_index} seq={seq}; {coord}] {line}"
|
|
@@ -1022,11 +1025,17 @@ class AgentPipeline:
|
|
|
1022
1025
|
|
|
1023
1026
|
# Fuse uses total prompt size, including the fixed prompt and history prefix.
|
|
1024
1027
|
dt = self.config.insend_distill_tokens
|
|
1025
|
-
if dt is not None and int(dt) > 0 and
|
|
1028
|
+
if dt is not None and int(dt) > 0 and (
|
|
1029
|
+
round_index > 0 or getattr(self, "_context_prompt_tokens_estimate", None) is not None
|
|
1030
|
+
):
|
|
1026
1031
|
real = int((self.ctx.token_usage or {}).get("prompt_tokens", 0) or 0)
|
|
1027
1032
|
if real and self._send_baseline_prompt is None:
|
|
1028
1033
|
self._send_baseline_prompt = real # diagnostics only; never subtracted from trigger
|
|
1029
|
-
|
|
1034
|
+
# Optional host estimate after context retirement. Never mutate provider
|
|
1035
|
+
# usage: the latter is billing evidence for the previous request.
|
|
1036
|
+
current_estimate = getattr(self, "_context_prompt_tokens_estimate", None)
|
|
1037
|
+
total = (max(0, int(current_estimate)) if current_estimate is not None
|
|
1038
|
+
else real or self._estimate_history_tokens())
|
|
1030
1039
|
if total >= int(dt):
|
|
1031
1040
|
freed = self._distill_oldest_tool_rows(
|
|
1032
1041
|
0, int(self.config.insend_distill_hot_tail or 0),
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Opt-in capture of normalized terminal output before bash display truncation.
|
|
2
|
+
|
|
3
|
+
This preserves every line delivered by the persistent terminal reader, not raw PTY
|
|
4
|
+
bytes (ANSI cleanup and terminal line normalization still apply). No capture by default.
|
|
5
|
+
"""
|
|
6
|
+
from contextvars import ContextVar
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
current_bash_capture: ContextVar['BashOutputCapture | None'] = ContextVar('bash_output_capture', default=None)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class BashOutputCapture:
|
|
13
|
+
def __init__(self, path: Path):
|
|
14
|
+
self.path = Path(path)
|
|
15
|
+
self.error: str | None = None
|
|
16
|
+
self.lines = 0
|
|
17
|
+
|
|
18
|
+
def __enter__(self):
|
|
19
|
+
self.stream = self.path.open('x', encoding='utf-8')
|
|
20
|
+
self.token = current_bash_capture.set(self)
|
|
21
|
+
return self
|
|
22
|
+
|
|
23
|
+
def write_line(self, line: str) -> None:
|
|
24
|
+
if self.error:
|
|
25
|
+
return
|
|
26
|
+
try:
|
|
27
|
+
self.stream.write(line + '\n')
|
|
28
|
+
self.lines += 1
|
|
29
|
+
except OSError as exc:
|
|
30
|
+
# Never interrupt command draining and leave a shell running with stale output.
|
|
31
|
+
self.error = type(exc).__name__
|
|
32
|
+
|
|
33
|
+
def __exit__(self, *exc):
|
|
34
|
+
current_bash_capture.reset(self.token)
|
|
35
|
+
try:
|
|
36
|
+
self.stream.close()
|
|
37
|
+
except OSError as error:
|
|
38
|
+
self.error = type(error).__name__
|
|
@@ -491,6 +491,9 @@ class BashSession:
|
|
|
491
491
|
# head+tail (via _truncate_lines), so a command emitting millions of lines must not buffer
|
|
492
492
|
# them all. Keep the first _BASH_HEAD_KEEP fully + the last _BASH_TAIL_KEEP in a ring,
|
|
493
493
|
# dropping the middle (both bounds comfortably exceed _truncate_lines' 30+170 window).
|
|
494
|
+
from power_loop.runtime.bash_capture import current_bash_capture
|
|
495
|
+
|
|
496
|
+
capture = current_bash_capture.get()
|
|
494
497
|
head: list[str] = []
|
|
495
498
|
tail: deque[str] = deque(maxlen=_BASH_TAIL_KEEP)
|
|
496
499
|
dropped = 0
|
|
@@ -499,6 +502,8 @@ class BashSession:
|
|
|
499
502
|
|
|
500
503
|
def _accumulate(line: str) -> None:
|
|
501
504
|
nonlocal dropped
|
|
505
|
+
if capture is not None:
|
|
506
|
+
capture.write_line(line)
|
|
502
507
|
if len(head) < _BASH_HEAD_KEEP:
|
|
503
508
|
head.append(line)
|
|
504
509
|
return
|
|
@@ -49,6 +49,7 @@ power_loop/core/pipeline.py
|
|
|
49
49
|
power_loop/core/runner.py
|
|
50
50
|
power_loop/core/state.py
|
|
51
51
|
power_loop/runtime/background.py
|
|
52
|
+
power_loop/runtime/bash_capture.py
|
|
52
53
|
power_loop/runtime/blackboard.py
|
|
53
54
|
power_loop/runtime/budget.py
|
|
54
55
|
power_loop/runtime/cancellation.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|