traw 0.2.2 → 0.2.4

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "traw",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "module": "src/index.ts",
5
5
  "type": "module",
6
6
  "bin": {
@@ -72,9 +72,13 @@ export class Agent {
72
72
  log.step(step + 1, this.config.maxSteps, state.url)
73
73
 
74
74
  const thinkStart = Date.now()
75
+ let decision: { thought: string; action: Action }
75
76
  log.receiveStart()
76
- const decision = await this.think(state)
77
- log.receiveStop()
77
+ try {
78
+ decision = await this.think(state)
79
+ } finally {
80
+ log.receiveStop()
81
+ }
78
82
  this.aiTime += Date.now() - thinkStart
79
83
 
80
84
  log.thought(decision.thought)
@@ -22,7 +22,7 @@ export class MoClient {
22
22
  this.thinking = opts.thinking
23
23
  }
24
24
 
25
- async chat(messages: ChatMessage[]): Promise<string> {
25
+ async chat(messages: ChatMessage[], timeoutMs = 300000): Promise<string> {
26
26
  const headers: Record<string, string> = {
27
27
  "Content-Type": "application/json",
28
28
  }
@@ -31,16 +31,30 @@ export class MoClient {
31
31
  headers["Authorization"] = `Bearer ${this.apiKey}`
32
32
  }
33
33
 
34
- const resp = await fetch(`${this.url}/v1/chat/completions`, {
35
- method: "POST",
36
- headers,
37
- body: JSON.stringify({
38
- model: this.model,
39
- messages,
40
- stream: false,
41
- thinking: this.thinking,
42
- }),
43
- })
34
+ const controller = new AbortController()
35
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs)
36
+
37
+ let resp: Response
38
+ try {
39
+ resp = await fetch(`${this.url}/v1/chat/completions`, {
40
+ method: "POST",
41
+ headers,
42
+ signal: controller.signal,
43
+ body: JSON.stringify({
44
+ model: this.model,
45
+ messages,
46
+ stream: false,
47
+ thinking: this.thinking,
48
+ }),
49
+ })
50
+ } catch (err: any) {
51
+ clearTimeout(timeoutId)
52
+ if (err.name === "AbortError") {
53
+ throw new Error(`mo timeout: no response in ${timeoutMs / 1000}s`)
54
+ }
55
+ throw err
56
+ }
57
+ clearTimeout(timeoutId)
44
58
 
45
59
  if (!resp.ok) {
46
60
  const body = await resp.text()
@@ -74,8 +74,6 @@ export class BrowserController {
74
74
 
75
75
  const walk = (node: Element, depth: number) => {
76
76
  const el = node as HTMLElement
77
- if (el.offsetParent === null && el.tagName !== "BODY" && el.tagName !== "HTML") return
78
-
79
77
  const tag = el.tagName.toLowerCase()
80
78
  const indent = " ".repeat(depth)
81
79
 
@@ -99,7 +97,7 @@ export class BrowserController {
99
97
  if (href && tag === "a") attrs.push(`href="${esc(href.slice(0, 80))}"`)
100
98
 
101
99
  const val = (el as HTMLInputElement).value
102
- if (val) attrs.push(`value="${esc(val.slice(0, 40))}"`)
100
+ if (val) attrs.push(`value="${esc(val)}"`)
103
101
 
104
102
  if ((el as any).disabled) attrs.push(`disabled="true"`)
105
103
  if ((el as any).checked) attrs.push(`checked="true"`)
@@ -108,7 +106,7 @@ export class BrowserController {
108
106
  if (el.getAttribute("aria-expanded")) attrs.push(`expanded="${el.getAttribute("aria-expanded")}"`)
109
107
  if (el.getAttribute("aria-selected") === "true") attrs.push(`selected="true"`)
110
108
 
111
- const text = el.textContent?.trim().slice(0, 60) || ""
109
+ const text = el.textContent?.trim() || ""
112
110
  const ariaLabel = el.getAttribute("aria-label")
113
111
  const placeholder = (el as HTMLInputElement).placeholder
114
112
  const label = esc(ariaLabel || text || placeholder || "")
@@ -123,7 +121,6 @@ export class BrowserController {
123
121
  .map(n => n.textContent?.trim())
124
122
  .join(" ")
125
123
  .trim()
126
- .slice(0, 120)
127
124
 
128
125
  if (directText.length > 2) {
129
126
  out.push(`${indent}<${tag}>${esc(directText)}</${tag}>`)