@melaya/runner 1.0.84 → 1.0.86

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 (2) hide show
  1. package/dist/assistantHost.py +63 -6
  2. package/package.json +42 -42
@@ -46,6 +46,55 @@ _stream = {"turnId": "", "lens": {}, "cancel": False}
46
46
  _CANCELLED = object()
47
47
 
48
48
 
49
+ class _RedactingStdout:
50
+ """Wrap stdout to strip long base64 runs before they reach the log.
51
+
52
+ agentscope prints every agent message verbatim (the `MelayaAssistant: {...}`
53
+ lines), which for phone_screenshot tool results embeds a full base64 JPEG —
54
+ tens of KB per turn that floods and explodes the runner logs. This filter is
55
+ line-buffered and only replaces base64-looking runs (>=200 chars), so the
56
+ structured `MELASSIST ` event lines (short text deltas / tool names) pass
57
+ through byte-for-byte and the runner's line parser is unaffected."""
58
+
59
+ import re as _re
60
+ _B64 = _re.compile(r"[A-Za-z0-9+/]{200,}={0,2}")
61
+
62
+ def __init__(self, real):
63
+ self._real = real
64
+ self._buf = ""
65
+
66
+ def _scrub(self, s: str) -> str:
67
+ return self._B64.sub(lambda m: f"<redacted base64 {len(m.group(0))} bytes>", s)
68
+
69
+ def write(self, s):
70
+ try:
71
+ self._buf += s
72
+ while "\n" in self._buf:
73
+ line, self._buf = self._buf.split("\n", 1)
74
+ self._real.write(self._scrub(line) + "\n")
75
+ return len(s)
76
+ except Exception:
77
+ return self._real.write(s)
78
+
79
+ def flush(self):
80
+ try:
81
+ if self._buf:
82
+ self._real.write(self._scrub(self._buf))
83
+ self._buf = ""
84
+ self._real.flush()
85
+ except Exception:
86
+ pass
87
+
88
+ def __getattr__(self, k):
89
+ return getattr(self._real, k)
90
+
91
+
92
+ # Install the redactor as early as possible so agentscope's message printing is
93
+ # filtered for the whole process lifetime.
94
+ if not isinstance(sys.stdout, _RedactingStdout):
95
+ sys.stdout = _RedactingStdout(sys.stdout)
96
+
97
+
49
98
  def _emit(turn_id: str, kind: str, **fields) -> None:
50
99
  """Write one structured event line to stdout (flushed) for the runner to relay."""
51
100
  try:
@@ -127,14 +176,22 @@ def _build_agent():
127
176
  "tap, type, comment, post), use the phone_* tools. ALWAYS call "
128
177
  "phone_get_screen_tree before you tap or type. Publish comments/posts with "
129
178
  "phone_post_comment / phone_create_post — every publish is approved by the "
130
- "user ON THEIR PHONE, so never refuse for safety. Only touch apps the user "
131
- "asked for; the phone enforces an allowlist and blocks the rest.\n"
179
+ "user ON THEIR PHONE, so never refuse for safety.\n"
180
+ "- EXACT APP ONLY this overrides your autonomy: operate on the EXACT app "
181
+ "the user named, never a different one. If that app is not in the allowlist "
182
+ "(phone_open_app returns app_not_allowed) or not installed, STOP and tell the "
183
+ "user to authorize/install it in Device Control. NEVER substitute a 'similar', "
184
+ "'closest', or 'equivalent' app (e.g. do NOT open Instagram when asked for "
185
+ "TikTok). Opening the wrong app is a FAILED task, not a reasonable default. "
186
+ "After the user authorizes the app, phone_list_apps reflects it immediately — "
187
+ "re-check and open the REQUESTED app.\n"
132
188
  "- You are FULLY AUTONOMOUS on the phone: NEVER ask the user a question, "
133
189
  "never end your turn asking for confirmation or offering a choice — make the "
