micro-models-agent 0.31.0 → 0.33.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/main.js +1408 -396
- package/dist/modules/browser/bridge-server.mjs +194 -0
- package/package.json +45 -45
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { createRequire } from 'module'
|
|
2
|
+
import readline from 'readline'
|
|
3
|
+
|
|
4
|
+
const require = createRequire(import.meta.url)
|
|
5
|
+
const { chromium } = require('playwright')
|
|
6
|
+
|
|
7
|
+
const CONSOLE_CAP = 500
|
|
8
|
+
const NETWORK_CAP = 100
|
|
9
|
+
let maxLineChars = 400
|
|
10
|
+
|
|
11
|
+
let browser = null
|
|
12
|
+
let context = null
|
|
13
|
+
let page = null
|
|
14
|
+
let consoleBuf = []
|
|
15
|
+
let networkBuf = []
|
|
16
|
+
let lastUrl = ''
|
|
17
|
+
|
|
18
|
+
function pushConsole(type, text) {
|
|
19
|
+
if (consoleBuf.length >= CONSOLE_CAP) return
|
|
20
|
+
const clean = String(text).replace(/\s+/g, ' ').trim()
|
|
21
|
+
if (!clean) return
|
|
22
|
+
const line = clean.length > maxLineChars ? clean.slice(0, maxLineChars) + '…' : clean
|
|
23
|
+
consoleBuf.push({ type, text: line })
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function pushNetwork(err) {
|
|
27
|
+
if (networkBuf.length >= NETWORK_CAP) return
|
|
28
|
+
networkBuf.push(err)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function drain() {
|
|
32
|
+
const consoleEvents = consoleBuf
|
|
33
|
+
const networkEvents = networkBuf
|
|
34
|
+
consoleBuf = []
|
|
35
|
+
networkBuf = []
|
|
36
|
+
return { console: consoleEvents, network: networkEvents }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function readInt(v, fallback) {
|
|
40
|
+
const n = Number(v)
|
|
41
|
+
return Number.isFinite(n) && n > 0 ? n : fallback
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function handleLaunch(params) {
|
|
45
|
+
if (browser) return { ok: true }
|
|
46
|
+
maxLineChars = readInt(params?.maxConsoleLineChars, 400)
|
|
47
|
+
browser = await chromium.launch({
|
|
48
|
+
headless: params?.headless !== false,
|
|
49
|
+
timeout: readInt(params?.timeoutMs, 30000),
|
|
50
|
+
})
|
|
51
|
+
context = await browser.newContext({
|
|
52
|
+
viewport: params?.viewport || { width: 1280, height: 720 },
|
|
53
|
+
})
|
|
54
|
+
page = await context.newPage()
|
|
55
|
+
page.setDefaultTimeout(readInt(params?.timeoutMs, 30000))
|
|
56
|
+
|
|
57
|
+
page.on('console', (msg) => pushConsole(msg.type(), msg.text()))
|
|
58
|
+
page.on('pageerror', (err) => pushConsole('pageerror', `Page error: ${err.message}`))
|
|
59
|
+
page.on('requestfailed', (req) => {
|
|
60
|
+
const failure = req.failure()
|
|
61
|
+
pushNetwork({ method: req.method(), url: req.url(), error: failure?.errorText || 'unknown' })
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
return { ok: true }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function handleGoto(params) {
|
|
68
|
+
if (!page) return { ok: false, error: 'No page open' }
|
|
69
|
+
const url = String(params?.url || '')
|
|
70
|
+
const timeoutMs = readInt(params?.timeoutMs, 15000)
|
|
71
|
+
consoleBuf = []
|
|
72
|
+
networkBuf = []
|
|
73
|
+
try {
|
|
74
|
+
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: timeoutMs })
|
|
75
|
+
lastUrl = page.url()
|
|
76
|
+
return { ok: true, data: { url: lastUrl } }
|
|
77
|
+
} catch (err) {
|
|
78
|
+
lastUrl = page.url()
|
|
79
|
+
return { ok: false, error: err.message, data: { url: lastUrl } }
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function handleEvaluate(params) {
|
|
84
|
+
if (!page) return { ok: false, error: 'No page open' }
|
|
85
|
+
const js = String(params?.js || '')
|
|
86
|
+
try {
|
|
87
|
+
const result = await page.evaluate(js)
|
|
88
|
+
return { ok: true, data: { result } }
|
|
89
|
+
} catch (err) {
|
|
90
|
+
return { ok: false, error: err.message }
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function handleClose() {
|
|
95
|
+
try {
|
|
96
|
+
if (page) await page.close()
|
|
97
|
+
} catch {}
|
|
98
|
+
try {
|
|
99
|
+
if (context) await context.close()
|
|
100
|
+
} catch {}
|
|
101
|
+
try {
|
|
102
|
+
if (browser) await browser.close()
|
|
103
|
+
} catch {}
|
|
104
|
+
page = null
|
|
105
|
+
context = null
|
|
106
|
+
browser = null
|
|
107
|
+
return { ok: true }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const handlers = {
|
|
111
|
+
ping: async () => ({ ok: true, data: { pong: true, runtime: process.version } }),
|
|
112
|
+
launch: handleLaunch,
|
|
113
|
+
goto: handleGoto,
|
|
114
|
+
evaluate: handleEvaluate,
|
|
115
|
+
content: async () => ({ ok: true, data: { html: page ? await page.content() : '' } }),
|
|
116
|
+
title: async () => ({ ok: true, data: { title: page ? await page.title() : '' } }),
|
|
117
|
+
url: async () => ({ ok: true, data: { url: page ? page.url() : lastUrl } }),
|
|
118
|
+
waitLoad: async (params) => {
|
|
119
|
+
if (!page) return { ok: false, error: 'No page open' }
|
|
120
|
+
try {
|
|
121
|
+
await page.waitForLoadState('domcontentloaded', { timeout: readInt(params?.timeoutMs, 15000) })
|
|
122
|
+
} catch {}
|
|
123
|
+
return { ok: true }
|
|
124
|
+
},
|
|
125
|
+
screenshot: async () => {
|
|
126
|
+
if (!page) return { ok: false, error: 'No page open' }
|
|
127
|
+
try {
|
|
128
|
+
const buf = await page.screenshot({ type: 'png', fullPage: false })
|
|
129
|
+
return { ok: true, data: { base64: buf.toString('base64') } }
|
|
130
|
+
} catch (err) {
|
|
131
|
+
return { ok: false, error: err.message }
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
cookies: async () => {
|
|
135
|
+
if (!context) return { ok: true, data: { cookies: [] } }
|
|
136
|
+
const cookies = await context.cookies()
|
|
137
|
+
return { ok: true, data: { cookies } }
|
|
138
|
+
},
|
|
139
|
+
setCookies: async (params) => {
|
|
140
|
+
if (!context) return { ok: false, error: 'No context' }
|
|
141
|
+
const cookies = Array.isArray(params?.cookies) ? params.cookies : []
|
|
142
|
+
if (cookies.length > 0) {
|
|
143
|
+
try {
|
|
144
|
+
await context.addCookies(cookies)
|
|
145
|
+
} catch (err) {
|
|
146
|
+
return { ok: false, error: err.message }
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return { ok: true }
|
|
150
|
+
},
|
|
151
|
+
back: async (params) => {
|
|
152
|
+
if (!page) return { ok: false, error: 'No page open' }
|
|
153
|
+
try {
|
|
154
|
+
await page.goBack({ waitUntil: 'domcontentloaded', timeout: readInt(params?.timeoutMs, 15000) })
|
|
155
|
+
} catch {}
|
|
156
|
+
lastUrl = page.url()
|
|
157
|
+
return { ok: true, data: { url: lastUrl } }
|
|
158
|
+
},
|
|
159
|
+
forward: async (params) => {
|
|
160
|
+
if (!page) return { ok: false, error: 'No page open' }
|
|
161
|
+
try {
|
|
162
|
+
await page.goForward({ waitUntil: 'domcontentloaded', timeout: readInt(params?.timeoutMs, 15000) })
|
|
163
|
+
} catch {}
|
|
164
|
+
lastUrl = page.url()
|
|
165
|
+
return { ok: true, data: { url: lastUrl } }
|
|
166
|
+
},
|
|
167
|
+
close: handleClose,
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const rl = readline.createInterface({ input: process.stdin })
|
|
171
|
+
rl.on('line', async (line) => {
|
|
172
|
+
let req
|
|
173
|
+
try {
|
|
174
|
+
req = JSON.parse(line)
|
|
175
|
+
} catch {
|
|
176
|
+
return
|
|
177
|
+
}
|
|
178
|
+
const handler = handlers[req.cmd]
|
|
179
|
+
let resp
|
|
180
|
+
if (!handler) {
|
|
181
|
+
resp = { id: req.id, ok: false, error: `Unknown command: ${req.cmd}`, ...drain() }
|
|
182
|
+
} else {
|
|
183
|
+
try {
|
|
184
|
+
const result = await handler(req.params || {})
|
|
185
|
+
resp = { id: req.id, ...result, ...drain() }
|
|
186
|
+
} catch (err) {
|
|
187
|
+
resp = { id: req.id, ok: false, error: err.message, ...drain() }
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
process.stdout.write(JSON.stringify(resp) + '\n')
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
process.on('SIGTERM', () => process.exit(0))
|
|
194
|
+
process.on('SIGINT', () => process.exit(0))
|
package/package.json
CHANGED
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "micro-models-agent",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Micro Models Agent (MMA) — LLM agent harness for small models (Qwen3.5-9B, 32K-64K context)",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"bin": {
|
|
7
|
-
"mma": "bin/mma.mjs"
|
|
8
|
-
},
|
|
9
|
-
"files": [
|
|
10
|
-
"dist/",
|
|
11
|
-
"bin/"
|
|
12
|
-
],
|
|
13
|
-
"engines": {
|
|
14
|
-
"node": ">=20"
|
|
15
|
-
},
|
|
16
|
-
"scripts": {
|
|
17
|
-
"mma": "bun run src/cli/main.ts",
|
|
18
|
-
"build": "bun run build:tsc && bun run build:copy-assets",
|
|
19
|
-
"build:tsc": "tsc -p tsconfig.build.json",
|
|
20
|
-
"build:copy-assets": "bun run scripts/copy-assets.ts",
|
|
21
|
-
"build:prod": "bun run 'build:bundle' && bun run 'build:copy-assets'",
|
|
22
|
-
"build:clean": "cmd /c \"if exist dist rmdir /s /q dist\"",
|
|
23
|
-
"build:bundle": "bun build ./src/cli/main.ts --outfile ./dist/main.js --target node --format esm --external playwright",
|
|
24
|
-
"dev": "bun --watch src/cli/main.ts",
|
|
25
|
-
"typecheck": "tsc --noEmit",
|
|
26
|
-
"test": "vitest run",
|
|
27
|
-
"test:watch": "vitest",
|
|
28
|
-
"test:integration": "vitest run --config vitest.integration.config.ts"
|
|
29
|
-
},
|
|
30
|
-
"dependencies": {
|
|
31
|
-
"commander": "^12.0.0",
|
|
32
|
-
"js-tiktoken": "^1.0.0",
|
|
33
|
-
"jsonrepair": "^3.15.0",
|
|
34
|
-
"picocolors": "^1.1.1",
|
|
35
|
-
"playwright": "^1.62.0",
|
|
36
|
-
"string-width": "^8.2.2",
|
|
37
|
-
"yaml": "^2.9.0"
|
|
38
|
-
},
|
|
39
|
-
"devDependencies": {
|
|
40
|
-
"@types/bun": "^1.3.14",
|
|
41
|
-
"@types/node": "^22.20.1",
|
|
42
|
-
"typescript": "^5.9.3",
|
|
43
|
-
"vitest": "^4.1.10"
|
|
44
|
-
}
|
|
45
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "micro-models-agent",
|
|
3
|
+
"version": "0.33.0",
|
|
4
|
+
"description": "Micro Models Agent (MMA) — LLM agent harness for small models (Qwen3.5-9B, 32K-64K context)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"mma": "bin/mma.mjs"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist/",
|
|
11
|
+
"bin/"
|
|
12
|
+
],
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=20"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"mma": "bun run src/cli/main.ts",
|
|
18
|
+
"build": "bun run build:tsc && bun run build:copy-assets",
|
|
19
|
+
"build:tsc": "tsc -p tsconfig.build.json",
|
|
20
|
+
"build:copy-assets": "bun run scripts/copy-assets.ts",
|
|
21
|
+
"build:prod": "bun run 'build:bundle' && bun run 'build:copy-assets'",
|
|
22
|
+
"build:clean": "cmd /c \"if exist dist rmdir /s /q dist\"",
|
|
23
|
+
"build:bundle": "bun build ./src/cli/main.ts --outfile ./dist/main.js --target node --format esm --external playwright",
|
|
24
|
+
"dev": "bun --watch src/cli/main.ts",
|
|
25
|
+
"typecheck": "tsc --noEmit",
|
|
26
|
+
"test": "vitest run",
|
|
27
|
+
"test:watch": "vitest",
|
|
28
|
+
"test:integration": "vitest run --config vitest.integration.config.ts"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"commander": "^12.0.0",
|
|
32
|
+
"js-tiktoken": "^1.0.0",
|
|
33
|
+
"jsonrepair": "^3.15.0",
|
|
34
|
+
"picocolors": "^1.1.1",
|
|
35
|
+
"playwright": "^1.62.0",
|
|
36
|
+
"string-width": "^8.2.2",
|
|
37
|
+
"yaml": "^2.9.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/bun": "^1.3.14",
|
|
41
|
+
"@types/node": "^22.20.1",
|
|
42
|
+
"typescript": "^5.9.3",
|
|
43
|
+
"vitest": "^4.1.10"
|
|
44
|
+
}
|
|
45
|
+
}
|