trinity-config 1.2.2 → 1.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/README.md CHANGED
@@ -4,6 +4,8 @@
4
4
 
5
5
  协议按 `GET /v1/models/{code}` 的 `capabilities.text.interfaces` **自动择优**(Anthropic → Responses → Completions),再与工具能力求交。
6
6
 
7
+ 写入客户端的模型列表来自 `GET /v1/models?modality=text`(仅生文/多模态,不含生图/生视频)。
8
+
7
9
  ```bash
8
10
  npx -y trinity-config --type zcode -k xh-你的key --model gpt-5.4
9
11
  ```
@@ -0,0 +1,26 @@
1
+ // src/text-models.ts
2
+ function isLikelyNonTextModel(id) {
3
+ const lower = id.toLowerCase();
4
+ return lower.includes("image") || lower.includes("video") || lower.includes("seedance") || lower.includes("wan-") || lower.includes("kling") || lower.includes("og-image") || lower.includes("midjourney") || lower.includes("flux");
5
+ }
6
+ function filterTextModelIds(primaryModel, modelIds, limit = 80) {
7
+ const ids = [];
8
+ const seen = /* @__PURE__ */ new Set();
9
+ const push = (raw) => {
10
+ const trimmed = raw?.trim();
11
+ if (!trimmed || seen.has(trimmed)) return;
12
+ if (ids.length > 0 && isLikelyNonTextModel(trimmed)) return;
13
+ seen.add(trimmed);
14
+ ids.push(trimmed);
15
+ };
16
+ push(primaryModel);
17
+ for (const id of modelIds ?? []) {
18
+ if (ids.length >= limit) break;
19
+ push(id);
20
+ }
21
+ return ids;
22
+ }
23
+
24
+ export {
25
+ filterTextModelIds
26
+ };
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import pc from "picocolors";
5
5
 
6
6
  // src/constants.ts
7
7
  var PACKAGE_NAME = "trinity-config";
8
- var PACKAGE_VERSION = "1.2.2";
8
+ var PACKAGE_VERSION = "1.2.4";
9
9
  var TRINITY_BASE_URL = "https://api.trinitydesk.ai";
10
10
  var DEFAULT_CLAUDE_MODEL = "claude-sonnet-4-6";
11
11
  var DEFAULT_CLAUDE_FAST_MODEL = "claude-sonnet-4-6";
@@ -422,7 +422,7 @@ async function configureCodex(apiKey, codexBaseUrl, codexModel, _verbose) {
422
422
  return configureCodexDirect(apiKey, codexBaseUrl, codexModel);
423
423
  }