134
- "reasonable decision and DO it. If a feed is algorithmic, use the app's own "
135
- "Search / Explore to find the right content yourself. Keep going until the "
136
- "task is COMPLETE (e.g. all N comments posted) or you are genuinely blocked; "
137
- "only then report what you did and what (if anything) is blocked.\n"
190
+ "reasonable decision and DO it (the ONE exception is the EXACT-APP rule above: "
191
+ "a missing app is a stop, not a substitution). If a feed is algorithmic, use "
192
+ "the app's own Search / Explore to find the right content yourself. Keep going "
193
+ "until the task is COMPLETE (e.g. all N comments posted) or you are genuinely "
194
+ "blocked; only then report what you did and what (if anything) is blocked.\n"
138
195
  if phone_enabled else ""
139
196
  )
140
197
  sys_prompt = (
package/package.json CHANGED
@@ -1,42 +1,42 @@
1
- {
2
- "name": "@melaya/runner",
3
- "version": "1.0.84",
4
- "description": "Run Melaya AI pipelines locally with your own LM Studio or Ollama models",
5
- "license": "UNLICENSED",
6
- "private": false,
7
- "type": "module",
8
- "bin": {
9
- "melaya-runner": "dist/cli.js"
10
- },
11
- "main": "dist/index.js",
12
- "files": [
13
- "dist/**/*.js",
14
- "dist/**/*.d.ts",
15
- "dist/**/*.py",
16
- "localRagIngest.py",
17
- "localRagRetrieve.py",
18
- "nltk_data/**",
19
- "README.md"
20
- ],
21
- "scripts": {
22
- "build": "tsc && node -e \"const fs=require('fs'); fs.copyFileSync('localRagIngest.py','dist/localRagIngest.py'); fs.copyFileSync('localRagRetrieve.py','dist/localRagRetrieve.py'); fs.copyFileSync('src/assistantHost.py','dist/assistantHost.py')\"",
23
- "prepublishOnly": "npm run build"
24
- },
25
- "dependencies": {
26
- "chalk": "^5.3.0",
27
- "commander": "^12.0.0",
28
- "ora": "^8.0.0",
29
- "playwright": "^1.47.0",
30
- "socket.io-client": "^4.8.0"
31
- },
32
- "devDependencies": {
33
- "@types/node": "^20.0.0",
34
- "typescript": "^5.5.0"
35
- },
36
- "engines": {
37
- "node": ">=18"
38
- },
39
- "publishConfig": {
40
- "access": "public"
41
- }
42
- }
1
+ {
2
+ "name": "@melaya/runner",
3
+ "version": "1.0.86",
4
+ "description": "Run Melaya AI pipelines locally with your own LM Studio or Ollama models",
5
+ "license": "UNLICENSED",
6
+ "private": false,
7
+ "type": "module",
8
+ "bin": {
9
+ "melaya-runner": "dist/cli.js"
10
+ },
11
+ "main": "dist/index.js",
12
+ "files": [
13
+ "dist/**/*.js",
14
+ "dist/**/*.d.ts",
15
+ "dist/**/*.py",
16
+ "localRagIngest.py",
17
+ "localRagRetrieve.py",
18
+ "nltk_data/**",
19
+ "README.md"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsc && node -e \"const fs=require('fs'); fs.copyFileSync('localRagIngest.py','dist/localRagIngest.py'); fs.copyFileSync('localRagRetrieve.py','dist/localRagRetrieve.py'); fs.copyFileSync('src/assistantHost.py','dist/assistantHost.py')\"",
23
+ "prepublishOnly": "npm run build"
24
+ },
25
+ "dependencies": {
26
+ "chalk": "^5.3.0",
27
+ "commander": "^12.0.0",
28
+ "ora": "^8.0.0",
29
+ "playwright": "^1.47.0",
30
+ "socket.io-client": "^4.8.0"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^20.0.0",
34
+ "typescript": "^5.5.0"
35
+ },
36
+ "engines": {
37
+ "node": ">=18"
38
+ },
39
+ "publishConfig": {
40
+ "access": "public"
41
+ }
42
+ }