@magpie-community/opencode-trae-auth 0.2.6 → 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/README.md +9 -1
- package/index.mjs +58 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -138,7 +138,15 @@ a bigger `context_window_tokens.max` is listed again as its Max,
|
|
|
138
138
|
can name the `__max` model, a SOLO list the windows). It asks the
|
|
139
139
|
`__max` model through the function that names it, with `max_tokens` set
|
|
140
140
|
and `user_message_context.model_info.prompt_max_tokens` the window less
|
|
141
|
-
it, as Max mode does.
|
|
141
|
+
it, as Max mode does. The lists needn't agree on a model's *name*: chat_v3
|
|
142
|
+
calls deepseek-v4.1-flash "DeepSeek-V4-Flash 正式版", as it once called
|
|
143
|
+
DeepSeek-V4-Flash-Official, where the SOLO lists call it
|
|
144
|
+
"DeepSeek-V4.1-Flash" (yetone/magpie#681). Trae's usage page books a
|
|
145
|
+
request under the name of the list it was served through, so the plugin
|
|
146
|
+
takes the name most of a model's lists give — the one Trae's own client is
|
|
147
|
+
served under — and asks that model, and its Max, through a list carrying
|
|
148
|
+
it. Trae renamed its official entries on 2026-10-09, leaving the name its
|
|
149
|
+
lists mostly agree on the only thing that tells a misnamed entry apart.
|
|
142
150
|
|
|
143
151
|
Reasoning: the models reason, but Trae's request takes no effort or
|
|
144
152
|
thinking level, so the plugin lists no variants and a level an agent
|
package/index.mjs
CHANGED
|
@@ -1338,6 +1338,31 @@ function toolNamed(name, tools) {
|
|
|
1338
1338
|
return names.find((n) => norm(n) === norm(name)) ?? name
|
|
1339
1339
|
}
|
|
1340
1340
|
|
|
1341
|
+
// unwrapped is a call's arguments with the layer a model put around them
|
|
1342
|
+
// taken off: asked for {"name":…,"arguments":{…}}, some write the
|
|
1343
|
+
// arguments as {"arguments":{…}} again, natively or in the block, and the
|
|
1344
|
+
// agent got {"arguments":{"content":…,"path":…}} for its write (bee2an on
|
|
1345
|
+
// X). A lone arguments, input, parameters or args key holding an object is
|
|
1346
|
+
// that layer when the tool has no parameter of that name.
|
|
1347
|
+
const WRAPS = ["arguments", "input", "parameters", "args"]
|
|
1348
|
+
function unwrapped(args, name, tools) {
|
|
1349
|
+
const t = tools.map((x) => x.function ?? x).find((f) => f?.name === name)
|
|
1350
|
+
if (!t) return args
|
|
1351
|
+
const props = t.parameters?.properties ?? {}
|
|
1352
|
+
let v = looseJSON(args)
|
|
1353
|
+
let changed = false
|
|
1354
|
+
for (let k = 0; k < 3 && v && typeof v === "object" && !Array.isArray(v); k++) {
|
|
1355
|
+
const keys = Object.keys(v)
|
|
1356
|
+
if (keys.length !== 1 || !WRAPS.includes(keys[0]) || keys[0] in props) break
|
|
1357
|
+
let inner = v[keys[0]]
|
|
1358
|
+
if (typeof inner === "string") inner = looseJSON(inner)
|
|
1359
|
+
if (!inner || typeof inner !== "object" || Array.isArray(inner)) break
|
|
1360
|
+
v = inner
|
|
1361
|
+
changed = true
|
|
1362
|
+
}
|
|
1363
|
+
return changed ? JSON.stringify(v) : args
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1341
1366
|
// DeepSeek's tags, with its full-width bar or a plain one
|
|
1342
1367
|
const DSML = String.raw`<\s*\/?\s*[||][\s||]*DSML[\s||]*`
|
|
1343
1368
|
const DSML_AT = new RegExp(DSML)
|
|
@@ -1569,7 +1594,10 @@ async function* parts(events, tools = []) {
|
|
|
1569
1594
|
const tt = new TextTools(tools)
|
|
1570
1595
|
const nc = new NativeCalls()
|
|
1571
1596
|
const th = new Thoughts()
|
|
1572
|
-
const call = (c) =>
|
|
1597
|
+
const call = (c) => {
|
|
1598
|
+
const name = toolNamed(c.name, tools)
|
|
1599
|
+
return { call: { ...c, name, arguments: unwrapped(c.arguments, name, tools) } }
|
|
1600
|
+
}
|
|
1573
1601
|
let finish = ""
|
|
1574
1602
|
for await (const { event, data } of events) {
|
|
1575
1603
|
const name = eventName(event)
|
|
@@ -2042,24 +2070,40 @@ const makePlugin = (site) => async ({ client }) => {
|
|
|
2042
2070
|
// deepseek-v4.1-flash "DeepSeek-V4-Flash 正式版", as it does
|
|
2043
2071
|
// DeepSeek-V4-Flash-Official, where SOLO's lists call it
|
|
2044
2072
|
// DeepSeek-V4.1-Flash (yetone/magpie#681) — Trae's usage page then books
|
|
2045
|
-
//
|
|
2046
|
-
// model's in the same list, and
|
|
2073
|
+
// a request under the name of the list it was served through. Such an
|
|
2074
|
+
// entry is misnamed: its name is another model's in the same list, and
|
|
2075
|
+
// other lists name it otherwise.
|
|
2047
2076
|
const nameOf = (m) => String(m.display_config?.display_name || m.display_name || m.display_model_name || m.config_name)
|
|
2048
|
-
const names = new Map() // id → the names its lists give it
|
|
2077
|
+
const names = new Map() // id → the names its lists give it, and how many give each
|
|
2049
2078
|
for (const fn of site.functions) {
|
|
2050
2079
|
for (const m of lists[fn] ?? []) {
|
|
2051
2080
|
if (!chatModel(m, site)) continue
|
|
2052
|
-
const id = String(m.config_name)
|
|
2053
|
-
|
|
2081
|
+
const id = String(m.config_name), name = nameOf(m)
|
|
2082
|
+
const by = names.get(id) ?? new Map()
|
|
2083
|
+
by.set(name, (by.get(name) ?? 0) + 1)
|
|
2084
|
+
names.set(id, by)
|
|
2054
2085
|
}
|
|
2055
2086
|
}
|
|
2087
|
+
// the name most of a model's lists give it: the one Trae's own client is
|
|
2088
|
+
// served under, and so the one its usage page books it as. Trae renames
|
|
2089
|
+
// entries when it likes, and its 2026-10-09 rename of
|
|
2090
|
+
// DeepSeek-V4-Flash-Official left chat_v3 the only list still calling
|
|
2091
|
+
// deepseek-v4.1-flash by another's name — which neither signal above
|
|
2092
|
+
// catches. A tie leaves the name to its entry.
|
|
2093
|
+
const agreed = new Map() // id → that name, "" when the lists tie
|
|
2094
|
+
for (const [id, by] of names) {
|
|
2095
|
+
const top = Math.max(...by.values())
|
|
2096
|
+
const most = [...by].filter(([, n]) => n === top)
|
|
2097
|
+
agreed.set(id, most.length === 1 ? most[0][0] : "")
|
|
2098
|
+
}
|
|
2056
2099
|
const misnamed = (fn, m) => {
|
|
2057
2100
|
const id = String(m.config_name), name = nameOf(m)
|
|
2058
2101
|
return names.get(id).size > 1 && (lists[fn] ?? []).some((o) => chatModel(o, site) && String(o.config_name) !== id && nameOf(o) === name)
|
|
2059
2102
|
}
|
|
2060
2103
|
// a function's entry is worth more when it names a __dev model, then
|
|
2061
|
-
// when it isn't misnamed
|
|
2062
|
-
|
|
2104
|
+
// when it isn't misnamed, then when it carries the name its lists agree
|
|
2105
|
+
// on; the first of the best is taken
|
|
2106
|
+
const worth = (fn, m) => (devModel(m) ? 2 : 0) + (misnamed(fn, m) ? 0 : 1) + (nameOf(m) === agreed.get(String(m.config_name)) ? 1 : 0)
|
|
2063
2107
|
const out = new Map()
|
|
2064
2108
|
for (const fn of site.functions) {
|
|
2065
2109
|
for (const m of lists[fn] ?? []) {
|
|
@@ -2075,8 +2119,11 @@ const makePlugin = (site) => async ({ client }) => {
|
|
|
2075
2119
|
if (dev) modelNames.set(id, { fn, name: dev.model_name, most: Number(dev.max_tokens) || 0 })
|
|
2076
2120
|
else modelNames.delete(id)
|
|
2077
2121
|
if (out.has(id + MAX)) continue
|
|
2078
|
-
// its Max is asked through the function whose entry names the __max
|
|
2079
|
-
|
|
2122
|
+
// its Max is asked through the function whose entry names the __max
|
|
2123
|
+
// model, the entries carrying the agreed name first: Trae books the
|
|
2124
|
+
// Max under that name too
|
|
2125
|
+
const plain = (e) => (nameOf(e.m) === agreed.get(id) ? 0 : 1)
|
|
2126
|
+
const entries = [{ m, fn }, ...site.functions.flatMap((f) => (lists[f] ?? []).filter((o) => o !== m && chatModel(o, site) && String(o.config_name) === id).map((o) => ({ m: o, fn: f })))].sort((a, b) => plain(a) - plain(b))
|
|
2080
2127
|
const max = maxModel(...entries.map((e) => e.m))
|
|
2081
2128
|
maxes.set(id, max)
|
|
2082
2129
|
if (max) {
|
|
@@ -2282,4 +2329,4 @@ const makePlugin = (site) => async ({ client }) => {
|
|
|
2282
2329
|
export const TraeCNAuthPlugin = makePlugin(SITES["trae-cn"])
|
|
2283
2330
|
export const TraeGlobalAuthPlugin = makePlugin(SITES["trae-global"])
|
|
2284
2331
|
|
|
2285
|
-
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 }
|
|
2332
|
+
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.8",
|
|
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",
|