@animalabs/agent-framework 0.7.4 → 0.9.0
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.
- package/dist/src/agent.d.ts +10 -0
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +33 -3
- package/dist/src/agent.js.map +1 -1
- package/dist/src/code-execution/index.d.ts +1 -1
- package/dist/src/code-execution/index.d.ts.map +1 -1
- package/dist/src/code-execution/index.js.map +1 -1
- package/dist/src/code-execution/py-runner.d.ts +23 -1
- package/dist/src/code-execution/py-runner.d.ts.map +1 -1
- package/dist/src/code-execution/py-runner.js +40 -4
- package/dist/src/code-execution/py-runner.js.map +1 -1
- package/dist/src/code-execution/runtime-py.d.ts +15 -2
- package/dist/src/code-execution/runtime-py.d.ts.map +1 -1
- package/dist/src/code-execution/runtime-py.js +156 -7
- package/dist/src/code-execution/runtime-py.js.map +1 -1
- package/dist/src/code-execution/tool-definition.d.ts.map +1 -1
- package/dist/src/code-execution/tool-definition.js +27 -2
- package/dist/src/code-execution/tool-definition.js.map +1 -1
- package/dist/src/framework.d.ts +234 -5
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +1818 -188
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts +11 -0
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +66 -0
- package/dist/src/gate/event-gate.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcpl/capability-grant.d.ts +115 -0
- package/dist/src/mcpl/capability-grant.d.ts.map +1 -0
- package/dist/src/mcpl/capability-grant.js +291 -0
- package/dist/src/mcpl/capability-grant.js.map +1 -0
- package/dist/src/mcpl/capability-mask.d.ts +51 -0
- package/dist/src/mcpl/capability-mask.d.ts.map +1 -0
- package/dist/src/mcpl/capability-mask.js +190 -0
- package/dist/src/mcpl/capability-mask.js.map +1 -0
- package/dist/src/mcpl/channel-registry.d.ts +30 -2
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +216 -43
- package/dist/src/mcpl/channel-registry.js.map +1 -1
- package/dist/src/mcpl/checkpoint-manager.d.ts +8 -3
- package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -1
- package/dist/src/mcpl/checkpoint-manager.js +28 -8
- package/dist/src/mcpl/checkpoint-manager.js.map +1 -1
- package/dist/src/mcpl/errors.d.ts +6 -0
- package/dist/src/mcpl/errors.d.ts.map +1 -1
- package/dist/src/mcpl/errors.js +6 -0
- package/dist/src/mcpl/errors.js.map +1 -1
- package/dist/src/mcpl/feature-set-manager.d.ts +10 -1
- package/dist/src/mcpl/feature-set-manager.d.ts.map +1 -1
- package/dist/src/mcpl/feature-set-manager.js +45 -4
- package/dist/src/mcpl/feature-set-manager.js.map +1 -1
- package/dist/src/mcpl/hook-orchestrator.d.ts +10 -14
- package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -1
- package/dist/src/mcpl/hook-orchestrator.js +58 -67
- package/dist/src/mcpl/hook-orchestrator.js.map +1 -1
- package/dist/src/mcpl/index.d.ts +1 -1
- package/dist/src/mcpl/index.d.ts.map +1 -1
- package/dist/src/mcpl/index.js.map +1 -1
- package/dist/src/mcpl/prose-stream-router.d.ts +9 -0
- package/dist/src/mcpl/prose-stream-router.d.ts.map +1 -1
- package/dist/src/mcpl/prose-stream-router.js +16 -0
- package/dist/src/mcpl/prose-stream-router.js.map +1 -1
- package/dist/src/mcpl/push-handler.d.ts.map +1 -1
- package/dist/src/mcpl/push-handler.js +20 -2
- package/dist/src/mcpl/push-handler.js.map +1 -1
- package/dist/src/mcpl/server-connection.d.ts +93 -9
- package/dist/src/mcpl/server-connection.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.js +231 -32
- package/dist/src/mcpl/server-connection.js.map +1 -1
- package/dist/src/mcpl/server-registry.d.ts.map +1 -1
- package/dist/src/mcpl/server-registry.js +4 -3
- package/dist/src/mcpl/server-registry.js.map +1 -1
- package/dist/src/mcpl/tags.d.ts +24 -0
- package/dist/src/mcpl/tags.d.ts.map +1 -0
- package/dist/src/mcpl/tags.js +52 -0
- package/dist/src/mcpl/tags.js.map +1 -0
- package/dist/src/mcpl/transport.d.ts +1 -1
- package/dist/src/mcpl/transport.d.ts.map +1 -1
- package/dist/src/mcpl/transport.js +35 -7
- package/dist/src/mcpl/transport.js.map +1 -1
- package/dist/src/mcpl/types.d.ts +169 -64
- package/dist/src/mcpl/types.d.ts.map +1 -1
- package/dist/src/mcpl/types.js +16 -2
- package/dist/src/mcpl/types.js.map +1 -1
- package/dist/src/module-registry.d.ts +12 -0
- package/dist/src/module-registry.d.ts.map +1 -1
- package/dist/src/module-registry.js +26 -0
- package/dist/src/module-registry.js.map +1 -1
- package/dist/src/modules/workspace/index.d.ts +20 -0
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +48 -15
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/modules/workspace/sync.d.ts +4 -0
- package/dist/src/modules/workspace/sync.d.ts.map +1 -1
- package/dist/src/modules/workspace/sync.js +1 -1
- package/dist/src/modules/workspace/sync.js.map +1 -1
- package/dist/src/refusal-reactions.d.ts +27 -0
- package/dist/src/refusal-reactions.d.ts.map +1 -0
- package/dist/src/refusal-reactions.js +35 -0
- package/dist/src/refusal-reactions.js.map +1 -0
- package/dist/src/tool-result-history.d.ts +10 -0
- package/dist/src/tool-result-history.d.ts.map +1 -1
- package/dist/src/tool-result-history.js +16 -5
- package/dist/src/tool-result-history.js.map +1 -1
- package/dist/src/types/agent.d.ts +35 -0
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +26 -0
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/module.d.ts +22 -0
- package/dist/src/types/module.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +24 -0
- package/dist/src/types/trace.d.ts.map +1 -1
- package/dist/test/busy-agent-scheduler.test.js +1 -0
- package/dist/test/busy-agent-scheduler.test.js.map +1 -1
- package/dist/test/channel-registry-routing.test.js +38 -10
- package/dist/test/channel-registry-routing.test.js.map +1 -1
- package/dist/test/channel-registry-typing.test.js +10 -1
- package/dist/test/channel-registry-typing.test.js.map +1 -1
- package/dist/test/checkpoint-attribution.test.js +168 -8
- package/dist/test/checkpoint-attribution.test.js.map +1 -1
- package/dist/test/code-execution.test.js +327 -1
- package/dist/test/code-execution.test.js.map +1 -1
- package/dist/test/conversation-fork-injection-scoping.test.js +8 -3
- package/dist/test/conversation-fork-injection-scoping.test.js.map +1 -1
- package/dist/test/deferred-wake-integrity.test.d.ts +29 -0
- package/dist/test/deferred-wake-integrity.test.d.ts.map +1 -0
- package/dist/test/deferred-wake-integrity.test.js +320 -0
- package/dist/test/deferred-wake-integrity.test.js.map +1 -0
- package/dist/test/event-gate-selfwake.test.d.ts +15 -0
- package/dist/test/event-gate-selfwake.test.d.ts.map +1 -0
- package/dist/test/event-gate-selfwake.test.js +125 -0
- package/dist/test/event-gate-selfwake.test.js.map +1 -0
- package/dist/test/machine-close-provenance.test.d.ts +2 -0
- package/dist/test/machine-close-provenance.test.d.ts.map +1 -0
- package/dist/test/machine-close-provenance.test.js +116 -0
- package/dist/test/machine-close-provenance.test.js.map +1 -0
- package/dist/test/mcpl-access-provider.test.d.ts +2 -0
- package/dist/test/mcpl-access-provider.test.d.ts.map +1 -0
- package/dist/test/mcpl-access-provider.test.js +20 -0
- package/dist/test/mcpl-access-provider.test.js.map +1 -0
- package/dist/test/mcpl-awareness-barrier.test.js +10 -0
- package/dist/test/mcpl-awareness-barrier.test.js.map +1 -1
- package/dist/test/mcpl-capability-grant.test.d.ts +10 -0
- package/dist/test/mcpl-capability-grant.test.d.ts.map +1 -0
- package/dist/test/mcpl-capability-grant.test.js +109 -0
- package/dist/test/mcpl-capability-grant.test.js.map +1 -0
- package/dist/test/mcpl-capability-scoping.test.d.ts +2 -0
- package/dist/test/mcpl-capability-scoping.test.d.ts.map +1 -0
- package/dist/test/mcpl-capability-scoping.test.js +266 -0
- package/dist/test/mcpl-capability-scoping.test.js.map +1 -0
- package/dist/test/mcpl-gate-roundtrip.test.js +13 -0
- package/dist/test/mcpl-gate-roundtrip.test.js.map +1 -1
- package/dist/test/mcpl-list-status.test.d.ts +2 -0
- package/dist/test/mcpl-list-status.test.d.ts.map +1 -0
- package/dist/test/mcpl-list-status.test.js +78 -0
- package/dist/test/mcpl-list-status.test.js.map +1 -0
- package/dist/test/mcpl-manifest-changed.test.d.ts +2 -0
- package/dist/test/mcpl-manifest-changed.test.d.ts.map +1 -0
- package/dist/test/mcpl-manifest-changed.test.js +177 -0
- package/dist/test/mcpl-manifest-changed.test.js.map +1 -0
- package/dist/test/mcpl-reconnect-events.test.js +27 -2
- package/dist/test/mcpl-reconnect-events.test.js.map +1 -1
- package/dist/test/mcpl-reconnect-reregistration.test.js +53 -17
- package/dist/test/mcpl-reconnect-reregistration.test.js.map +1 -1
- package/dist/test/mcpl-request-timeout.test.js +1 -1
- package/dist/test/mcpl-request-timeout.test.js.map +1 -1
- package/dist/test/module-context-integration.test.d.ts +18 -0
- package/dist/test/module-context-integration.test.d.ts.map +1 -0
- package/dist/test/module-context-integration.test.js +181 -0
- package/dist/test/module-context-integration.test.js.map +1 -0
- package/dist/test/physical-window-restart.test.d.ts +14 -0
- package/dist/test/physical-window-restart.test.d.ts.map +1 -0
- package/dist/test/physical-window-restart.test.js +222 -0
- package/dist/test/physical-window-restart.test.js.map +1 -0
- package/dist/test/present-while-acting.test.js +270 -0
- package/dist/test/present-while-acting.test.js.map +1 -1
- package/dist/test/refusal-reaction-baseline.test.d.ts +2 -0
- package/dist/test/refusal-reaction-baseline.test.d.ts.map +1 -0
- package/dist/test/refusal-reaction-baseline.test.js +74 -0
- package/dist/test/refusal-reaction-baseline.test.js.map +1 -0
- package/dist/test/state-scaling-e2e.test.js +7 -1
- package/dist/test/state-scaling-e2e.test.js.map +1 -1
- package/dist/test/state-scaling.test.js +9 -1
- package/dist/test/state-scaling.test.js.map +1 -1
- package/dist/test/tool-result-spill.test.d.ts +13 -0
- package/dist/test/tool-result-spill.test.d.ts.map +1 -0
- package/dist/test/tool-result-spill.test.js +463 -0
- package/dist/test/tool-result-spill.test.js.map +1 -0
- package/dist/test/trunk-channel-routing.test.js +45 -0
- package/dist/test/trunk-channel-routing.test.js.map +1 -1
- package/dist/test/utils-surface.test.d.ts +2 -0
- package/dist/test/utils-surface.test.d.ts.map +1 -0
- package/dist/test/utils-surface.test.js +145 -0
- package/dist/test/utils-surface.test.js.map +1 -0
- package/dist/test/workspace-read-image.test.js +71 -0
- package/dist/test/workspace-read-image.test.js.map +1 -1
- package/dist/test/workspace-restore-order.test.d.ts +16 -0
- package/dist/test/workspace-restore-order.test.d.ts.map +1 -0
- package/dist/test/workspace-restore-order.test.js +140 -0
- package/dist/test/workspace-restore-order.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/agent.ts +37 -3
- package/src/code-execution/index.ts +1 -0
- package/src/code-execution/py-runner.ts +56 -4
- package/src/code-execution/runtime-py.ts +156 -7
- package/src/code-execution/tool-definition.ts +27 -2
- package/src/framework.ts +2080 -203
- package/src/gate/event-gate.ts +72 -0
- package/src/index.ts +1 -0
- package/src/mcpl/capability-grant.ts +319 -0
- package/src/mcpl/capability-mask.ts +228 -0
- package/src/mcpl/channel-registry.ts +265 -43
- package/src/mcpl/checkpoint-manager.ts +28 -8
- package/src/mcpl/errors.ts +7 -0
- package/src/mcpl/feature-set-manager.ts +50 -5
- package/src/mcpl/hook-orchestrator.ts +64 -86
- package/src/mcpl/index.ts +0 -2
- package/src/mcpl/prose-stream-router.ts +17 -0
- package/src/mcpl/push-handler.ts +18 -2
- package/src/mcpl/server-connection.ts +262 -34
- package/src/mcpl/server-registry.ts +4 -3
- package/src/mcpl/tags.ts +50 -0
- package/src/mcpl/transport.ts +37 -7
- package/src/mcpl/types.ts +187 -78
- package/src/module-registry.ts +34 -0
- package/src/modules/workspace/index.ts +49 -15
- package/src/modules/workspace/sync.ts +1 -1
- package/src/refusal-reactions.ts +37 -0
- package/src/tool-result-history.ts +17 -5
- package/src/types/agent.ts +36 -0
- package/src/types/framework.ts +27 -0
- package/src/types/module.ts +24 -0
- package/src/types/trace.ts +22 -0
|
@@ -12,17 +12,30 @@
|
|
|
12
12
|
* same message shape the managed runtime produces
|
|
13
13
|
* - interpreter globals persist across execs (container-reuse semantics)
|
|
14
14
|
*
|
|
15
|
+
* BACKGROUND MODE (model-authored daemons): when init carries
|
|
16
|
+
* `background: true`, the exec additionally gets:
|
|
17
|
+
* - `wake_agent(payload)` — async; reports the caller's line number (which
|
|
18
|
+
* indexes into the agent-authored script — self-correlation) and delivers
|
|
19
|
+
* the payload to the host, which injects it into the agent's context and
|
|
20
|
+
* triggers inference. Awaits a host ack so rate limiting backpressures
|
|
21
|
+
* inside the script instead of dropping wakes.
|
|
22
|
+
* - stdout/stderr tee'd line-buffered to `log_path` (agent-readable via
|
|
23
|
+
* their file tools) with an in-memory tail kept for the crash envelope.
|
|
24
|
+
*
|
|
15
25
|
* Embedded as a TS string because tsc does not copy non-TS assets to dist/;
|
|
16
26
|
* PyRunner materializes it to a temp file at spawn.
|
|
17
27
|
*
|
|
18
28
|
* Protocol (JSON lines):
|
|
19
|
-
* host -> py : {op:"init", tools:[{py_name,tool_name}], call_timeout_s
|
|
29
|
+
* host -> py : {op:"init", tools:[{py_name,tool_name}], call_timeout_s,
|
|
30
|
+
* background?, log_path?, tail_chars?}
|
|
20
31
|
* {op:"exec", id, code}
|
|
21
32
|
* {op:"tool_result", id, result}
|
|
33
|
+
* {op:"wake_ack", id, error?}
|
|
22
34
|
* {op:"cancel", id, reason?}
|
|
23
35
|
* py -> host : {op:"ready"}
|
|
24
36
|
* {op:"tool_call", id, exec_id, name, args}
|
|
25
|
-
* {op:"
|
|
37
|
+
* {op:"wake", id, exec_id, line, payload}
|
|
38
|
+
* {op:"exec_result", id, stdout, stderr, return_code, tail?}
|
|
26
39
|
*
|
|
27
40
|
* IMPORTANT: the python source below must not contain backticks or the
|
|
28
41
|
* sequence dollar+brace (TS template literal syntax). String.raw preserves
|
|
@@ -34,6 +47,7 @@ import asyncio
|
|
|
34
47
|
import inspect
|
|
35
48
|
import io
|
|
36
49
|
import json
|
|
50
|
+
import os
|
|
37
51
|
import sys
|
|
38
52
|
import threading
|
|
39
53
|
import traceback
|
|
@@ -42,6 +56,11 @@ PROTO_OUT = sys.stdout # protocol channel (real stdout)
|
|
|
42
56
|
REAL_STDERR = sys.stderr # runtime diagnostics outside execs
|
|
43
57
|
CALL_TIMEOUT_S = 270.0
|
|
44
58
|
OUTPUT_CAP_CHARS = 2_000_000
|
|
59
|
+
LOG_FILE_CAP_BYTES = 50_000_000
|
|
60
|
+
|
|
61
|
+
BACKGROUND = False
|
|
62
|
+
LOG_PATH = None
|
|
63
|
+
TAIL_CHARS = 4000
|
|
45
64
|
|
|
46
65
|
_send_lock = threading.Lock()
|
|
47
66
|
|
|
@@ -74,13 +93,78 @@ class CappedIO(io.StringIO):
|
|
|
74
93
|
return super().write(s)
|
|
75
94
|
|
|
76
95
|
|
|
96
|
+
class LogTee:
|
|
97
|
+
"""Background-mode writer: line-buffered file append + rolling tail.
|
|
98
|
+
|
|
99
|
+
The file is the agent-readable journal (their read/grep/shell tools work
|
|
100
|
+
on it); the tail rides the exec_result so the host can build a crash
|
|
101
|
+
envelope without re-reading the file.
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
def __init__(self, path, tail_chars):
|
|
105
|
+
self._fh = None
|
|
106
|
+
self._written = 0
|
|
107
|
+
self._tail = ""
|
|
108
|
+
self._tail_chars = tail_chars
|
|
109
|
+
self.truncated = False
|
|
110
|
+
if path:
|
|
111
|
+
try:
|
|
112
|
+
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
113
|
+
self._fh = open(path, "a", encoding="utf-8", errors="replace")
|
|
114
|
+
except Exception as exc:
|
|
115
|
+
REAL_STDERR.write("[pytc-runtime] cannot open log file: " + str(exc) + "\n")
|
|
116
|
+
REAL_STDERR.flush()
|
|
117
|
+
|
|
118
|
+
def write(self, s):
|
|
119
|
+
if not isinstance(s, str):
|
|
120
|
+
s = str(s)
|
|
121
|
+
self._tail = (self._tail + s)[-self._tail_chars:]
|
|
122
|
+
if self._fh is not None and not self.truncated:
|
|
123
|
+
if self._written + len(s) > LOG_FILE_CAP_BYTES:
|
|
124
|
+
self.truncated = True
|
|
125
|
+
try:
|
|
126
|
+
self._fh.write("\n[log capped at " + str(LOG_FILE_CAP_BYTES) + " bytes]\n")
|
|
127
|
+
self._fh.flush()
|
|
128
|
+
except Exception:
|
|
129
|
+
pass
|
|
130
|
+
else:
|
|
131
|
+
try:
|
|
132
|
+
self._fh.write(s)
|
|
133
|
+
if "\n" in s:
|
|
134
|
+
self._fh.flush()
|
|
135
|
+
self._written += len(s)
|
|
136
|
+
except Exception:
|
|
137
|
+
pass
|
|
138
|
+
return len(s)
|
|
139
|
+
|
|
140
|
+
def flush(self):
|
|
141
|
+
if self._fh is not None:
|
|
142
|
+
try:
|
|
143
|
+
self._fh.flush()
|
|
144
|
+
except Exception:
|
|
145
|
+
pass
|
|
146
|
+
|
|
147
|
+
def close(self):
|
|
148
|
+
if self._fh is not None:
|
|
149
|
+
try:
|
|
150
|
+
self._fh.close()
|
|
151
|
+
except Exception:
|
|
152
|
+
pass
|
|
153
|
+
self._fh = None
|
|
154
|
+
|
|
155
|
+
def tail(self):
|
|
156
|
+
return self._tail
|
|
157
|
+
|
|
158
|
+
|
|
77
159
|
# Persistent interpreter state (mirrors container reuse: variables survive
|
|
78
160
|
# between exec calls until the host reclaims the interpreter).
|
|
79
161
|
SCRIPT_GLOBALS = {"__name__": "__main__", "__builtins__": __builtins__}
|
|
80
162
|
_injected_py_names = set()
|
|
81
163
|
|
|
82
164
|
_pending_tool_futures = {}
|
|
165
|
+
_pending_wake_futures = {}
|
|
83
166
|
_next_tool_call_id = 0
|
|
167
|
+
_next_wake_id = 0
|
|
84
168
|
_current_exec_id = None
|
|
85
169
|
_current_exec_task = None
|
|
86
170
|
|
|
@@ -115,7 +199,6 @@ def _make_tool_fn(tool_name, py_name):
|
|
|
115
199
|
)
|
|
116
200
|
finally:
|
|
117
201
|
_pending_tool_futures.pop(call_id, None)
|
|
118
|
-
|
|
119
202
|
tool_fn.__name__ = py_name
|
|
120
203
|
tool_fn.__qualname__ = py_name
|
|
121
204
|
tool_fn.__doc__ = (
|
|
@@ -125,11 +208,47 @@ def _make_tool_fn(tool_name, py_name):
|
|
|
125
208
|
return tool_fn
|
|
126
209
|
|
|
127
210
|
|
|
211
|
+
async def wake_agent(payload=None):
|
|
212
|
+
"""Wake the agent: deliver payload into their context and trigger a turn.
|
|
213
|
+
|
|
214
|
+
Reports the caller's line number (indexes into the script the agent
|
|
215
|
+
wrote). Awaits the host ack — rate limiting backpressures here rather
|
|
216
|
+
than dropping wakes. Raises RuntimeError when the host refuses (wake cap
|
|
217
|
+
exceeded, script cancelled).
|
|
218
|
+
"""
|
|
219
|
+
global _next_wake_id
|
|
220
|
+
frame = inspect.currentframe()
|
|
221
|
+
line = frame.f_back.f_lineno if frame is not None and frame.f_back is not None else -1
|
|
222
|
+
_next_wake_id += 1
|
|
223
|
+
wake_id = "w" + str(_next_wake_id)
|
|
224
|
+
fut = asyncio.get_running_loop().create_future()
|
|
225
|
+
_pending_wake_futures[wake_id] = fut
|
|
226
|
+
send({
|
|
227
|
+
"op": "wake",
|
|
228
|
+
"id": wake_id,
|
|
229
|
+
"exec_id": _current_exec_id,
|
|
230
|
+
"line": line,
|
|
231
|
+
"payload": payload,
|
|
232
|
+
})
|
|
233
|
+
try:
|
|
234
|
+
error = await fut
|
|
235
|
+
if error:
|
|
236
|
+
raise RuntimeError("wake_agent refused by host: " + str(error))
|
|
237
|
+
return None
|
|
238
|
+
finally:
|
|
239
|
+
_pending_wake_futures.pop(wake_id, None)
|
|
240
|
+
|
|
241
|
+
|
|
128
242
|
def handle_init(msg):
|
|
129
|
-
global CALL_TIMEOUT_S
|
|
243
|
+
global CALL_TIMEOUT_S, BACKGROUND, LOG_PATH, TAIL_CHARS
|
|
130
244
|
timeout = msg.get("call_timeout_s")
|
|
131
245
|
if isinstance(timeout, (int, float)) and timeout > 0:
|
|
132
246
|
CALL_TIMEOUT_S = float(timeout)
|
|
247
|
+
BACKGROUND = bool(msg.get("background"))
|
|
248
|
+
LOG_PATH = msg.get("log_path") or None
|
|
249
|
+
tail = msg.get("tail_chars")
|
|
250
|
+
if isinstance(tail, int) and tail > 0:
|
|
251
|
+
TAIL_CHARS = tail
|
|
133
252
|
|
|
134
253
|
# Remove functions injected by a previous init that are no longer present
|
|
135
254
|
# (tool list changed) without touching user-defined globals.
|
|
@@ -151,12 +270,22 @@ def handle_init(msg):
|
|
|
151
270
|
_injected_py_names.update(new_py_names)
|
|
152
271
|
# Exact-name escape hatch: tools["mcpl--server--tool"]({...})
|
|
153
272
|
SCRIPT_GLOBALS["tools"] = tools_dict
|
|
273
|
+
# The doorbell exists only in background mode — a foreground script's
|
|
274
|
+
# agent is already awake (mid-turn).
|
|
275
|
+
if BACKGROUND:
|
|
276
|
+
SCRIPT_GLOBALS["wake_agent"] = wake_agent
|
|
277
|
+
else:
|
|
278
|
+
SCRIPT_GLOBALS.pop("wake_agent", None)
|
|
154
279
|
|
|
155
280
|
|
|
156
281
|
async def _run_script(exec_id, code):
|
|
157
282
|
global _current_exec_id, _current_exec_task
|
|
158
|
-
|
|
159
|
-
|
|
283
|
+
if BACKGROUND:
|
|
284
|
+
out = LogTee(LOG_PATH, TAIL_CHARS)
|
|
285
|
+
err = out # interleave, terminal-style; tail is shared
|
|
286
|
+
else:
|
|
287
|
+
out = CappedIO(OUTPUT_CAP_CHARS)
|
|
288
|
+
err = CappedIO(OUTPUT_CAP_CHARS)
|
|
160
289
|
old_out, old_err, old_in = sys.stdout, sys.stderr, sys.stdin
|
|
161
290
|
sys.stdout, sys.stderr = out, err
|
|
162
291
|
sys.stdin = io.StringIO("") # input() must not steal the protocol channel
|
|
@@ -176,11 +305,27 @@ async def _run_script(exec_id, code):
|
|
|
176
305
|
sys.stdout, sys.stderr, sys.stdin = old_out, old_err, old_in
|
|
177
306
|
_current_exec_id = None
|
|
178
307
|
_current_exec_task = None
|
|
179
|
-
# Fail any tool futures still pending: their exec is gone.
|
|
180
308
|
for fut in list(_pending_tool_futures.values()):
|
|
181
309
|
if not fut.done():
|
|
182
310
|
fut.cancel()
|
|
183
311
|
_pending_tool_futures.clear()
|
|
312
|
+
for fut in list(_pending_wake_futures.values()):
|
|
313
|
+
if not fut.done():
|
|
314
|
+
fut.cancel()
|
|
315
|
+
_pending_wake_futures.clear()
|
|
316
|
+
|
|
317
|
+
if BACKGROUND:
|
|
318
|
+
out.flush()
|
|
319
|
+
out.close()
|
|
320
|
+
send({
|
|
321
|
+
"op": "exec_result",
|
|
322
|
+
"id": exec_id,
|
|
323
|
+
"stdout": "",
|
|
324
|
+
"stderr": "",
|
|
325
|
+
"tail": out.tail(),
|
|
326
|
+
"return_code": return_code,
|
|
327
|
+
})
|
|
328
|
+
return
|
|
184
329
|
|
|
185
330
|
stdout_text = out.getvalue()
|
|
186
331
|
if out.truncated:
|
|
@@ -244,6 +389,10 @@ async def main():
|
|
|
244
389
|
fut = _pending_tool_futures.get(msg.get("id"))
|
|
245
390
|
if fut is not None and not fut.done():
|
|
246
391
|
fut.set_result(str(msg.get("result", "")))
|
|
392
|
+
elif op == "wake_ack":
|
|
393
|
+
fut = _pending_wake_futures.get(msg.get("id"))
|
|
394
|
+
if fut is not None and not fut.done():
|
|
395
|
+
fut.set_result(msg.get("error") or None)
|
|
247
396
|
elif op == "cancel":
|
|
248
397
|
if _current_exec_task is not None and not _current_exec_task.done():
|
|
249
398
|
_current_exec_task.cancel()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-py.js","sourceRoot":"","sources":["../../../src/code-execution/runtime-py.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"runtime-py.js","sourceRoot":"","sources":["../../../src/code-execution/runtime-py.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,MAAM,CAAC,MAAM,qBAAqB,GAAW,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiXtD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-definition.d.ts","sourceRoot":"","sources":["../../../src/code-execution/tool-definition.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,eAAO,MAAM,wBAAwB,mBAAmB,CAAC;AAEzD,wBAAgB,gCAAgC,CAAC,IAAI,CAAC,EAAE;IACtD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,GAAG,cAAc,
|
|
1
|
+
{"version":3,"file":"tool-definition.d.ts","sourceRoot":"","sources":["../../../src/code-execution/tool-definition.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,eAAO,MAAM,wBAAwB,mBAAmB,CAAC;AAEzD,wBAAgB,gCAAgC,CAAC,IAAI,CAAC,EAAE;IACtD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,GAAG,cAAc,CA6DjB"}
|
|
@@ -31,7 +31,19 @@ export function buildCodeExecutionToolDefinition(opts) {
|
|
|
31
31
|
'Use this when fanning out across many items, looping over tool calls, or when tool ' +
|
|
32
32
|
'results are large and you only need a slice or summary. Call tools directly (not via ' +
|
|
33
33
|
'code) when a single call answers the question or when you need to reason about each ' +
|
|
34
|
-
'result before deciding the next step.'
|
|
34
|
+
'result before deciding the next step. ' +
|
|
35
|
+
'BACKGROUND MODE: pass background=true to run the script as a detached watcher that ' +
|
|
36
|
+
'outlives this turn — the tool returns immediately with a script_id and you can end ' +
|
|
37
|
+
'your turn (e.g. sleep). Inside a background script, await wake_agent(payload) wakes ' +
|
|
38
|
+
'you: the payload plus provenance (script id, the line number in your script, elapsed ' +
|
|
39
|
+
'time) is delivered into your context and starts a turn for you. A script that ends ' +
|
|
40
|
+
'without calling wake_agent wakes nobody — that silence is the point (poll cheaply, ' +
|
|
41
|
+
'wake only on signal). If your background script CRASHES you are woken with the error. ' +
|
|
42
|
+
'Its print() output streams to a workspace log file you can read any time. Wakes are ' +
|
|
43
|
+
'rate-limited (early wakes are delayed, not dropped) and capped per script. ' +
|
|
44
|
+
'CAUTION: background scripts die silently if the host process restarts — for a wake ' +
|
|
45
|
+
'you absolutely must not miss, also arm a wake rule as backup. ' +
|
|
46
|
+
'Manage your scripts with {"action": "list"} and {"action": "cancel", "script_id": "..."}.',
|
|
35
47
|
inputSchema: {
|
|
36
48
|
type: 'object',
|
|
37
49
|
properties: {
|
|
@@ -39,8 +51,21 @@ export function buildCodeExecutionToolDefinition(opts) {
|
|
|
39
51
|
type: 'string',
|
|
40
52
|
description: 'Python code to execute. Top-level await is allowed.',
|
|
41
53
|
},
|
|
54
|
+
background: {
|
|
55
|
+
type: 'boolean',
|
|
56
|
+
description: 'Run detached as a background watcher with wake_agent() available (default false).',
|
|
57
|
+
},
|
|
58
|
+
action: {
|
|
59
|
+
type: 'string',
|
|
60
|
+
enum: ['run', 'list', 'cancel'],
|
|
61
|
+
description: 'run (default) executes `code`; list shows your background scripts; cancel stops one.',
|
|
62
|
+
},
|
|
63
|
+
script_id: {
|
|
64
|
+
type: 'string',
|
|
65
|
+
description: 'Background script id (for action: cancel).',
|
|
66
|
+
},
|
|
42
67
|
},
|
|
43
|
-
required: [
|
|
68
|
+
required: [],
|
|
44
69
|
},
|
|
45
70
|
};
|
|
46
71
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-definition.js","sourceRoot":"","sources":["../../../src/code-execution/tool-definition.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,MAAM,CAAC,MAAM,wBAAwB,GAAG,gBAAgB,CAAC;AAEzD,MAAM,UAAU,gCAAgC,CAAC,IAGhD;IACC,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,aAAa,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;IACvF,MAAM,kBAAkB,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,iBAAiB,IAAI,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;IACnF,OAAO;QACL,IAAI,EAAE,wBAAwB;QAC9B,WAAW,EACT,mEAAmE;YACnE,kFAAkF;YAClF,8EAA8E;YAC9E,2CAA2C;YAC3C,0FAA0F;YAC1F,oEAAoE;YACpE,sFAAsF;YACtF,0FAA0F;YAC1F,6FAA6F;YAC7F,8EAA8E;YAC9E,yFAAyF;YACzF,0FAA0F;YAC1F,uFAAuF;YACvF,iCAAiC,WAAW,8CAA8C;YAC1F,oBAAoB,kBAAkB,2CAA2C;YACjF,qFAAqF;YACrF,uFAAuF;YACvF,sFAAsF;YACtF,
|
|
1
|
+
{"version":3,"file":"tool-definition.js","sourceRoot":"","sources":["../../../src/code-execution/tool-definition.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,MAAM,CAAC,MAAM,wBAAwB,GAAG,gBAAgB,CAAC;AAEzD,MAAM,UAAU,gCAAgC,CAAC,IAGhD;IACC,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,aAAa,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;IACvF,MAAM,kBAAkB,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,iBAAiB,IAAI,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;IACnF,OAAO;QACL,IAAI,EAAE,wBAAwB;QAC9B,WAAW,EACT,mEAAmE;YACnE,kFAAkF;YAClF,8EAA8E;YAC9E,2CAA2C;YAC3C,0FAA0F;YAC1F,oEAAoE;YACpE,sFAAsF;YACtF,0FAA0F;YAC1F,6FAA6F;YAC7F,8EAA8E;YAC9E,yFAAyF;YACzF,0FAA0F;YAC1F,uFAAuF;YACvF,iCAAiC,WAAW,8CAA8C;YAC1F,oBAAoB,kBAAkB,2CAA2C;YACjF,qFAAqF;YACrF,uFAAuF;YACvF,sFAAsF;YACtF,wCAAwC;YACxC,qFAAqF;YACrF,qFAAqF;YACrF,sFAAsF;YACtF,uFAAuF;YACvF,qFAAqF;YACrF,qFAAqF;YACrF,wFAAwF;YACxF,sFAAsF;YACtF,6EAA6E;YAC7E,qFAAqF;YACrF,gEAAgE;YAChE,2FAA2F;QAC7F,WAAW,EAAE;YACX,IAAI,EAAE,QAAiB;YACvB,UAAU,EAAE;gBACV,IAAI,EAAE;oBACJ,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,qDAAqD;iBACnE;gBACD,UAAU,EAAE;oBACV,IAAI,EAAE,SAAS;oBACf,WAAW,EAAE,mFAAmF;iBACjG;gBACD,MAAM,EAAE;oBACN,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC;oBAC/B,WAAW,EAAE,sFAAsF;iBACpG;gBACD,SAAS,EAAE;oBACT,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,4CAA4C;iBAC1D;aACF;YACD,QAAQ,EAAE,EAAE;SACb;KACF,CAAC;AACJ,CAAC"}
|