@magpie-community/opencode-trae-auth 0.2.7 → 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.
- package/index.mjs +60 -14
- 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
|
|
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 +
|
|
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 +
|
|
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
|
|
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 +
|
|
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 +
|
|
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
|
-
|
|
1160
|
-
const
|
|
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(/<\/
|
|
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
|
|
@@ -1338,6 +1356,31 @@ function toolNamed(name, tools) {
|
|
|
1338
1356
|
return names.find((n) => norm(n) === norm(name)) ?? name
|
|
1339
1357
|
}
|
|
1340
1358
|
|
|
1359
|
+
// unwrapped is a call's arguments with the layer a model put around them
|
|
1360
|
+
// taken off: asked for {"name":…,"arguments":{…}}, some write the
|
|
1361
|
+
// arguments as {"arguments":{…}} again, natively or in the block, and the
|
|
1362
|
+
// agent got {"arguments":{"content":…,"path":…}} for its write (bee2an on
|
|
1363
|
+
// X). A lone arguments, input, parameters or args key holding an object is
|
|
1364
|
+
// that layer when the tool has no parameter of that name.
|
|
1365
|
+
const WRAPS = ["arguments", "input", "parameters", "args"]
|
|
1366
|
+
function unwrapped(args, name, tools) {
|
|
1367
|
+
const t = tools.map((x) => x.function ?? x).find((f) => f?.name === name)
|
|
1368
|
+
if (!t) return args
|
|
1369
|
+
const props = t.parameters?.properties ?? {}
|
|
1370
|
+
let v = looseJSON(args)
|
|
1371
|
+
let changed = false
|
|
1372
|
+
for (let k = 0; k < 3 && v && typeof v === "object" && !Array.isArray(v); k++) {
|
|
1373
|
+
const keys = Object.keys(v)
|
|
1374
|
+
if (keys.length !== 1 || !WRAPS.includes(keys[0]) || keys[0] in props) break
|
|
1375
|
+
let inner = v[keys[0]]
|
|
1376
|
+
if (typeof inner === "string") inner = looseJSON(inner)
|
|
1377
|
+
if (!inner || typeof inner !== "object" || Array.isArray(inner)) break
|
|
1378
|
+
v = inner
|
|
1379
|
+
changed = true
|
|
1380
|
+
}
|
|
1381
|
+
return changed ? JSON.stringify(v) : args
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1341
1384
|
// DeepSeek's tags, with its full-width bar or a plain one
|
|
1342
1385
|
const DSML = String.raw`<\s*\/?\s*[||][\s||]*DSML[\s||]*`
|
|
1343
1386
|
const DSML_AT = new RegExp(DSML)
|
|
@@ -1348,9 +1391,9 @@ const DSML_CLOSE = new RegExp(String.raw`<\s*\/\s*[||][\s||]*DSML[\s||]*in
|
|
|
1348
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")
|
|
1349
1392
|
// what is left after a call: blanks, our close, DeepSeek's tags but the
|
|
1350
1393
|
// next call's
|
|
1351
|
-
const LEFTOVER = new RegExp(String.raw`^(?:\s+|<\/
|
|
1394
|
+
const LEFTOVER = new RegExp(String.raw`^(?:\s+|<\/tool_?calls?>|<tool_?calls>|` + DSML + String.raw`(?![\s||]*invoke\b)[^<>]*>)+`)
|
|
1352
1395
|
// what text may be the start of, so held back
|
|
1353
|
-
const MARKS = [OPEN, CLOSE, "<|DSML|", "<|DSML|", "</|DSML|", "</|DSML|", '{"reasoning_content"']
|
|
1396
|
+
const MARKS = [OPEN, CLOSE, "<toolcall>", "</toolcall>", "<|DSML|", "<|DSML|", "</|DSML|", "</|DSML|", '{"reasoning_content"']
|
|
1354
1397
|
// reasoning a model wrote into its text as JSON
|
|
1355
1398
|
const REASON_AT = /\{\s*"reasoning_content"\s*:/
|
|
1356
1399
|
const MARK_MAX = Math.max(...MARKS.map((m) => m.length))
|
|
@@ -1569,7 +1612,10 @@ async function* parts(events, tools = []) {
|
|
|
1569
1612
|
const tt = new TextTools(tools)
|
|
1570
1613
|
const nc = new NativeCalls()
|
|
1571
1614
|
const th = new Thoughts()
|
|
1572
|
-
const call = (c) =>
|
|
1615
|
+
const call = (c) => {
|
|
1616
|
+
const name = toolNamed(c.name, tools)
|
|
1617
|
+
return { call: { ...c, name, arguments: unwrapped(c.arguments, name, tools) } }
|
|
1618
|
+
}
|
|
1573
1619
|
let finish = ""
|
|
1574
1620
|
for await (const { event, data } of events) {
|
|
1575
1621
|
const name = eventName(event)
|
|
@@ -2301,4 +2347,4 @@ const makePlugin = (site) => async ({ client }) => {
|
|
|
2301
2347
|
export const TraeCNAuthPlugin = makePlugin(SITES["trae-cn"])
|
|
2302
2348
|
export const TraeGlobalAuthPlugin = makePlugin(SITES["trae-global"])
|
|
2303
2349
|
|
|
2304
|
-
export const _internal = { HOSTS: SITES["trae-cn"].hosts, MODELS: SITES["trae-cn"].models, TextTools, NativeCalls, looseJSON, glmCall, toolNamed, traeMessages, chatBody, credits, dollarUsageOf, whenOf, newDevice, proofOf, SITES, SESSION, conversationID }
|
|
2350
|
+
export const _internal = { HOSTS: SITES["trae-cn"].hosts, MODELS: SITES["trae-cn"].models, TextTools, NativeCalls, looseJSON, glmCall, toolNamed, unwrapped, traeMessages, chatBody, credits, dollarUsageOf, whenOf, newDevice, proofOf, SITES, SESSION, conversationID }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@magpie-community/opencode-trae-auth",
|
|
3
|
-
"version": "0.2.
|
|
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",
|