traw 0.2.7 → 0.2.8
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/package.json +1 -1
- package/readme.md +1 -1
- package/src/cli/help.ts +9 -18
- package/src/cli/index.ts +12 -109
package/package.json
CHANGED
package/readme.md
CHANGED
package/src/cli/help.ts
CHANGED
|
@@ -6,41 +6,32 @@ traw v${VERSION} - AI browser agent
|
|
|
6
6
|
|
|
7
7
|
Usage:
|
|
8
8
|
traw run "your goal here"
|
|
9
|
-
traw auth
|
|
9
|
+
traw auth
|
|
10
10
|
traw upd
|
|
11
11
|
|
|
12
12
|
Commands:
|
|
13
|
-
run
|
|
14
|
-
auth
|
|
15
|
-
|
|
16
|
-
auth list [provider] list tokens (all or by provider)
|
|
17
|
-
auth activate <id> activate token by id
|
|
18
|
-
upd check for updates
|
|
19
|
-
|
|
20
|
-
Models:
|
|
21
|
-
qwen: coder-model (default), vision-model (--fast)
|
|
22
|
-
glm: GLM-4-Plus, GLM-4-Flash, GLM-4-Air, GLM-4-6-API-V1
|
|
13
|
+
run execute browser agent with a goal
|
|
14
|
+
auth register new account and set as default
|
|
15
|
+
upd check for updates
|
|
23
16
|
|
|
24
17
|
Options:
|
|
25
|
-
--fast use fast model (
|
|
18
|
+
--fast use fast model (glm-4-flash, no thinking)
|
|
26
19
|
--headless run without visible browser (default)
|
|
27
20
|
--headed show browser window
|
|
28
21
|
--video enable video recording
|
|
22
|
+
--vision send screenshots to AI (visual mode)
|
|
29
23
|
--steps=N max steps (default: 20)
|
|
30
24
|
--mo=URL mo server url (default: http://localhost:8804)
|
|
31
25
|
--api=URL custom OpenAI-compatible API url (bypasses mo)
|
|
32
26
|
--api-key=KEY API key for custom endpoint (or use OPENAI_API_KEY env)
|
|
33
|
-
--model=NAME model name (default:
|
|
27
|
+
--model=NAME model name (default: glm-4.7)
|
|
34
28
|
-v, --version show version
|
|
35
29
|
|
|
36
30
|
Examples:
|
|
37
|
-
traw auth
|
|
38
|
-
traw auth glm
|
|
39
|
-
traw auth list
|
|
40
|
-
traw auth activate abc123
|
|
31
|
+
traw auth
|
|
41
32
|
traw run "find the weather in Moscow"
|
|
42
|
-
traw run --model=GLM-4-Plus "search for news"
|
|
43
33
|
traw run --fast "quick search for bun.js"
|
|
44
34
|
traw run --video "search for documentation"
|
|
35
|
+
traw run --api=https://api.openai.com --model=gpt-4o "search for news"
|
|
45
36
|
`)
|
|
46
37
|
}
|
package/src/cli/index.ts
CHANGED
|
@@ -26,18 +26,11 @@ const cliOptions = {
|
|
|
26
26
|
model: { type: "string" as const },
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
type Provider = "qwen" | "glm"
|
|
30
|
-
|
|
31
|
-
const providerModels: Record<Provider, { default: string; fast: string }> = {
|
|
32
|
-
qwen: { default: "coder-model", fast: "vision-model" },
|
|
33
|
-
glm: { default: "GLM-4-Plus", fast: "GLM-4-Flash" },
|
|
34
|
-
}
|
|
35
|
-
|
|
36
29
|
const defaultConfig: AgentConfig = {
|
|
37
30
|
moUrl: `http://localhost:${DEFAULT_MO_PORT}`,
|
|
38
31
|
apiUrl: undefined,
|
|
39
32
|
apiKey: process.env.OPENAI_API_KEY || process.env.API_KEY,
|
|
40
|
-
model: "
|
|
33
|
+
model: "glm-4.7",
|
|
41
34
|
thinking: true,
|
|
42
35
|
headless: true,
|
|
43
36
|
recordVideo: false,
|
|
@@ -55,10 +48,12 @@ async function prompt(question: string): Promise<string> {
|
|
|
55
48
|
}
|
|
56
49
|
|
|
57
50
|
async function ensureMo(moUrl: string): Promise<boolean> {
|
|
51
|
+
// check if mo is already running
|
|
58
52
|
if (await pingMo(moUrl)) {
|
|
59
53
|
return true
|
|
60
54
|
}
|
|
61
55
|
|
|
56
|
+
// mo not running, check if installed
|
|
62
57
|
const installed = await isMoInstalled()
|
|
63
58
|
|
|
64
59
|
if (!installed) {
|
|
@@ -76,6 +71,7 @@ async function ensureMo(moUrl: string): Promise<boolean> {
|
|
|
76
71
|
}
|
|
77
72
|
}
|
|
78
73
|
|
|
74
|
+
// start mo
|
|
79
75
|
try {
|
|
80
76
|
const port = parseInt(new URL(moUrl).port) || DEFAULT_MO_PORT
|
|
81
77
|
await startMo(port)
|
|
@@ -86,13 +82,11 @@ async function ensureMo(moUrl: string): Promise<boolean> {
|
|
|
86
82
|
}
|
|
87
83
|
}
|
|
88
84
|
|
|
89
|
-
async function registerAccount(moUrl: string
|
|
90
|
-
log.info(
|
|
85
|
+
async function registerAccount(moUrl: string): Promise<void> {
|
|
86
|
+
log.info("registering new account...")
|
|
91
87
|
log.info("browser will open for captcha solving")
|
|
92
88
|
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
const resp = await fetch(`${moUrl}${endpoint}`, {
|
|
89
|
+
const resp = await fetch(`${moUrl}/auth/register`, {
|
|
96
90
|
method: "POST",
|
|
97
91
|
headers: { "Content-Type": "application/json" },
|
|
98
92
|
})
|
|
@@ -104,7 +98,7 @@ async function registerAccount(moUrl: string, provider: Provider): Promise<void>
|
|
|
104
98
|
|
|
105
99
|
const data = await resp.json() as {
|
|
106
100
|
success: boolean
|
|
107
|
-
token: { id: string; email: string;
|
|
101
|
+
token: { id: string; email: string; active: boolean }
|
|
108
102
|
}
|
|
109
103
|
|
|
110
104
|
if (!data.success) {
|
|
@@ -113,66 +107,9 @@ async function registerAccount(moUrl: string, provider: Provider): Promise<void>
|
|
|
113
107
|
|
|
114
108
|
log.success(`registered: ${data.token.email}`)
|
|
115
109
|
log.info(`token id: ${data.token.id}`)
|
|
116
|
-
log.info(`provider: ${provider}`)
|
|
117
110
|
log.info("token is now active and ready to use")
|
|
118
111
|
}
|
|
119
112
|
|
|
120
|
-
async function listTokens(moUrl: string, provider: Provider): Promise<void> {
|
|
121
|
-
const endpoint = `/auth/${provider}/tokens`
|
|
122
|
-
|
|
123
|
-
const resp = await fetch(`${moUrl}${endpoint}`)
|
|
124
|
-
if (!resp.ok) {
|
|
125
|
-
throw new Error(`failed to list tokens: ${resp.status}`)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const data = await resp.json() as {
|
|
129
|
-
tokens: Array<{
|
|
130
|
-
id: string
|
|
131
|
-
email: string
|
|
132
|
-
provider: string
|
|
133
|
-
is_active: boolean
|
|
134
|
-
created_at: string
|
|
135
|
-
}>
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
if (!data.tokens || data.tokens.length === 0) {
|
|
139
|
-
log.info(`no ${provider} tokens found`)
|
|
140
|
-
return
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
console.log()
|
|
144
|
-
log.info(`${provider} tokens:`)
|
|
145
|
-
for (const t of data.tokens) {
|
|
146
|
-
const active = t.is_active ? " [active]" : ""
|
|
147
|
-
console.log(` ${t.id} - ${t.email}${active}`)
|
|
148
|
-
}
|
|
149
|
-
console.log()
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
async function activateToken(moUrl: string, tokenId: string): Promise<void> {
|
|
153
|
-
const providers: Provider[] = ["qwen", "glm"]
|
|
154
|
-
|
|
155
|
-
for (const provider of providers) {
|
|
156
|
-
const resp = await fetch(`${moUrl}/auth/${provider}/tokens/${tokenId}/activate`, {
|
|
157
|
-
method: "POST",
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
if (resp.ok) {
|
|
161
|
-
log.success(`token ${tokenId} activated`)
|
|
162
|
-
return
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
throw new Error(`token ${tokenId} not found`)
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function detectProviderFromModel(model: string): Provider {
|
|
170
|
-
if (model.startsWith("coder-") || model.startsWith("vision-")) {
|
|
171
|
-
return "qwen"
|
|
172
|
-
}
|
|
173
|
-
return "glm"
|
|
174
|
-
}
|
|
175
|
-
|
|
176
113
|
async function main() {
|
|
177
114
|
const { values, positionals } = parseArgs({
|
|
178
115
|
args: Bun.argv.slice(2),
|
|
@@ -220,40 +157,13 @@ async function main() {
|
|
|
220
157
|
|
|
221
158
|
if (cmd === "auth") {
|
|
222
159
|
const moUrl = typeof values.mo === "string" ? values.mo : defaultConfig.moUrl
|
|
223
|
-
const subCmd = positionals[1]
|
|
224
160
|
|
|
225
161
|
if (!await ensureMo(moUrl)) {
|
|
226
162
|
process.exit(1)
|
|
227
163
|
}
|
|
228
164
|
|
|
229
165
|
try {
|
|
230
|
-
|
|
231
|
-
await registerAccount(moUrl, "qwen")
|
|
232
|
-
} else if (subCmd === "glm") {
|
|
233
|
-
await registerAccount(moUrl, "glm")
|
|
234
|
-
} else if (subCmd === "list") {
|
|
235
|
-
const provider = positionals[2] as Provider | undefined
|
|
236
|
-
if (provider && (provider === "qwen" || provider === "glm")) {
|
|
237
|
-
await listTokens(moUrl, provider)
|
|
238
|
-
} else {
|
|
239
|
-
await listTokens(moUrl, "qwen")
|
|
240
|
-
await listTokens(moUrl, "glm")
|
|
241
|
-
}
|
|
242
|
-
} else if (subCmd === "activate") {
|
|
243
|
-
const tokenId = positionals[2]
|
|
244
|
-
if (!tokenId) {
|
|
245
|
-
log.error("provide token id: traw auth activate <id>")
|
|
246
|
-
process.exit(1)
|
|
247
|
-
}
|
|
248
|
-
await activateToken(moUrl, tokenId)
|
|
249
|
-
} else {
|
|
250
|
-
log.error("usage: traw auth <qwen|glm|list|activate>")
|
|
251
|
-
log.info(" traw auth qwen - register qwen account")
|
|
252
|
-
log.info(" traw auth glm - register glm/z.ai account")
|
|
253
|
-
log.info(" traw auth list - list all tokens")
|
|
254
|
-
log.info(" traw auth activate <id> - activate token")
|
|
255
|
-
process.exit(1)
|
|
256
|
-
}
|
|
166
|
+
await registerAccount(moUrl)
|
|
257
167
|
} catch (err: any) {
|
|
258
168
|
log.error(err.message)
|
|
259
169
|
process.exit(1)
|
|
@@ -271,15 +181,7 @@ async function main() {
|
|
|
271
181
|
const moUrl = typeof values.mo === "string" ? values.mo : defaultConfig.moUrl
|
|
272
182
|
const apiUrl = typeof values.api === "string" ? values.api : undefined
|
|
273
183
|
const apiKey = typeof values["api-key"] === "string" ? values["api-key"] : defaultConfig.apiKey
|
|
274
|
-
|
|
275
|
-
let model: string
|
|
276
|
-
if (typeof values.model === "string") {
|
|
277
|
-
model = values.model
|
|
278
|
-
} else {
|
|
279
|
-
const provider: Provider = "qwen"
|
|
280
|
-
model = values.fast ? providerModels[provider].fast : providerModels[provider].default
|
|
281
|
-
}
|
|
282
|
-
|
|
184
|
+
const model = typeof values.model === "string" ? values.model : (values.fast ? "0727-106B-API" : defaultConfig.model)
|
|
283
185
|
const steps = typeof values.steps === "string" ? parseInt(values.steps) : defaultConfig.maxSteps
|
|
284
186
|
|
|
285
187
|
const config: AgentConfig = {
|
|
@@ -297,7 +199,7 @@ async function main() {
|
|
|
297
199
|
|
|
298
200
|
const goal = positionals.slice(1).join(" ")
|
|
299
201
|
if (!goal) {
|
|
300
|
-
log.error("provide a goal: traw run \"your goal\"")
|
|
202
|
+
log.error("provide a goal: bun run traw run \"your goal\"")
|
|
301
203
|
process.exit(1)
|
|
302
204
|
}
|
|
303
205
|
|
|
@@ -315,6 +217,7 @@ async function main() {
|
|
|
315
217
|
setSilent(true)
|
|
316
218
|
}
|
|
317
219
|
|
|
220
|
+
// skip mo setup if using custom api
|
|
318
221
|
if (!config.apiUrl && !await ensureMo(config.moUrl)) {
|
|
319
222
|
process.exit(1)
|
|
320
223
|
}
|