@magpie-community/opencode-trae-auth 0.2.8 → 0.2.9

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/index.mjs +30 -12
  2. package/package.json +1 -1
package/index.mjs CHANGED
@@ -1067,6 +1067,15 @@ class TextTools {
1067
1067
  this.after = true
1068
1068
  }
1069
1069
  if (end) {
1070
+ // an opener the stream ended inside (<tool_call name): a call cut
1071
+ // short, not the answer (plugins#38)
1072
+ const h = this.buf.search(OPEN_HOLD)
1073
+ if (h >= 0 && !quoted(this.sent + text + this.buf.slice(0, h))) {
1074
+ text += this.buf.slice(0, h)
1075
+ this.buf = ""
1076
+ this.sent += text
1077
+ return { text, calls, reasoning, error: CUT_SHORT }
1078
+ }
1070
1079
  text += this.buf
1071
1080
  this.buf = ""
1072
1081
  } else {
@@ -1088,11 +1097,11 @@ class TextTools {
1088
1097
  // gave as <tool_call name="…">.
1089
1098
  block(body, named, end) {
1090
1099
  if (!end && !body.trim()) return { wait: true }
1091
- const close = body.indexOf(CLOSE)
1100
+ const [close, closeLen] = closeAt(body)
1092
1101
  if (named) {
1093
1102
  if (close < 0 && !end) return { wait: true }
1094
1103
  const region = close >= 0 ? body.slice(0, close) : body
1095
- const rest = close >= 0 ? body.slice(close + CLOSE.length) : ""
1104
+ const rest = close >= 0 ? body.slice(close + closeLen) : ""
1096
1105
  if (region.trimStart().startsWith("{")) {
1097
1106
  const v = repairedJSON(region.trim())
1098
1107
  if (!v) return { error: close >= 0 ? UNREADABLE : CUT_SHORT }
@@ -1116,7 +1125,7 @@ class TextTools {
1116
1125
  const region = body.slice(ph[0].length, close >= 0 ? close : body.length)
1117
1126
  const p = paramArgs(region, ph[1], this.tools)
1118
1127
  if (close < 0 && !p.closed) return { error: CUT_SHORT }
1119
- return { call: { name: ph[1], arguments: JSON.stringify(p.args) }, rest: close >= 0 ? body.slice(close + CLOSE.length) : "" }
1128
+ return { call: { name: ph[1], arguments: JSON.stringify(p.args) }, rest: close >= 0 ? body.slice(close + closeLen) : "" }
1120
1129
  }
1121
1130
  const o = objectEnd(body, 0)
1122
1131
  if (o > 0 && !this.bad.has(":" + o)) {
@@ -1128,10 +1137,10 @@ class TextTools {
1128
1137
  }
1129
1138
  // not whole, or not JSON as it stands: read up to a close (a file's
1130
1139
  // content may hold one), or at the end all of it
1131
- for (let j = close; j >= 0; j = body.indexOf(CLOSE, j + 1)) {
1140
+ for (let [j, n] = [close, closeLen]; j >= 0; [j, n] = closeAt(body, j + 1)) {
1132
1141
  if (this.bad.has("<" + j)) continue
1133
1142
  const v = callJSON(body.slice(0, j))
1134
- if (v) return { call: { name: String(v.name), arguments: callArgs(v) }, rest: body.slice(j + CLOSE.length) }
1143
+ if (v) return { call: { name: String(v.name), arguments: callArgs(v) }, rest: body.slice(j + n) }
1135
1144
  this.bad.add("<" + j)
1136
1145
  }
1137
1146
  if (!end) return { wait: true }
@@ -1145,7 +1154,7 @@ class TextTools {
1145
1154
  const region = close >= 0 ? body.slice(0, close) : body
1146
1155
  const w = glmCall(region, this.tools)
1147
1156
  // GLM's call, cut short at the end, is still the call
1148
- if (w) return { call: { name: w.name, arguments: callArgs(w) }, rest: close >= 0 ? body.slice(close + CLOSE.length) : "" }
1157
+ if (w) return { call: { name: w.name, arguments: callArgs(w) }, rest: close >= 0 ? body.slice(close + closeLen) : "" }
1149
1158
  if (/^\s*[\w.:-]{1,128}\s*<arg_key>/.test(body)) return { error: close >= 0 ? UNREADABLE : CUT_SHORT }
1150
1159
  return { text: true }
1151
1160
  }
@@ -1155,9 +1164,18 @@ const CUT_SHORT = "the model's tool call, written as text, was cut short; it is
1155
1164
  const UNREADABLE = "the model's tool call, written as text, can't be read; it is not sent on as the answer"
1156
1165
 
1157
1166
  // an opener: <tool_call>, one with attributes (<tool_call name="bash">),
1158
- // or <tool_call right before its JSON; and one still being written
1159
- const OPEN_AT = /<tool_call(?:(\s[^<>{}]*)?>|(?=\s*\{))/
1160
- const OPEN_HOLD = /<tool_call(?:\s[^<>{}\n]{0,200})?$/
1167
+ // or <tool_call right before its JSON; and one still being written. GLM
1168
+ // also writes it without the underscore, <toolcall> (plugins#38)
1169
+ const OPEN_AT = /<tool_?call(?:(\s[^<>{}]*)?>|(?=\s*\{))/
1170
+ const OPEN_HOLD = /<tool_?call(?:\s[^<>{}\n]{0,200})?$/
1171
+ // closeAt is where the next close is from i, </tool_call> or </toolcall>,
1172
+ // and its length: [-1, 0] when there is none
1173
+ function closeAt(s, i = 0) {
1174
+ const re = /<\/tool_?call>/g
1175
+ re.lastIndex = i
1176
+ const m = re.exec(s)
1177
+ return m ? [m.index, m[0].length] : [-1, 0]
1178
+ }
1161
1179
  // DeepSeek's half-and-half call: {"name":"x"} (or its brace or > left
1162
1180
  // out), then <parameter name="k">v</parameter> or Qwen's <parameter=k>
1163
1181
  const PARAM_HEAD = /^\s*\{\s*"name"\s*:\s*"([^"]+)"\s*\}?\s*>?\s*(?=<parameter\b)/
@@ -1303,7 +1321,7 @@ const GLM_ARG = /<arg_key>\s*([\s\S]*?)\s*<\/arg_key>\s*<arg_value>([\s\S]*?)<\/
1303
1321
  // a value that isn't a string. A name alone is a call only to a tool the
1304
1322
  // request has.
1305
1323
  function glmCall(s, tools = []) {
1306
- s = String(s ?? "").replace(/<\/tool_call>\s*$/, "")
1324
+ s = String(s ?? "").replace(/<\/tool_?call>\s*$/, "")
1307
1325
  const k = s.indexOf("<arg_key>")
1308
1326
  const name = (k < 0 ? s : s.slice(0, k)).trim()
1309
1327
  if (!/^[\w.:-]{1,128}$/.test(name)) return null
@@ -1373,9 +1391,9 @@ const DSML_CLOSE = new RegExp(String.raw`<\s*\/\s*[||][\s||]*DSML[\s||]*in
1373
1391
  const DSML_PARAM = new RegExp(String.raw`<\s*[||][\s||]*DSML[\s||]*parameter\s+name\s*=\s*"([^"]+)"((?:\s+\w+\s*=\s*"[^"]*")*)\s*>([\s\S]*?)` + DSML + String.raw`parameter\s*>`, "g")
1374
1392
  // what is left after a call: blanks, our close, DeepSeek's tags but the
1375
1393
  // next call's
1376
- const LEFTOVER = new RegExp(String.raw`^(?:\s+|<\/tool_calls?>|<tool_calls>|` + DSML + String.raw`(?![\s||]*invoke\b)[^<>]*>)+`)
1394
+ const LEFTOVER = new RegExp(String.raw`^(?:\s+|<\/tool_?calls?>|<tool_?calls>|` + DSML + String.raw`(?![\s||]*invoke\b)[^<>]*>)+`)
1377
1395
  // what text may be the start of, so held back
1378
- const MARKS = [OPEN, CLOSE, "<|DSML|", "<|DSML|", "</|DSML|", "</|DSML|", '{"reasoning_content"']
1396
+ const MARKS = [OPEN, CLOSE, "<toolcall>", "</toolcall>", "<|DSML|", "<|DSML|", "</|DSML|", "</|DSML|", '{"reasoning_content"']
1379
1397
  // reasoning a model wrote into its text as JSON
1380
1398
  const REASON_AT = /\{\s*"reasoning_content"\s*:/
1381
1399
  const MARK_MAX = Math.max(...MARKS.map((m) => m.length))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magpie-community/opencode-trae-auth",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
4
4
  "description": "OpenCode provider plugins for Trae: Trae CN (trae.cn) and Trae Global (trae.ai), free tier included, with Trae's own browser sign-in",
5
5
  "type": "module",
6
6
  "main": "./index.mjs",