@cloudwarriors-ai/rlm 0.1.5
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/README.md +208 -0
- package/dist/application/index.d.ts +4 -0
- package/dist/application/index.d.ts.map +1 -0
- package/dist/application/index.js +4 -0
- package/dist/application/index.js.map +1 -0
- package/dist/application/query-handler.d.ts +49 -0
- package/dist/application/query-handler.d.ts.map +1 -0
- package/dist/application/query-handler.js +311 -0
- package/dist/application/query-handler.js.map +1 -0
- package/dist/application/rlm-service.d.ts +68 -0
- package/dist/application/rlm-service.d.ts.map +1 -0
- package/dist/application/rlm-service.js +132 -0
- package/dist/application/rlm-service.js.map +1 -0
- package/dist/application/session-manager.d.ts +70 -0
- package/dist/application/session-manager.d.ts.map +1 -0
- package/dist/application/session-manager.js +237 -0
- package/dist/application/session-manager.js.map +1 -0
- package/dist/cli/commands/config.d.ts +34 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +157 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/index.d.ts +4 -0
- package/dist/cli/commands/index.d.ts.map +1 -0
- package/dist/cli/commands/index.js +4 -0
- package/dist/cli/commands/index.js.map +1 -0
- package/dist/cli/commands/query.d.ts +26 -0
- package/dist/cli/commands/query.d.ts.map +1 -0
- package/dist/cli/commands/query.js +90 -0
- package/dist/cli/commands/query.js.map +1 -0
- package/dist/cli/commands/session.d.ts +40 -0
- package/dist/cli/commands/session.d.ts.map +1 -0
- package/dist/cli/commands/session.js +55 -0
- package/dist/cli/commands/session.js.map +1 -0
- package/dist/cli/config-loader.d.ts +63 -0
- package/dist/cli/config-loader.d.ts.map +1 -0
- package/dist/cli/config-loader.js +94 -0
- package/dist/cli/config-loader.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +120 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/output/formatter.d.ts +24 -0
- package/dist/cli/output/formatter.d.ts.map +1 -0
- package/dist/cli/output/formatter.js +196 -0
- package/dist/cli/output/formatter.js.map +1 -0
- package/dist/cli/output/index.d.ts +3 -0
- package/dist/cli/output/index.d.ts.map +1 -0
- package/dist/cli/output/index.js +3 -0
- package/dist/cli/output/index.js.map +1 -0
- package/dist/cli/output/progress.d.ts +60 -0
- package/dist/cli/output/progress.d.ts.map +1 -0
- package/dist/cli/output/progress.js +142 -0
- package/dist/cli/output/progress.js.map +1 -0
- package/dist/domain/errors/base-error.d.ts +17 -0
- package/dist/domain/errors/base-error.d.ts.map +1 -0
- package/dist/domain/errors/base-error.js +29 -0
- package/dist/domain/errors/base-error.js.map +1 -0
- package/dist/domain/errors/execution-error.d.ts +61 -0
- package/dist/domain/errors/execution-error.d.ts.map +1 -0
- package/dist/domain/errors/execution-error.js +86 -0
- package/dist/domain/errors/execution-error.js.map +1 -0
- package/dist/domain/errors/index.d.ts +14 -0
- package/dist/domain/errors/index.d.ts.map +1 -0
- package/dist/domain/errors/index.js +26 -0
- package/dist/domain/errors/index.js.map +1 -0
- package/dist/domain/errors/limit-exceeded.d.ts +38 -0
- package/dist/domain/errors/limit-exceeded.d.ts.map +1 -0
- package/dist/domain/errors/limit-exceeded.js +71 -0
- package/dist/domain/errors/limit-exceeded.js.map +1 -0
- package/dist/domain/errors/llm-error.d.ts +60 -0
- package/dist/domain/errors/llm-error.d.ts.map +1 -0
- package/dist/domain/errors/llm-error.js +92 -0
- package/dist/domain/errors/llm-error.js.map +1 -0
- package/dist/domain/errors/validation-error.d.ts +58 -0
- package/dist/domain/errors/validation-error.d.ts.map +1 -0
- package/dist/domain/errors/validation-error.js +81 -0
- package/dist/domain/errors/validation-error.js.map +1 -0
- package/dist/domain/interfaces/code-executor.d.ts +98 -0
- package/dist/domain/interfaces/code-executor.d.ts.map +1 -0
- package/dist/domain/interfaces/code-executor.js +2 -0
- package/dist/domain/interfaces/code-executor.js.map +1 -0
- package/dist/domain/interfaces/event-emitter.d.ts +137 -0
- package/dist/domain/interfaces/event-emitter.d.ts.map +1 -0
- package/dist/domain/interfaces/event-emitter.js +2 -0
- package/dist/domain/interfaces/event-emitter.js.map +1 -0
- package/dist/domain/interfaces/index.d.ts +5 -0
- package/dist/domain/interfaces/index.d.ts.map +1 -0
- package/dist/domain/interfaces/index.js +2 -0
- package/dist/domain/interfaces/index.js.map +1 -0
- package/dist/domain/interfaces/llm-provider.d.ts +64 -0
- package/dist/domain/interfaces/llm-provider.d.ts.map +1 -0
- package/dist/domain/interfaces/llm-provider.js +2 -0
- package/dist/domain/interfaces/llm-provider.js.map +1 -0
- package/dist/domain/interfaces/session-store.d.ts +65 -0
- package/dist/domain/interfaces/session-store.d.ts.map +1 -0
- package/dist/domain/interfaces/session-store.js +2 -0
- package/dist/domain/interfaces/session-store.js.map +1 -0
- package/dist/domain/services/context-chunker.d.ts +43 -0
- package/dist/domain/services/context-chunker.d.ts.map +1 -0
- package/dist/domain/services/context-chunker.js +152 -0
- package/dist/domain/services/context-chunker.js.map +1 -0
- package/dist/domain/services/cost-calculator.d.ts +63 -0
- package/dist/domain/services/cost-calculator.d.ts.map +1 -0
- package/dist/domain/services/cost-calculator.js +121 -0
- package/dist/domain/services/cost-calculator.js.map +1 -0
- package/dist/domain/services/index.d.ts +5 -0
- package/dist/domain/services/index.d.ts.map +1 -0
- package/dist/domain/services/index.js +9 -0
- package/dist/domain/services/index.js.map +1 -0
- package/dist/domain/services/limit-checker.d.ts +54 -0
- package/dist/domain/services/limit-checker.d.ts.map +1 -0
- package/dist/domain/services/limit-checker.js +146 -0
- package/dist/domain/services/limit-checker.js.map +1 -0
- package/dist/domain/services/result-aggregator.d.ts +49 -0
- package/dist/domain/services/result-aggregator.d.ts.map +1 -0
- package/dist/domain/services/result-aggregator.js +131 -0
- package/dist/domain/services/result-aggregator.js.map +1 -0
- package/dist/domain/types/config.d.ts +41 -0
- package/dist/domain/types/config.d.ts.map +1 -0
- package/dist/domain/types/config.js +22 -0
- package/dist/domain/types/config.js.map +1 -0
- package/dist/domain/types/context.d.ts +64 -0
- package/dist/domain/types/context.d.ts.map +1 -0
- package/dist/domain/types/context.js +20 -0
- package/dist/domain/types/context.js.map +1 -0
- package/dist/domain/types/index.d.ts +5 -0
- package/dist/domain/types/index.d.ts.map +1 -0
- package/dist/domain/types/index.js +9 -0
- package/dist/domain/types/index.js.map +1 -0
- package/dist/domain/types/result.d.ts +137 -0
- package/dist/domain/types/result.d.ts.map +1 -0
- package/dist/domain/types/result.js +27 -0
- package/dist/domain/types/result.js.map +1 -0
- package/dist/domain/types/session.d.ts +74 -0
- package/dist/domain/types/session.d.ts.map +1 -0
- package/dist/domain/types/session.js +31 -0
- package/dist/domain/types/session.js.map +1 -0
- package/dist/factory/create-rlm.d.ts +77 -0
- package/dist/factory/create-rlm.d.ts.map +1 -0
- package/dist/factory/create-rlm.js +82 -0
- package/dist/factory/create-rlm.js.map +1 -0
- package/dist/factory/default-config.d.ts +27 -0
- package/dist/factory/default-config.d.ts.map +1 -0
- package/dist/factory/default-config.js +98 -0
- package/dist/factory/default-config.js.map +1 -0
- package/dist/factory/index.d.ts +3 -0
- package/dist/factory/index.d.ts.map +1 -0
- package/dist/factory/index.js +3 -0
- package/dist/factory/index.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/infrastructure/events/event-types.d.ts +35 -0
- package/dist/infrastructure/events/event-types.d.ts.map +1 -0
- package/dist/infrastructure/events/event-types.js +44 -0
- package/dist/infrastructure/events/event-types.js.map +1 -0
- package/dist/infrastructure/events/index.d.ts +3 -0
- package/dist/infrastructure/events/index.d.ts.map +1 -0
- package/dist/infrastructure/events/index.js +3 -0
- package/dist/infrastructure/events/index.js.map +1 -0
- package/dist/infrastructure/events/node-emitter.d.ts +72 -0
- package/dist/infrastructure/events/node-emitter.d.ts.map +1 -0
- package/dist/infrastructure/events/node-emitter.js +125 -0
- package/dist/infrastructure/events/node-emitter.js.map +1 -0
- package/dist/infrastructure/llm/index.d.ts +3 -0
- package/dist/infrastructure/llm/index.d.ts.map +1 -0
- package/dist/infrastructure/llm/index.js +3 -0
- package/dist/infrastructure/llm/index.js.map +1 -0
- package/dist/infrastructure/llm/openrouter-provider.d.ts +35 -0
- package/dist/infrastructure/llm/openrouter-provider.d.ts.map +1 -0
- package/dist/infrastructure/llm/openrouter-provider.js +158 -0
- package/dist/infrastructure/llm/openrouter-provider.js.map +1 -0
- package/dist/infrastructure/llm/prompts/code-gen-prompt.d.ts +21 -0
- package/dist/infrastructure/llm/prompts/code-gen-prompt.d.ts.map +1 -0
- package/dist/infrastructure/llm/prompts/code-gen-prompt.js +78 -0
- package/dist/infrastructure/llm/prompts/code-gen-prompt.js.map +1 -0
- package/dist/infrastructure/llm/prompts/error-recovery-prompt.d.ts +24 -0
- package/dist/infrastructure/llm/prompts/error-recovery-prompt.d.ts.map +1 -0
- package/dist/infrastructure/llm/prompts/error-recovery-prompt.js +70 -0
- package/dist/infrastructure/llm/prompts/error-recovery-prompt.js.map +1 -0
- package/dist/infrastructure/llm/prompts/index.d.ts +4 -0
- package/dist/infrastructure/llm/prompts/index.d.ts.map +1 -0
- package/dist/infrastructure/llm/prompts/index.js +4 -0
- package/dist/infrastructure/llm/prompts/index.js.map +1 -0
- package/dist/infrastructure/llm/prompts/system-prompt.d.ts +12 -0
- package/dist/infrastructure/llm/prompts/system-prompt.d.ts.map +1 -0
- package/dist/infrastructure/llm/prompts/system-prompt.js +96 -0
- package/dist/infrastructure/llm/prompts/system-prompt.js.map +1 -0
- package/dist/infrastructure/persistence/index.d.ts +3 -0
- package/dist/infrastructure/persistence/index.d.ts.map +1 -0
- package/dist/infrastructure/persistence/index.js +3 -0
- package/dist/infrastructure/persistence/index.js.map +1 -0
- package/dist/infrastructure/persistence/memory-store.d.ts +24 -0
- package/dist/infrastructure/persistence/memory-store.d.ts.map +1 -0
- package/dist/infrastructure/persistence/memory-store.js +71 -0
- package/dist/infrastructure/persistence/memory-store.js.map +1 -0
- package/dist/infrastructure/persistence/schema.d.ts +120 -0
- package/dist/infrastructure/persistence/schema.d.ts.map +1 -0
- package/dist/infrastructure/persistence/schema.js +130 -0
- package/dist/infrastructure/persistence/schema.js.map +1 -0
- package/dist/infrastructure/sandbox/ast-validator.d.ts +23 -0
- package/dist/infrastructure/sandbox/ast-validator.d.ts.map +1 -0
- package/dist/infrastructure/sandbox/ast-validator.js +249 -0
- package/dist/infrastructure/sandbox/ast-validator.js.map +1 -0
- package/dist/infrastructure/sandbox/index.d.ts +4 -0
- package/dist/infrastructure/sandbox/index.d.ts.map +1 -0
- package/dist/infrastructure/sandbox/index.js +4 -0
- package/dist/infrastructure/sandbox/index.js.map +1 -0
- package/dist/infrastructure/sandbox/prelude/rlm_prelude.py +376 -0
- package/dist/infrastructure/sandbox/process-manager.d.ts +98 -0
- package/dist/infrastructure/sandbox/process-manager.d.ts.map +1 -0
- package/dist/infrastructure/sandbox/process-manager.js +186 -0
- package/dist/infrastructure/sandbox/process-manager.js.map +1 -0
- package/dist/infrastructure/sandbox/python-executor.d.ts +29 -0
- package/dist/infrastructure/sandbox/python-executor.d.ts.map +1 -0
- package/dist/infrastructure/sandbox/python-executor.js +182 -0
- package/dist/infrastructure/sandbox/python-executor.js.map +1 -0
- package/package.json +65 -0
- package/src/infrastructure/sandbox/prelude/rlm_prelude.py +376 -0
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
RLM Python Prelude
|
|
4
|
+
|
|
5
|
+
This module provides the runtime environment for RLM code execution.
|
|
6
|
+
It defines the special functions available to user code and handles
|
|
7
|
+
communication with the Node.js parent process.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import sys
|
|
11
|
+
import json
|
|
12
|
+
import builtins
|
|
13
|
+
from typing import Any, Optional
|
|
14
|
+
|
|
15
|
+
# Store for context variables
|
|
16
|
+
_context_store: dict[str, str] = {}
|
|
17
|
+
|
|
18
|
+
# Result storage
|
|
19
|
+
_result: Optional[str] = None
|
|
20
|
+
|
|
21
|
+
# Command counter for tracking
|
|
22
|
+
_command_id: int = 0
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _send_command(command_type: str, payload: Any) -> None:
|
|
26
|
+
"""Send a command to the Node.js parent process."""
|
|
27
|
+
global _command_id
|
|
28
|
+
_command_id += 1
|
|
29
|
+
command = {
|
|
30
|
+
"id": _command_id,
|
|
31
|
+
"type": command_type,
|
|
32
|
+
"payload": payload
|
|
33
|
+
}
|
|
34
|
+
print(f"__COMMAND__:{json.dumps(command)}", flush=True)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _wait_for_response() -> Any:
|
|
38
|
+
"""Wait for a response from the Node.js parent process."""
|
|
39
|
+
while True:
|
|
40
|
+
line = sys.stdin.readline()
|
|
41
|
+
if not line:
|
|
42
|
+
raise RuntimeError("Parent process closed stdin")
|
|
43
|
+
|
|
44
|
+
line = line.strip()
|
|
45
|
+
if line.startswith("__RESPONSE__:"):
|
|
46
|
+
try:
|
|
47
|
+
return json.loads(line[len("__RESPONSE__:"):])
|
|
48
|
+
except json.JSONDecodeError as e:
|
|
49
|
+
raise RuntimeError(f"Invalid response JSON: {e}")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def llm_query(query: str, *context_vars: str) -> str:
|
|
53
|
+
"""
|
|
54
|
+
Make a recursive LLM query.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
query: The question or task for the LLM
|
|
58
|
+
*context_vars: Variable names or string values to include as context
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
The LLM's response as a string
|
|
62
|
+
|
|
63
|
+
Example:
|
|
64
|
+
result = llm_query("Summarize this text", "context")
|
|
65
|
+
result = llm_query("What are the main points?", chunk1, chunk2)
|
|
66
|
+
"""
|
|
67
|
+
# Resolve context variables
|
|
68
|
+
context_values = []
|
|
69
|
+
for var in context_vars:
|
|
70
|
+
if var in _context_store:
|
|
71
|
+
context_values.append(_context_store[var])
|
|
72
|
+
elif isinstance(var, str):
|
|
73
|
+
# Treat as literal string value
|
|
74
|
+
context_values.append(var)
|
|
75
|
+
else:
|
|
76
|
+
raise ValueError(f"Context variable not found: {var}")
|
|
77
|
+
|
|
78
|
+
# Send the query command
|
|
79
|
+
_send_command("llm_query", {
|
|
80
|
+
"query": query,
|
|
81
|
+
"context": context_values
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
# Wait for response
|
|
85
|
+
response = _wait_for_response()
|
|
86
|
+
|
|
87
|
+
if "error" in response:
|
|
88
|
+
raise RuntimeError(f"LLM query failed: {response['error']}")
|
|
89
|
+
|
|
90
|
+
return response.get("result", "")
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def set_result(result: str) -> None:
|
|
94
|
+
"""
|
|
95
|
+
Set the final result of the RLM execution.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
result: The final answer/result to return
|
|
99
|
+
|
|
100
|
+
Example:
|
|
101
|
+
set_result("The analysis shows three main points...")
|
|
102
|
+
"""
|
|
103
|
+
global _result
|
|
104
|
+
_result = str(result)
|
|
105
|
+
_send_command("set_result", {"result": _result})
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def set_variable(name: str, value: str) -> None:
|
|
109
|
+
"""
|
|
110
|
+
Store a variable for use in subsequent code or queries.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
name: Variable name (valid Python identifier)
|
|
114
|
+
value: Value to store (will be converted to string)
|
|
115
|
+
|
|
116
|
+
Example:
|
|
117
|
+
set_variable("summary", "Key findings from chunk 1...")
|
|
118
|
+
"""
|
|
119
|
+
if not name.isidentifier():
|
|
120
|
+
raise ValueError(f"Invalid variable name: {name}")
|
|
121
|
+
|
|
122
|
+
_context_store[name] = str(value)
|
|
123
|
+
_send_command("set_variable", {"name": name, "value": str(value)})
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def chunk_text(text: str, chunk_size: int = 10000, overlap: int = 500) -> list[str]:
|
|
127
|
+
"""
|
|
128
|
+
Split text into overlapping chunks.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
text: The text to split
|
|
132
|
+
chunk_size: Maximum characters per chunk
|
|
133
|
+
overlap: Number of characters to overlap between chunks
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
List of text chunks
|
|
137
|
+
|
|
138
|
+
Example:
|
|
139
|
+
chunks = chunk_text(context, chunk_size=5000)
|
|
140
|
+
for i, chunk in enumerate(chunks):
|
|
141
|
+
result = llm_query(f"Analyze chunk {i+1}", chunk)
|
|
142
|
+
"""
|
|
143
|
+
if chunk_size <= overlap:
|
|
144
|
+
raise ValueError("chunk_size must be greater than overlap")
|
|
145
|
+
|
|
146
|
+
chunks = []
|
|
147
|
+
start = 0
|
|
148
|
+
|
|
149
|
+
while start < len(text):
|
|
150
|
+
end = start + chunk_size
|
|
151
|
+
chunk = text[start:end]
|
|
152
|
+
|
|
153
|
+
# Try to break at a newline or space
|
|
154
|
+
if end < len(text):
|
|
155
|
+
# Look for a good break point in the last 10% of the chunk
|
|
156
|
+
break_zone = chunk[int(chunk_size * 0.9):]
|
|
157
|
+
|
|
158
|
+
# Prefer paragraph break
|
|
159
|
+
para_break = break_zone.rfind('\n\n')
|
|
160
|
+
if para_break != -1:
|
|
161
|
+
end = start + int(chunk_size * 0.9) + para_break + 2
|
|
162
|
+
chunk = text[start:end]
|
|
163
|
+
else:
|
|
164
|
+
# Fall back to line break
|
|
165
|
+
line_break = break_zone.rfind('\n')
|
|
166
|
+
if line_break != -1:
|
|
167
|
+
end = start + int(chunk_size * 0.9) + line_break + 1
|
|
168
|
+
chunk = text[start:end]
|
|
169
|
+
else:
|
|
170
|
+
# Fall back to space
|
|
171
|
+
space_break = break_zone.rfind(' ')
|
|
172
|
+
if space_break != -1:
|
|
173
|
+
end = start + int(chunk_size * 0.9) + space_break + 1
|
|
174
|
+
chunk = text[start:end]
|
|
175
|
+
|
|
176
|
+
chunks.append(chunk.strip())
|
|
177
|
+
start = end - overlap
|
|
178
|
+
|
|
179
|
+
return [c for c in chunks if c] # Filter empty chunks
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def filter_lines(text: str, predicate: str) -> str:
|
|
183
|
+
"""
|
|
184
|
+
Filter lines in text based on a predicate.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
text: The text to filter
|
|
188
|
+
predicate: A string that matching lines must contain
|
|
189
|
+
|
|
190
|
+
Returns:
|
|
191
|
+
Filtered text with only matching lines
|
|
192
|
+
|
|
193
|
+
Example:
|
|
194
|
+
errors = filter_lines(log_content, "ERROR")
|
|
195
|
+
"""
|
|
196
|
+
lines = text.split('\n')
|
|
197
|
+
filtered = [line for line in lines if predicate in line]
|
|
198
|
+
return '\n'.join(filtered)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def count_tokens(text: str) -> int:
|
|
202
|
+
"""
|
|
203
|
+
Estimate the token count for text.
|
|
204
|
+
|
|
205
|
+
This is a rough estimate based on ~4 characters per token.
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
text: The text to estimate
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
Estimated token count
|
|
212
|
+
"""
|
|
213
|
+
return len(text) // 4
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
# Safe modules that can be imported (defined first so _restricted_import can use it)
|
|
217
|
+
_SAFE_MODULES = {
|
|
218
|
+
'json': __import__('json'),
|
|
219
|
+
're': __import__('re'),
|
|
220
|
+
'collections': __import__('collections'),
|
|
221
|
+
'itertools': __import__('itertools'),
|
|
222
|
+
'functools': __import__('functools'),
|
|
223
|
+
'math': __import__('math'),
|
|
224
|
+
'random': __import__('random'),
|
|
225
|
+
'string': __import__('string'),
|
|
226
|
+
'textwrap': __import__('textwrap'),
|
|
227
|
+
'difflib': __import__('difflib'),
|
|
228
|
+
'heapq': __import__('heapq'),
|
|
229
|
+
'bisect': __import__('bisect'),
|
|
230
|
+
'copy': __import__('copy'),
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def _restricted_import(name: str, globals_dict=None, locals_dict=None, fromlist=(), level=0):
|
|
235
|
+
"""Restricted import function that only allows safe modules."""
|
|
236
|
+
if name in _SAFE_MODULES:
|
|
237
|
+
return _SAFE_MODULES[name]
|
|
238
|
+
raise ImportError(f"Import of '{name}' is not allowed in RLM sandbox")
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
# Restricted builtins for sandboxed execution
|
|
242
|
+
_SAFE_BUILTINS = {
|
|
243
|
+
# Restricted import (must be in builtins for 'import' statement to work)
|
|
244
|
+
'__import__': _restricted_import,
|
|
245
|
+
|
|
246
|
+
# Safe types
|
|
247
|
+
'bool': bool,
|
|
248
|
+
'int': int,
|
|
249
|
+
'float': float,
|
|
250
|
+
'str': str,
|
|
251
|
+
'list': list,
|
|
252
|
+
'dict': dict,
|
|
253
|
+
'tuple': tuple,
|
|
254
|
+
'set': set,
|
|
255
|
+
'frozenset': frozenset,
|
|
256
|
+
'bytes': bytes,
|
|
257
|
+
'bytearray': bytearray,
|
|
258
|
+
|
|
259
|
+
# Safe functions
|
|
260
|
+
'abs': abs,
|
|
261
|
+
'all': all,
|
|
262
|
+
'any': any,
|
|
263
|
+
'bin': bin,
|
|
264
|
+
'chr': chr,
|
|
265
|
+
'divmod': divmod,
|
|
266
|
+
'enumerate': enumerate,
|
|
267
|
+
'filter': filter,
|
|
268
|
+
'format': format,
|
|
269
|
+
'hex': hex,
|
|
270
|
+
'isinstance': isinstance,
|
|
271
|
+
'issubclass': issubclass,
|
|
272
|
+
'iter': iter,
|
|
273
|
+
'len': len,
|
|
274
|
+
'map': map,
|
|
275
|
+
'max': max,
|
|
276
|
+
'min': min,
|
|
277
|
+
'next': next,
|
|
278
|
+
'oct': oct,
|
|
279
|
+
'ord': ord,
|
|
280
|
+
'pow': pow,
|
|
281
|
+
'print': print,
|
|
282
|
+
'range': range,
|
|
283
|
+
'repr': repr,
|
|
284
|
+
'reversed': reversed,
|
|
285
|
+
'round': round,
|
|
286
|
+
'slice': slice,
|
|
287
|
+
'sorted': sorted,
|
|
288
|
+
'sum': sum,
|
|
289
|
+
'type': type,
|
|
290
|
+
'zip': zip,
|
|
291
|
+
|
|
292
|
+
# Exceptions
|
|
293
|
+
'Exception': Exception,
|
|
294
|
+
'ValueError': ValueError,
|
|
295
|
+
'TypeError': TypeError,
|
|
296
|
+
'KeyError': KeyError,
|
|
297
|
+
'IndexError': IndexError,
|
|
298
|
+
'RuntimeError': RuntimeError,
|
|
299
|
+
'StopIteration': StopIteration,
|
|
300
|
+
|
|
301
|
+
# Constants
|
|
302
|
+
'True': True,
|
|
303
|
+
'False': False,
|
|
304
|
+
'None': None,
|
|
305
|
+
|
|
306
|
+
# RLM functions
|
|
307
|
+
'llm_query': llm_query,
|
|
308
|
+
'set_result': set_result,
|
|
309
|
+
'set_variable': set_variable,
|
|
310
|
+
'chunk_text': chunk_text,
|
|
311
|
+
'filter_lines': filter_lines,
|
|
312
|
+
'count_tokens': count_tokens,
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def main():
|
|
317
|
+
"""Main entry point for RLM prelude."""
|
|
318
|
+
# Read initial context
|
|
319
|
+
try:
|
|
320
|
+
init_line = sys.stdin.readline().strip()
|
|
321
|
+
if init_line.startswith("__INIT__:"):
|
|
322
|
+
init_data = json.loads(init_line[len("__INIT__:"):])
|
|
323
|
+
|
|
324
|
+
# Load context variables
|
|
325
|
+
for name, value in init_data.get("context", {}).items():
|
|
326
|
+
_context_store[name] = value
|
|
327
|
+
|
|
328
|
+
# Get the code to execute
|
|
329
|
+
code = init_data.get("code", "")
|
|
330
|
+
|
|
331
|
+
if not code:
|
|
332
|
+
print("__ERROR__:No code provided", flush=True)
|
|
333
|
+
return 1
|
|
334
|
+
|
|
335
|
+
# Create restricted execution environment
|
|
336
|
+
exec_globals = {
|
|
337
|
+
'__builtins__': _SAFE_BUILTINS,
|
|
338
|
+
'__name__': '__main__',
|
|
339
|
+
'__doc__': None,
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
# Add context variables to globals
|
|
343
|
+
exec_globals.update(_context_store)
|
|
344
|
+
|
|
345
|
+
# Execute the code
|
|
346
|
+
try:
|
|
347
|
+
exec(code, exec_globals)
|
|
348
|
+
|
|
349
|
+
# Check if result was set
|
|
350
|
+
if _result is None:
|
|
351
|
+
print("__WARNING__:No result was set. Call set_result() with your answer.", flush=True)
|
|
352
|
+
|
|
353
|
+
print("__DONE__", flush=True)
|
|
354
|
+
return 0
|
|
355
|
+
|
|
356
|
+
except Exception as e:
|
|
357
|
+
import traceback
|
|
358
|
+
tb = traceback.format_exc()
|
|
359
|
+
error_info = {
|
|
360
|
+
"error": str(e),
|
|
361
|
+
"type": type(e).__name__,
|
|
362
|
+
"traceback": tb
|
|
363
|
+
}
|
|
364
|
+
print(f"__ERROR__:{json.dumps(error_info)}", flush=True)
|
|
365
|
+
return 1
|
|
366
|
+
else:
|
|
367
|
+
print("__ERROR__:Invalid initialization", flush=True)
|
|
368
|
+
return 1
|
|
369
|
+
|
|
370
|
+
except Exception as e:
|
|
371
|
+
print(f"__ERROR__:{json.dumps({'error': str(e), 'type': type(e).__name__})}", flush=True)
|
|
372
|
+
return 1
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
if __name__ == "__main__":
|
|
376
|
+
sys.exit(main())
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { type ChildProcess } from 'node:child_process';
|
|
2
|
+
import { EventEmitter } from 'node:events';
|
|
3
|
+
/**
|
|
4
|
+
* Options for spawning a Python process
|
|
5
|
+
*/
|
|
6
|
+
export interface SpawnOptions {
|
|
7
|
+
/** Timeout in milliseconds */
|
|
8
|
+
readonly timeoutMs: number;
|
|
9
|
+
/** Working directory */
|
|
10
|
+
readonly cwd?: string;
|
|
11
|
+
/** Environment variables */
|
|
12
|
+
readonly env?: Record<string, string>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Events emitted by PythonProcess
|
|
16
|
+
*/
|
|
17
|
+
export interface PythonProcessEvents {
|
|
18
|
+
stdout: (data: string) => void;
|
|
19
|
+
stderr: (data: string) => void;
|
|
20
|
+
command: (command: PythonProcessCommand) => void;
|
|
21
|
+
exit: (code: number | null, signal: string | null) => void;
|
|
22
|
+
error: (error: Error) => void;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Command from Python process
|
|
26
|
+
*/
|
|
27
|
+
export interface PythonProcessCommand {
|
|
28
|
+
type: 'llm_query' | 'set_result' | 'set_variable';
|
|
29
|
+
payload: unknown;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A managed Python process
|
|
33
|
+
*/
|
|
34
|
+
export declare class PythonProcess extends EventEmitter {
|
|
35
|
+
private readonly process;
|
|
36
|
+
private readonly timeout;
|
|
37
|
+
private killed;
|
|
38
|
+
private stdoutBuffer;
|
|
39
|
+
private stderrBuffer;
|
|
40
|
+
constructor(process: ChildProcess, timeoutMs: number);
|
|
41
|
+
/**
|
|
42
|
+
* Send input to the process
|
|
43
|
+
*/
|
|
44
|
+
write(data: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* Send a command response to the process
|
|
47
|
+
*/
|
|
48
|
+
respond(response: unknown): void;
|
|
49
|
+
/**
|
|
50
|
+
* Kill the process
|
|
51
|
+
*/
|
|
52
|
+
kill(signal?: NodeJS.Signals): void;
|
|
53
|
+
/**
|
|
54
|
+
* Check if the process is still running
|
|
55
|
+
*/
|
|
56
|
+
isRunning(): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Get the process PID
|
|
59
|
+
*/
|
|
60
|
+
get pid(): number | undefined;
|
|
61
|
+
/**
|
|
62
|
+
* Get collected stdout
|
|
63
|
+
*/
|
|
64
|
+
getStdout(): string;
|
|
65
|
+
/**
|
|
66
|
+
* Get collected stderr
|
|
67
|
+
*/
|
|
68
|
+
getStderr(): string;
|
|
69
|
+
/**
|
|
70
|
+
* Process stdout to extract commands
|
|
71
|
+
*/
|
|
72
|
+
private processOutput;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Manages Python process lifecycle
|
|
76
|
+
*/
|
|
77
|
+
export declare class ProcessManager {
|
|
78
|
+
private activeProcesses;
|
|
79
|
+
private readonly preludePath;
|
|
80
|
+
constructor();
|
|
81
|
+
/**
|
|
82
|
+
* Spawn a new Python process
|
|
83
|
+
*/
|
|
84
|
+
spawn(options: SpawnOptions): PythonProcess;
|
|
85
|
+
/**
|
|
86
|
+
* Kill a specific process
|
|
87
|
+
*/
|
|
88
|
+
kill(process: PythonProcess): void;
|
|
89
|
+
/**
|
|
90
|
+
* Kill all active processes
|
|
91
|
+
*/
|
|
92
|
+
killAll(): void;
|
|
93
|
+
/**
|
|
94
|
+
* Get count of active processes
|
|
95
|
+
*/
|
|
96
|
+
get activeCount(): number;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=process-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-manager.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/sandbox/process-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,8BAA8B;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B,wBAAwB;IACxB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAEtB,4BAA4B;IAC5B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,OAAO,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACjD,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC3D,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,WAAW,GAAG,YAAY,GAAG,cAAc,CAAC;IAClD,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,qBAAa,aAAc,SAAQ,YAAY;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,YAAY,CAAM;gBAEd,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM;IAqCpD;;OAEG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIzB;;OAEG;IACH,OAAO,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAKhC;;OAEG;IACH,IAAI,CAAC,MAAM,GAAE,MAAM,CAAC,OAAmB,GAAG,IAAI;IAQ9C;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,IAAI,GAAG,IAAI,MAAM,GAAG,SAAS,CAE5B;IAED;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,OAAO,CAAC,aAAa;CAmCtB;AAED;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,eAAe,CAAiC;IACxD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;;IAQrC;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,aAAa;IAwB3C;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IAKlC;;OAEG;IACH,OAAO,IAAI,IAAI;IAOf;;OAEG;IACH,IAAI,WAAW,IAAI,MAAM,CAExB;CACF"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { EventEmitter } from 'node:events';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
/**
|
|
6
|
+
* A managed Python process
|
|
7
|
+
*/
|
|
8
|
+
export class PythonProcess extends EventEmitter {
|
|
9
|
+
process;
|
|
10
|
+
timeout;
|
|
11
|
+
killed = false;
|
|
12
|
+
stdoutBuffer = '';
|
|
13
|
+
stderrBuffer = '';
|
|
14
|
+
constructor(process, timeoutMs) {
|
|
15
|
+
super();
|
|
16
|
+
this.process = process;
|
|
17
|
+
// Set up timeout
|
|
18
|
+
this.timeout = setTimeout(() => {
|
|
19
|
+
this.kill('SIGKILL');
|
|
20
|
+
this.emit('error', new Error(`Process timed out after ${timeoutMs}ms`));
|
|
21
|
+
}, timeoutMs);
|
|
22
|
+
// Handle stdout
|
|
23
|
+
process.stdout?.on('data', (data) => {
|
|
24
|
+
const text = data.toString();
|
|
25
|
+
this.stdoutBuffer += text;
|
|
26
|
+
this.processOutput();
|
|
27
|
+
});
|
|
28
|
+
// Handle stderr
|
|
29
|
+
process.stderr?.on('data', (data) => {
|
|
30
|
+
const text = data.toString();
|
|
31
|
+
this.stderrBuffer += text;
|
|
32
|
+
this.emit('stderr', text);
|
|
33
|
+
});
|
|
34
|
+
// Handle exit
|
|
35
|
+
process.on('exit', (code, signal) => {
|
|
36
|
+
clearTimeout(this.timeout);
|
|
37
|
+
this.emit('exit', code, signal);
|
|
38
|
+
});
|
|
39
|
+
// Handle errors
|
|
40
|
+
process.on('error', (error) => {
|
|
41
|
+
clearTimeout(this.timeout);
|
|
42
|
+
this.emit('error', error);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Send input to the process
|
|
47
|
+
*/
|
|
48
|
+
write(data) {
|
|
49
|
+
this.process.stdin?.write(data);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Send a command response to the process
|
|
53
|
+
*/
|
|
54
|
+
respond(response) {
|
|
55
|
+
const json = JSON.stringify(response);
|
|
56
|
+
this.write(`__RESPONSE__:${json}\n`);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Kill the process
|
|
60
|
+
*/
|
|
61
|
+
kill(signal = 'SIGTERM') {
|
|
62
|
+
if (!this.killed) {
|
|
63
|
+
this.killed = true;
|
|
64
|
+
clearTimeout(this.timeout);
|
|
65
|
+
this.process.kill(signal);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Check if the process is still running
|
|
70
|
+
*/
|
|
71
|
+
isRunning() {
|
|
72
|
+
return !this.killed && this.process.exitCode === null;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get the process PID
|
|
76
|
+
*/
|
|
77
|
+
get pid() {
|
|
78
|
+
return this.process.pid;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Get collected stdout
|
|
82
|
+
*/
|
|
83
|
+
getStdout() {
|
|
84
|
+
return this.stdoutBuffer;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Get collected stderr
|
|
88
|
+
*/
|
|
89
|
+
getStderr() {
|
|
90
|
+
return this.stderrBuffer;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Process stdout to extract commands
|
|
94
|
+
*/
|
|
95
|
+
processOutput() {
|
|
96
|
+
// Look for command markers in output
|
|
97
|
+
const lines = this.stdoutBuffer.split('\n');
|
|
98
|
+
const remainingLines = [];
|
|
99
|
+
for (const line of lines) {
|
|
100
|
+
if (line.startsWith('__COMMAND__:')) {
|
|
101
|
+
try {
|
|
102
|
+
const json = line.slice('__COMMAND__:'.length);
|
|
103
|
+
const command = JSON.parse(json);
|
|
104
|
+
this.emit('command', command);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// Invalid JSON, treat as regular output
|
|
108
|
+
remainingLines.push(line);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else if (line.length > 0 || lines.indexOf(line) < lines.length - 1) {
|
|
112
|
+
remainingLines.push(line);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Keep incomplete line in buffer
|
|
116
|
+
const lastLine = remainingLines[remainingLines.length - 1];
|
|
117
|
+
if (lastLine !== undefined && !lastLine.endsWith('\n')) {
|
|
118
|
+
this.stdoutBuffer = lastLine;
|
|
119
|
+
remainingLines.pop();
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
this.stdoutBuffer = '';
|
|
123
|
+
}
|
|
124
|
+
// Emit remaining stdout
|
|
125
|
+
const output = remainingLines.join('\n');
|
|
126
|
+
if (output.length > 0) {
|
|
127
|
+
this.emit('stdout', output);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Manages Python process lifecycle
|
|
133
|
+
*/
|
|
134
|
+
export class ProcessManager {
|
|
135
|
+
activeProcesses = new Set();
|
|
136
|
+
preludePath;
|
|
137
|
+
constructor() {
|
|
138
|
+
// Get the directory containing this file
|
|
139
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
140
|
+
this.preludePath = path.join(__dirname, 'prelude', 'rlm_prelude.py');
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Spawn a new Python process
|
|
144
|
+
*/
|
|
145
|
+
spawn(options) {
|
|
146
|
+
const pythonPath = process.env['PYTHON_PATH'] ?? 'python3';
|
|
147
|
+
const childProcess = spawn(pythonPath, ['-u', this.preludePath], {
|
|
148
|
+
cwd: options.cwd,
|
|
149
|
+
env: {
|
|
150
|
+
...process.env,
|
|
151
|
+
...options.env,
|
|
152
|
+
PYTHONUNBUFFERED: '1',
|
|
153
|
+
},
|
|
154
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
155
|
+
});
|
|
156
|
+
const pythonProcess = new PythonProcess(childProcess, options.timeoutMs);
|
|
157
|
+
this.activeProcesses.add(pythonProcess);
|
|
158
|
+
pythonProcess.on('exit', () => {
|
|
159
|
+
this.activeProcesses.delete(pythonProcess);
|
|
160
|
+
});
|
|
161
|
+
return pythonProcess;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Kill a specific process
|
|
165
|
+
*/
|
|
166
|
+
kill(process) {
|
|
167
|
+
process.kill();
|
|
168
|
+
this.activeProcesses.delete(process);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Kill all active processes
|
|
172
|
+
*/
|
|
173
|
+
killAll() {
|
|
174
|
+
for (const process of this.activeProcesses) {
|
|
175
|
+
process.kill();
|
|
176
|
+
}
|
|
177
|
+
this.activeProcesses.clear();
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Get count of active processes
|
|
181
|
+
*/
|
|
182
|
+
get activeCount() {
|
|
183
|
+
return this.activeProcesses.size;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=process-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-manager.js","sourceRoot":"","sources":["../../../src/infrastructure/sandbox/process-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ICodeExecutor, ExecutionContext, ExecutionResult, ValidationResult } from '../../domain/interfaces/code-executor.js';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for Python executor
|
|
4
|
+
*/
|
|
5
|
+
export interface PythonExecutorConfig {
|
|
6
|
+
/** Strict mode for validation (default: true) */
|
|
7
|
+
readonly strictMode?: boolean;
|
|
8
|
+
/** Default timeout in ms (default: 30000) */
|
|
9
|
+
readonly defaultTimeoutMs?: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Python code executor implementation
|
|
13
|
+
*/
|
|
14
|
+
export declare class PythonExecutor implements ICodeExecutor {
|
|
15
|
+
private readonly validator;
|
|
16
|
+
private readonly processManager;
|
|
17
|
+
private readonly config;
|
|
18
|
+
private currentProcess;
|
|
19
|
+
private pendingQueryResolve;
|
|
20
|
+
private pendingQueryReject;
|
|
21
|
+
constructor(config?: PythonExecutorConfig);
|
|
22
|
+
validate(code: string): ValidationResult;
|
|
23
|
+
execute(code: string, context: ExecutionContext): Promise<ExecutionResult>;
|
|
24
|
+
respondToQuery(response: string): Promise<void>;
|
|
25
|
+
kill(): Promise<void>;
|
|
26
|
+
isReady(): boolean;
|
|
27
|
+
private convertCommand;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=python-executor.d.ts.map
|