424
424
  async function configureOpenCode(apiKey, openCodeBaseUrl, model, modelIds, protocol) {
425
- const { configureOpenCodeDirect } = await import("./merge-opencode-config-24P7MV7L.js");
425
+ const { configureOpenCodeDirect } = await import("./merge-opencode-config-XGIZYPOW.js");
426
426
  return configureOpenCodeDirect({
427
427
  apiKey,
428
428
  baseUrl: openCodeBaseUrl,
@@ -432,7 +432,7 @@ async function configureOpenCode(apiKey, openCodeBaseUrl, model, modelIds, proto
432
432
  });
433
433
  }
434
434
  async function configureOpenClaw(apiKey, openClawBaseUrl, model, modelIds, protocol) {
435
- const { configureOpenClawDirect } = await import("./merge-openclaw-config-BNKTK35F.js");
435
+ const { configureOpenClawDirect } = await import("./merge-openclaw-config-KMG3FYK6.js");
436
436
  return configureOpenClawDirect({
437
437
  apiKey,
438
438
  baseUrl: openClawBaseUrl,
@@ -442,7 +442,7 @@ async function configureOpenClaw(apiKey, openClawBaseUrl, model, modelIds, proto
442
442
  });
443
443
  }
444
444
  async function configureZCode(apiKey, zcodeBaseUrl, model, modelIds, protocol) {
445
- const { configureZCodeDirect } = await import("./merge-zcode-config-U4V7XCYT.js");
445
+ const { configureZCodeDirect } = await import("./merge-zcode-config-PTPY6RXN.js");
446
446
  return configureZCodeDirect({
447
447
  apiKey,
448
448
  baseUrl: zcodeBaseUrl,
@@ -496,7 +496,7 @@ function getJson2(url, apiKey) {
496
496
  }
497
497
  async function verifyTrinityApi(apiKey, baseUrl = TRINITY_BASE_URL) {
498
498
  const root = baseUrl.replace(/\/+$/, "");
499
- const modelsUrl = `${root}/v1/models`;
499
+ const modelsUrl = `${root}/v1/models?modality=text`;
500
500
  try {
501
501
  const { statusCode, body } = await getJson2(modelsUrl, apiKey);
502
502
  if (statusCode === 401 || statusCode === 403) {
@@ -532,7 +532,7 @@ async function verifyTrinityApi(apiKey, baseUrl = TRINITY_BASE_URL) {
532
532
  return {
533
533
  ok: true,
534
534
  statusCode,
535
- message: `\u8FDE\u901A\u6210\u529F\uFF08${modelIds.length} \u4E2A\u6A21\u578B\uFF09`,
535
+ message: `\u8FDE\u901A\u6210\u529F\uFF08${modelIds.length} \u4E2A\u751F\u6587\u6A21\u578B\uFF09`,
536
536
  modelIds
537
537
  };
538
538
  } catch (error) {
@@ -1,3 +1,7 @@
1
+ import {
2
+ filterTextModelIds
3
+ } from "./chunk-QS4QYSMM.js";
4
+
1
5
  // src/merge-openclaw-config.ts
2
6
  import fs from "fs";
3
7
  import os from "os";
@@ -47,21 +51,8 @@ function readOpenClawConfig() {
47
51
  );
48
52
  }
49
53
  }
50
- function isLikelyNonTextModel(id) {
51
- const lower = id.toLowerCase();
52
- return lower.includes("image") || lower.includes("video") || lower.includes("seedance") || lower.includes("wan-") || lower.includes("kling");
53
- }
54
54
  function buildModelEntries(primaryModel, modelIds) {
55
- const ids = [primaryModel];
56
- const seen = new Set(ids);
57
- for (const id of modelIds ?? []) {
58
- const trimmed = id?.trim();
59
- if (!trimmed || seen.has(trimmed) || isLikelyNonTextModel(trimmed)) continue;
60
- seen.add(trimmed);
61
- ids.push(trimmed);
62
- if (ids.length >= 80) break;
63
- }
64
- return ids.map((id) => ({
55
+ return filterTextModelIds(primaryModel, modelIds).map((id) => ({
65
56
  id,
66
57
  name: id,
67
58
  reasoning: false,
@@ -1,3 +1,7 @@
1
+ import {
2
+ filterTextModelIds
3
+ } from "./chunk-QS4QYSMM.js";
4
+
1
5
  // src/merge-opencode-config.ts
2
6
  import fs from "fs";
3
7
  import os from "os";
@@ -46,21 +50,8 @@ function readOpenCodeConfig() {
46
50
  }
47
51
  }
48
52
  function buildModelMap(primaryModel, modelIds) {
49
- const ids = [primaryModel];
50
- const seen = new Set(ids);
51
- for (const id of modelIds ?? []) {
52
- const trimmed = id?.trim();
53
- if (!trimmed || seen.has(trimmed)) continue;
54
- const lower = trimmed.toLowerCase();
55
- if (lower.includes("image") || lower.includes("video") || lower.includes("seedance") || lower.includes("wan-") || lower.includes("kling")) {
56
- continue;
57
- }
58
- seen.add(trimmed);
59
- ids.push(trimmed);
60
- if (ids.length >= 80) break;
61
- }
62
53
  const models = {};
63
- for (const id of ids) {
54
+ for (const id of filterTextModelIds(primaryModel, modelIds)) {
64
55
  models[id] = { name: id };
65
56
  }
66
57
  return models;
@@ -1,3 +1,7 @@
1
+ import {
2
+ filterTextModelIds
3
+ } from "./chunk-QS4QYSMM.js";
4
+
1
5
  // src/merge-zcode-config.ts
2
6
  import fs from "fs";
3
7
  import os from "os";
@@ -15,6 +19,38 @@ function zcodeConfigPath() {
15
19
  }
16
20
  return path.join(zcodeHome(), "v2", "config.json");
17
21
  }
22
+ function zcodeProtocolBinding(protocol = "chat_completions") {
23
+ switch (protocol) {
24
+ case "anthropic_messages":
25
+ return {
26
+ kind: "anthropic",
27
+ apiFormat: "anthropic-messages",
28
+ npm: "@ai-sdk/anthropic",
29
+ modelFormat: "anthropic",
30
+ pathKey: "anthropic",
31
+ pathSuffix: "/v1/messages"
32
+ };
33
+ case "responses":
34
+ return {
35
+ kind: "openai",
36
+ apiFormat: "openai-responses",
37
+ npm: "@ai-sdk/openai",
38
+ modelFormat: "responses",
39
+ pathKey: "openai",
40
+ pathSuffix: "/responses"
41
+ };
42
+ case "chat_completions":
43
+ default:
44
+ return {
45
+ kind: "openai-compatible",
46
+ apiFormat: "openai-chat-completions",
47
+ npm: "@ai-sdk/openai-compatible",
48
+ modelFormat: "openai",
49
+ pathKey: "openai-compatible",
50
+ pathSuffix: "/chat/completions"
51
+ };
52
+ }
53
+ }
18
54
  function timestampLabel() {
19
55
  const now = /* @__PURE__ */ new Date();
20
56
  const pad = (n) => String(n).padStart(2, "0");
@@ -43,24 +79,24 @@ function readZCodeConfig() {
43
79
  throw new Error(`\u65E0\u6CD5\u89E3\u6790 ${configPath}\uFF0C\u8BF7\u68C0\u67E5 JSON \u8BED\u6CD5\u540E\u91CD\u8BD5\u3002`);
44
80
  }
45
81
  }
46
- function buildModels(primary, modelIds) {
47
- const ids = /* @__PURE__ */ new Set([primary]);
48
- for (const id of modelIds ?? []) {
49
- const t = id?.trim();
50
- if (!t) continue;
51
- const lower = t.toLowerCase();
52
- if (lower.includes("image") || lower.includes("video") || lower.includes("seedance") || lower.includes("wan-") || lower.includes("kling")) {
53
- continue;
54
- }
55
- ids.add(t);
56
- if (ids.size >= 80) break;
57
- }
82
+ function buildModels(primary, modelIds, binding) {
58
83
  const models = {};
59
- for (const id of ids) {
60
- models[id] = { name: id };
84
+ for (const id of filterTextModelIds(primary, modelIds)) {
85
+ models[id] = {
86
+ name: id,
87
+ kinds: [binding.kind],
88
+ defaultKind: binding.kind
89
+ };
61
90
  }
62
91
  return models;
63
92
  }
93
+ function buildModelSupportedFormats(primary, modelIds, modelFormat) {
94
+ const out = {};
95
+ for (const id of filterTextModelIds(primary, modelIds)) {
96
+ out[id] = [modelFormat];
97
+ }
98
+ return out;
99
+ }
64
100
  function mergeZCodeConfig(options) {
65
101
  const configPath = zcodeConfigPath();
66
102
  const doc = readZCodeConfig();
@@ -76,22 +112,46 @@ function mergeZCodeConfig(options) {
76
112
  const root = options.baseUrl.replace(/\/v1\/?$/, "").replace(/\/+$/, "");
77
113
  const withV1 = `${root}/v1`;
78
114
  const withoutV1 = root;
115
+ const binding = zcodeProtocolBinding(options.protocol);
79
116
  const primaryBase = options.protocol === "anthropic_messages" ? withoutV1 : withV1;
117
+ const now = Date.now();
118
+ const models = {
119
+ ...existingModels,
120
+ ...buildModels(options.model, options.modelIds, binding)
121
+ };
80
122
  providers[TRINITY_ZCODE_PROVIDER] = {
81
123
  ...existing,
82
124
  enabled: true,
83
125
  name: "Trinity",
126
+ source: "custom",
127
+ kind: binding.kind,
128
+ defaultKind: binding.kind,
129
+ apiFormat: binding.apiFormat,
130
+ npm: binding.npm,
131
+ endpoints: {
132
+ anthropic: withoutV1,
133
+ openai: withV1,
134
+ baseURL: primaryBase,
135
+ paths: {
136
+ anthropic: "/v1/messages",
137
+ openai: "/responses",
138
+ "openai-compatible": "/chat/completions",
139
+ [binding.pathKey]: binding.pathSuffix
140
+ }
141
+ },
84
142
  options: {
85
143
  ...existing.options ?? {},
86
144
  baseURL: primaryBase,
87
- apiKey: options.apiKey,
88
- openaiBaseURL: withV1,
89
- anthropicBaseURL: withoutV1
145
+ apiKey: options.apiKey
90
146
  },
91
- models: {
92
- ...existingModels,
93
- ...buildModels(options.model, options.modelIds)
94
- }
147
+ models,
148
+ modelSupportedFormats: buildModelSupportedFormats(
149
+ options.model,
150
+ options.modelIds,
151
+ binding.modelFormat
152
+ ),
153
+ createdAt: typeof existing.createdAt === "number" ? existing.createdAt : now,
154
+ updatedAt: now
95
155
  };
96
156
  doc.provider = providers;
97
157
  doc.model = `${TRINITY_ZCODE_PROVIDER}/${options.model}`;
@@ -110,5 +170,6 @@ export {
110
170
  configureZCodeDirect,
111
171
  mergeZCodeConfig,
112
172
  zcodeConfigPath,
113
- zcodeHome
173
+ zcodeHome,
174
+ zcodeProtocolBinding
114
175
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "trinity-config",
3
- "version": "1.2.2",
4
- "description": "一键把 Trinity API 接入 Claude Code、Codex、OpenCode、OpenClaw",
3
+ "version": "1.2.4",
4
+ "description": "一键把 Trinity API 接入 Claude Code、Codex、OpenCode、OpenClaw、ZCode",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "bin": {