@magpie-community/opencode-trae-auth 0.2.10 → 0.2.11

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 +56 -2
  2. package/package.json +1 -1
package/index.mjs CHANGED
@@ -1022,6 +1022,7 @@ class TextTools {
1022
1022
  this.tools = tools
1023
1023
  this.sent = "" // the text given out so far, to tell a block in code from a call
1024
1024
  this.bad = new Set() // where the waiting block's JSON was tried and not read, not tried again
1025
+ this.mark = 0 // where in sent the text after the last call starts
1025
1026
  }
1026
1027
  push(s, end = false) {
1027
1028
  this.buf += s
@@ -1044,6 +1045,27 @@ class TextTools {
1044
1045
  const i = om ? om.index : -1
1045
1046
  const d = this.buf.search(DSML_AT)
1046
1047
  const r = this.buf.search(REASON_AT)
1048
+ const sm = this.buf.match(STRAY_AT)
1049
+ const s = sm ? sm.index : -1
1050
+ if (s >= 0 && [i, d, r].every((x) => x < 0 || s < x)) {
1051
+ // a close with no call open, with what GLM left before it
1052
+ // (}}</tool_call>, magpie#1945): not the answer, dropped; in code,
1053
+ // shown
1054
+ const head = this.buf.slice(0, s)
1055
+ // only a tail: a close with nothing before it since the last call
1056
+ // (or the start), or with GLM's braces, quotes or > right before
1057
+ // it; a close a sentence names in passing stays
1058
+ const tail = /^[}\]"'>]/.test(sm[0]) || !(this.sent + text + head).slice(this.mark).trim()
1059
+ if (!tail || quoted(this.sent + text + head)) {
1060
+ text += this.buf.slice(0, s + sm[0].length)
1061
+ this.buf = this.buf.slice(s + sm[0].length)
1062
+ continue
1063
+ }
1064
+ text += head
1065
+ this.buf = this.buf.slice(s + sm[0].length)
1066
+ this.after = true
1067
+ continue
1068
+ }
1047
1069
  if (r >= 0 && (i < 0 || r < i) && (d < 0 || r < d)) {
1048
1070
  const o = objectEnd(this.buf, r)
1049
1071
  if (o === -1 && !end) {
@@ -1095,6 +1117,7 @@ class TextTools {
1095
1117
  stop = body.length
1096
1118
  }
1097
1119
  calls.push({ name: inv[1], arguments: dsmlArgs(body.slice(0, stop)) })
1120
+ this.mark = this.sent.length + text.length
1098
1121
  this.buf = body.slice(c && c.index === stop ? stop + c[0].length : stop)
1099
1122
  this.after = true
1100
1123
  continue
@@ -1136,6 +1159,7 @@ class TextTools {
1136
1159
  return { text, calls, reasoning, error: b.error }
1137
1160
  }
1138
1161
  calls.push(b.call)
1162
+ this.mark = this.sent.length + text.length
1139
1163
  this.buf = b.rest
1140
1164
  this.after = true
1141
1165
  }
@@ -1156,6 +1180,9 @@ class TextTools {
1156
1180
  const at = [this.buf.search(OPEN_AT), this.buf.search(OPEN_HOLD), this.buf.search(DSML_AT), this.buf.search(REASON_AT)].filter((x) => x >= 0)
1157
1181
  let keep = at.length ? this.buf.length - Math.min(...at) : 0
1158
1182
  if (!keep) for (let k = Math.min(MARK_MAX - 1, this.buf.length); k > 0; k--) if (MARKS.some((m) => m.startsWith(this.buf.slice(-k)))) { keep = k; break }
1183
+ // and braces, brackets, quotes or a > a close may still come after
1184
+ const sh = this.buf.slice(0, this.buf.length - keep).match(STRAY_HOLD)
1185
+ if (sh) keep = this.buf.length - sh.index
1159
1186
  text += this.buf.slice(0, this.buf.length - keep)
1160
1187
  this.buf = this.buf.slice(this.buf.length - keep)
1161
1188
  }
@@ -1205,8 +1232,27 @@ class TextTools {
1205
1232
  const v = callJSON(body.slice(0, o))
1206
1233
  // a name alone may have its parameters still to come
1207
1234
  if (v && !end && Object.keys(v).length === 1 && "<parameter".startsWith(body.slice(o).replace(/^\s*>?\s*/, ""))) return { wait: true }
1208
- if (v) return { call: { name: String(v.name), arguments: callArgs(v) }, rest: body.slice(o) }
1209
- this.bad.add(":" + o)
1235
+ if (v) {
1236
+ // what follows the object up to the close: GLM leaves braces,
1237
+ // brackets, quotes or a > of its own there (}}</tool_call>,
1238
+ // "></tool_call>, magpie#1945), dropped with the close; held
1239
+ // while only those have come
1240
+ const tail = body.slice(o)
1241
+ const junk = tail.match(TAIL_JUNK)[0]
1242
+ const next = tail.slice(junk.length)
1243
+ const call = { name: String(v.name), arguments: callArgs(v) }
1244
+ if (!end && (!next || ["</tool_call>", "</toolcall>"].some((k) => k.startsWith(next)))) return { wait: true }
1245
+ const [c, n] = closeAt(next)
1246
+ if (c === 0) return { call, rest: next.slice(n) }
1247
+ // after blanks alone, or with no close to come: the call, and
1248
+ // what follows read on as before. Other text before the close
1249
+ // right after the object means the object ended early, at a
1250
+ // quote inside a string left unescaped: that cut is wrong (a
1251
+ // heredoc's command cut short, magpie#1945), so it is read up to
1252
+ // the close below, or not at all
1253
+ if (!/\S/.test(junk) && !/^[^\s<]/.test(next)) return { call, rest: tail }
1254
+ if (close < 0 && end) return { call, rest: tail }
1255
+ } else this.bad.add(":" + o)
1210
1256
  }
1211
1257
  // not whole, or not JSON as it stands: read up to a close (a file's
1212
1258
  // content may hold one), or at the end all of it
@@ -1241,6 +1287,14 @@ const UNREADABLE = "the model's tool call, written as text, can't be read; it is
1241
1287
  // also writes it without the underscore, <toolcall> (plugins#38)
1242
1288
  const OPEN_AT = /<tool_?call(?:(\s[^<>{}]*)?>|(?=\s*\{))/
1243
1289
  const OPEN_HOLD = /<tool_?call(?:\s[^<>{}\n]{0,200})?$/
1290
+ // what GLM leaves between a call's JSON and its close: blanks, closing
1291
+ // braces and brackets, quotes, a > (magpie#1945)
1292
+ const TAIL_JUNK = /^[\s}\]"'>]*/
1293
+ // a close with no call open, and that leftover before it: the tail of a
1294
+ // call Trae's service read itself, or of one already read (magpie#1945)
1295
+ const STRAY_AT = /[}\]"'>]*\s*<\/tool_?calls?>/
1296
+ // the end of text that may be such a tail still being written
1297
+ const STRAY_HOLD = /[}\]"'>][\s}\]"'>]*$/
1244
1298
  // closeAt is where the next close is from i, </tool_call> or </toolcall>,
1245
1299
  // and its length: [-1, 0] when there is none
1246
1300
  function closeAt(s, i = 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magpie-community/opencode-trae-auth",
3
- "version": "0.2.10",
3
+ "version": "0.2.11",
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",