@jsonstudio/rcc 0.89.1348 → 0.89.1488

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 (126) hide show
  1. package/README.md +51 -1427
  2. package/configsamples/config.json +12 -4
  3. package/dist/build-info.js +2 -2
  4. package/dist/cli/commands/config.js +3 -0
  5. package/dist/cli/commands/config.js.map +1 -1
  6. package/dist/cli/commands/init.js +3 -0
  7. package/dist/cli/commands/init.js.map +1 -1
  8. package/dist/cli/config/bundled-docs.js +2 -2
  9. package/dist/cli/config/bundled-docs.js.map +1 -1
  10. package/dist/cli/config/init-config.d.ts +2 -1
  11. package/dist/cli/config/init-config.js +33 -1
  12. package/dist/cli/config/init-config.js.map +1 -1
  13. package/dist/client/gemini/gemini-protocol-client.js +2 -1
  14. package/dist/client/gemini/gemini-protocol-client.js.map +1 -1
  15. package/dist/client/gemini-cli/gemini-cli-protocol-client.js +67 -16
  16. package/dist/client/gemini-cli/gemini-cli-protocol-client.js.map +1 -1
  17. package/dist/client/openai/chat-protocol-client.js +2 -1
  18. package/dist/client/openai/chat-protocol-client.js.map +1 -1
  19. package/dist/client/responses/responses-protocol-client.js +2 -1
  20. package/dist/client/responses/responses-protocol-client.js.map +1 -1
  21. package/dist/error-handling/quiet-error-handling-center.js +46 -8
  22. package/dist/error-handling/quiet-error-handling-center.js.map +1 -1
  23. package/dist/manager/modules/quota/antigravity-quota-manager.d.ts +4 -0
  24. package/dist/manager/modules/quota/antigravity-quota-manager.js +130 -2
  25. package/dist/manager/modules/quota/antigravity-quota-manager.js.map +1 -1
  26. package/dist/manager/modules/quota/provider-quota-daemon.events.js +67 -4
  27. package/dist/manager/modules/quota/provider-quota-daemon.events.js.map +1 -1
  28. package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.js +9 -6
  29. package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.js.map +1 -1
  30. package/dist/modules/llmswitch/bridge.js +17 -4
  31. package/dist/modules/llmswitch/bridge.js.map +1 -1
  32. package/dist/modules/llmswitch/core-loader.d.ts +1 -1
  33. package/dist/modules/llmswitch/core-loader.js +15 -3
  34. package/dist/modules/llmswitch/core-loader.js.map +1 -1
  35. package/dist/providers/auth/antigravity-userinfo-helper.d.ts +5 -2
  36. package/dist/providers/auth/antigravity-userinfo-helper.js +63 -8
  37. package/dist/providers/auth/antigravity-userinfo-helper.js.map +1 -1
  38. package/dist/providers/auth/gemini-cli-userinfo-helper.js +66 -4
  39. package/dist/providers/auth/gemini-cli-userinfo-helper.js.map +1 -1
  40. package/dist/providers/auth/oauth-lifecycle.js +112 -1
  41. package/dist/providers/auth/oauth-lifecycle.js.map +1 -1
  42. package/dist/providers/auth/tokenfile-auth.d.ts +14 -0
  43. package/dist/providers/auth/tokenfile-auth.js +125 -2
  44. package/dist/providers/auth/tokenfile-auth.js.map +1 -1
  45. package/dist/providers/core/config/camoufox-launcher.d.ts +5 -0
  46. package/dist/providers/core/config/camoufox-launcher.js +5 -0
  47. package/dist/providers/core/config/camoufox-launcher.js.map +1 -1
  48. package/dist/providers/core/config/service-profiles.js +7 -18
  49. package/dist/providers/core/config/service-profiles.js.map +1 -1
  50. package/dist/providers/core/runtime/base-provider.d.ts +0 -5
  51. package/dist/providers/core/runtime/base-provider.js +26 -112
  52. package/dist/providers/core/runtime/base-provider.js.map +1 -1
  53. package/dist/providers/core/runtime/gemini-cli-http-provider.d.ts +6 -0
  54. package/dist/providers/core/runtime/gemini-cli-http-provider.js +409 -100
  55. package/dist/providers/core/runtime/gemini-cli-http-provider.js.map +1 -1
  56. package/dist/providers/core/runtime/http-request-executor.d.ts +3 -0
  57. package/dist/providers/core/runtime/http-request-executor.js +110 -38
  58. package/dist/providers/core/runtime/http-request-executor.js.map +1 -1
  59. package/dist/providers/core/runtime/http-transport-provider.d.ts +3 -0
  60. package/dist/providers/core/runtime/http-transport-provider.js +89 -39
  61. package/dist/providers/core/runtime/http-transport-provider.js.map +1 -1
  62. package/dist/providers/core/runtime/rate-limit-manager.d.ts +1 -12
  63. package/dist/providers/core/runtime/rate-limit-manager.js +4 -77
  64. package/dist/providers/core/runtime/rate-limit-manager.js.map +1 -1
  65. package/dist/providers/core/utils/http-client.js +20 -43
  66. package/dist/providers/core/utils/http-client.js.map +1 -1
  67. package/dist/runtime/wasm-runtime/wasm-config.d.ts +73 -0
  68. package/dist/runtime/wasm-runtime/wasm-config.js +124 -0
  69. package/dist/runtime/wasm-runtime/wasm-config.js.map +1 -0
  70. package/dist/runtime/wasm-runtime/wasm-loader.d.ts +40 -0
  71. package/dist/runtime/wasm-runtime/wasm-loader.js +62 -0
  72. package/dist/runtime/wasm-runtime/wasm-loader.js.map +1 -0
  73. package/dist/server/handlers/handler-utils.js +5 -1
  74. package/dist/server/handlers/handler-utils.js.map +1 -1
  75. package/dist/server/handlers/responses-handler.js +1 -1
  76. package/dist/server/handlers/responses-handler.js.map +1 -1
  77. package/dist/server/runtime/http-server/index.js +121 -30
  78. package/dist/server/runtime/http-server/index.js.map +1 -1
  79. package/dist/server/runtime/http-server/request-executor.js +50 -6
  80. package/dist/server/runtime/http-server/request-executor.js.map +1 -1
  81. package/dist/server/runtime/http-server/routes.js +4 -1
  82. package/dist/server/runtime/http-server/routes.js.map +1 -1
  83. package/dist/utils/strip-internal-keys.d.ts +12 -0
  84. package/dist/utils/strip-internal-keys.js +28 -0
  85. package/dist/utils/strip-internal-keys.js.map +1 -0
  86. package/docs/CHAT_PROCESS_PROTOCOL_AND_PIPELINE.md +221 -0
  87. package/docs/antigravity-gemini-format-cleanup.md +143 -0
  88. package/docs/antigravity-routing-contract.md +31 -0
  89. package/docs/chat-semantic-expansion-plan.md +8 -6
  90. package/docs/glm-chat-completions.md +1 -1
  91. package/docs/llms-wasm-migration.md +331 -0
  92. package/docs/llms-wasm-module-boundaries.md +588 -0
  93. package/docs/llms-wasm-replay-baseline.md +171 -0
  94. package/docs/plans/llms-wasm-migration-plan.md +401 -0
  95. package/docs/servertool-framework.md +65 -0
  96. package/docs/v2-architecture/README.md +6 -8
  97. package/docs/verified-configs/README.md +60 -0
  98. package/docs/verified-configs/v0.45.0/README.md +244 -0
  99. package/docs/verified-configs/v0.45.0/lmstudio-5521-gpt-oss-20b-mlx.json +135 -0
  100. package/docs/verified-configs/v0.45.0/merged-config.5521.json +1205 -0
  101. package/docs/verified-configs/v0.45.0/merged-config.qwen-5522.json +1559 -0
  102. package/docs/verified-configs/v0.45.0/qwen-5522-qwen3-coder-plus-final.json +221 -0
  103. package/docs/verified-configs/v0.45.0/qwen-5522-qwen3-coder-plus-fixed.json +242 -0
  104. package/docs/verified-configs/v0.45.0/qwen-5522-qwen3-coder-plus.json +242 -0
  105. package/package.json +17 -11
  106. package/scripts/antigravity-token-bridge.mjs +283 -0
  107. package/scripts/build-core.mjs +3 -1
  108. package/scripts/ci/repo-sanity.mjs +138 -0
  109. package/scripts/mock-provider/run-regressions.mjs +157 -1
  110. package/scripts/run-bg.sh +0 -14
  111. package/scripts/tests/ci-jest.mjs +119 -0
  112. package/scripts/tools-dev/responses-debug-client/README.md +23 -0
  113. package/scripts/tools-dev/responses-debug-client/payloads/poem.json +13 -0
  114. package/scripts/tools-dev/responses-debug-client/payloads/sample-no-tools.json +98 -0
  115. package/scripts/tools-dev/responses-debug-client/payloads/text.json +13 -0
  116. package/scripts/tools-dev/responses-debug-client/payloads/tool.json +27 -0
  117. package/scripts/tools-dev/responses-debug-client/run.mjs +65 -0
  118. package/scripts/tools-dev/responses-debug-client/src/index.ts +281 -0
  119. package/scripts/tools-dev/run-llmswitch-chat.mjs +53 -0
  120. package/scripts/tools-dev/server-tools-dev/run-web-fetch.mjs +65 -0
  121. package/scripts/vendor-core.mjs +13 -3
  122. package/scripts/test-fc-responses.mjs +0 -66
  123. package/scripts/test-guidance.mjs +0 -100
  124. package/scripts/test-iflow-web-search.mjs +0 -141
  125. package/scripts/test-iflow.mjs +0 -379
  126. package/scripts/test-tool-exec.mjs +0 -26
@@ -0,0 +1,281 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Responses Debug Client
4
+ * - Connects to RCC server (baseURL) using OpenAI SDK Responses stream
5
+ * - Consumes SSE named events, prints concise logs
6
+ * - Completes a minimal tool-calls loop by executing local tools and submitting outputs
7
+ */
8
+
9
+ import fs from 'node:fs/promises';
10
+ import path from 'node:path';
11
+ import process from 'node:process';
12
+ import OpenAI from 'openai';
13
+
14
+ type Unknown = Record<string, any>;
15
+
16
+ function parseArgs(argv: string[]): Record<string, string | boolean> {
17
+ const out: Record<string, string | boolean> = {};
18
+ for (let i = 2; i < argv.length; i++) {
19
+ const a = argv[i];
20
+ if (!a) continue;
21
+ if (a.startsWith('--')) {
22
+ const [k, v] = a.split('=');
23
+ const key = k.replace(/^--/, '');
24
+ if (typeof v === 'string' && v.length) out[key] = v;
25
+ else if (i + 1 < argv.length && !argv[i + 1].startsWith('--')) { out[key] = argv[++i]; }
26
+ else out[key] = true;
27
+ }
28
+ }
29
+ return out;
30
+ }
31
+
32
+ function short(s: string, n = 60): string {
33
+ if (s.length <= n) return s;
34
+ return s.slice(0, n) + '…';
35
+ }
36
+
37
+ function nowIso(): string { return new Date().toISOString(); }
38
+
39
+ async function readJson(file: string): Promise<Unknown> {
40
+ const abs = path.isAbsolute(file) ? file : path.resolve(process.cwd(), file);
41
+ const raw = await fs.readFile(abs, 'utf-8');
42
+ return JSON.parse(raw) as Unknown;
43
+ }
44
+
45
+ type ToolOutput = { tool_call_id: string; output: string };
46
+
47
+ function safeJsonParse(s: string): any {
48
+ try { return JSON.parse(s); } catch { return s; }
49
+ }
50
+
51
+ // Minimal local tool handlers
52
+ const localTools: Record<string, (args: any) => Promise<string> | string> = {
53
+ echo: (args: any) => {
54
+ if (typeof args?.text === 'string') return String(args.text);
55
+ return typeof args === 'string' ? args : JSON.stringify(args ?? {});
56
+ },
57
+ sum: (args: any) => {
58
+ const arr = Array.isArray(args?.numbers) ? args.numbers : [];
59
+ const total = arr.reduce((a: number, b: any) => a + (typeof b === 'number' ? b : 0), 0);
60
+ return String(total);
61
+ },
62
+ time: () => new Date().toISOString(),
63
+ };
64
+
65
+ async function executeTool(name: string, argStr: string): Promise<string> {
66
+ const n = String(name || '').trim();
67
+ const handler = localTools[n] || (async () => `Unsupported tool: ${n}`);
68
+ const args = typeof argStr === 'string' ? safeJsonParse(argStr) : argStr;
69
+ try { return await handler(args); } catch (e: any) { return `Tool error: ${e?.message || String(e)}`; }
70
+ }
71
+
72
+ async function main() {
73
+ const args = parseArgs(process.argv);
74
+ const file = String(args.file || args.f || '');
75
+ if (!file) {
76
+ console.error('Usage: tsx scripts/tools-dev/responses-debug-client/src/index.ts --file <payload.json> [--baseURL URL] [--apiKey KEY] [--timeout 120] [--raw] [--save] [--maxRounds 3]');
77
+ process.exit(1);
78
+ }
79
+ const baseURL = String(args.baseURL || 'http://127.0.0.1:5520/v1');
80
+ const apiKey = String(args.apiKey || 'dummy');
81
+ const timeoutSec = Number(args.timeout || 120);
82
+ const raw = !!args.raw;
83
+ const save = !!args.save;
84
+ const maxRounds = Math.max(1, Number(args.maxRounds || 3));
85
+
86
+ const reqBody = await readJson(file);
87
+ if (reqBody.stream == null) reqBody.stream = true;
88
+
89
+ // Attach a client-side request id into payload.metadata for correlation
90
+ const clientRequestId = `cli_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
91
+ try {
92
+ const meta = (reqBody && typeof reqBody === 'object' && (reqBody as any).metadata && typeof (reqBody as any).metadata === 'object')
93
+ ? (reqBody as any).metadata : {};
94
+ (reqBody as any).metadata = { ...meta, client_request_id: clientRequestId };
95
+ } catch { /* ignore */ }
96
+
97
+ // Snapshot exact client request body to ~/.routecodex/codex-samples/responses-client/
98
+ try {
99
+ const home = process.env.HOME || process.env.USERPROFILE || '.';
100
+ const dir = path.join(String(home), '.routecodex', 'codex-samples', 'responses-client');
101
+ await fs.mkdir(dir, { recursive: true });
102
+ const out = path.join(dir, `${clientRequestId}_client-request.json`);
103
+ await fs.writeFile(out, JSON.stringify({
104
+ timestamp: new Date().toISOString(),
105
+ baseURL,
106
+ request: reqBody
107
+ }, null, 2), 'utf-8');
108
+ if (!raw) console.log(`[${nowIso()}] saved client snapshot: ${out}`);
109
+ } catch { /* non-blocking */ }
110
+
111
+ const client = new OpenAI({ apiKey, baseURL });
112
+ const start = Date.now();
113
+ console.log(`[${nowIso()}] connect baseURL=${baseURL}`);
114
+
115
+ const stream: any = await client.responses.stream(reqBody as any);
116
+ let responseId = '';
117
+ let model = '';
118
+ let round = 1;
119
+ const textBuf: string[] = [];
120
+
121
+ // tool state
122
+ const toolArgs: Record<string, string> = {};
123
+ const toolMeta: Record<string, { name?: string; output_index?: number; type?: string }> = {};
124
+ let sawRequiredAction = false;
125
+ let submittedThisRound = false;
126
+ const seqCheck = { last: -1 };
127
+
128
+ const writeLine = async (o: any) => {
129
+ if (!save) return;
130
+ try {
131
+ const dir = path.resolve(process.cwd(), 'logs', 'responses-debug', responseId || 'unknown');
132
+ await fs.mkdir(dir, { recursive: true });
133
+ await fs.appendFile(path.join(dir, 'events.jsonl'), JSON.stringify({ ts: Date.now(), ...o }) + '\n', 'utf-8');
134
+ } catch { /* ignore */ }
135
+ };
136
+
137
+ const submitToolOutputs = async (requiredAction: any) => {
138
+ const tc = Array.isArray(requiredAction?.submit_tool_outputs?.tool_calls)
139
+ ? requiredAction.submit_tool_outputs.tool_calls : [];
140
+ const outputs: ToolOutput[] = [];
141
+ for (const call of tc) {
142
+ const id = String(call?.id || '');
143
+ const name = String(call?.function?.name || '');
144
+ const argStr = String(call?.function?.arguments || '');
145
+ const out = await executeTool(name, argStr);
146
+ outputs.push({ tool_call_id: id, output: out });
147
+ console.log(` ↳ tool[${name}] id=${id} -> output(${out.length})`);
148
+ }
149
+ if (typeof stream.submitToolOutputs === 'function') {
150
+ console.log(` -> submitToolOutputs(${outputs.length}) via stream`);
151
+ await stream.submitToolOutputs({ tool_outputs: outputs, stream: true });
152
+ return;
153
+ }
154
+ throw new Error('SDK stream.submitToolOutputs unavailable; please upgrade openai package');
155
+ };
156
+
157
+ const dumpEvent = (ev: any) => {
158
+ const t = ev?.type || 'event';
159
+ const d = ev?.data ?? ev;
160
+ const seq = typeof d?.sequence_number === 'number' ? d.sequence_number : undefined;
161
+ if (typeof seq === 'number') {
162
+ if (seq <= seqCheck.last) console.warn(` ! sequence rollback: ${seqCheck.last} -> ${seq}`);
163
+ seqCheck.last = seq;
164
+ }
165
+ if (raw) console.log('evt', t, JSON.stringify(d));
166
+ };
167
+
168
+ for await (const ev of stream) {
169
+ await writeLine({ type: ev?.type || 'event', data: ev });
170
+ dumpEvent(ev);
171
+
172
+ switch (ev?.type) {
173
+ case 'response.created': {
174
+ responseId = String(ev?.data?.response?.id || responseId);
175
+ model = String(ev?.data?.response?.model || model);
176
+ console.log(`created id=${responseId} model=${model}`);
177
+ break;
178
+ }
179
+ case 'response.in_progress': {
180
+ break;
181
+ }
182
+ case 'response.output_text.delta': {
183
+ const s = String(ev?.data?.delta || '');
184
+ textBuf.push(s);
185
+ console.log(` textΔ(${s.length}): ${short(s)}`);
186
+ break;
187
+ }
188
+ case 'response.output_text.done': {
189
+ console.log(` text✓ (total=${textBuf.join('').length})`);
190
+ break;
191
+ }
192
+ case 'response.output_item.added': {
193
+ const item = ev?.data?.item || {};
194
+ const id = String(item?.id || '');
195
+ toolMeta[id] = { name: item?.name, output_index: ev?.data?.output_index, type: item?.type };
196
+ toolArgs[id] = toolArgs[id] || '';
197
+ console.log(` tool+ id=${id} name=${item?.name || ''}`);
198
+ break;
199
+ }
200
+ case 'response.function_call_arguments.delta': {
201
+ const id = String(ev?.data?.id || ev?.data?.item_id || '');
202
+ const d = String(ev?.data?.delta || '');
203
+ toolArgs[id] = (toolArgs[id] || '') + d;
204
+ console.log(` argsΔ id=${id} (+${d.length})`);
205
+ break;
206
+ }
207
+ case 'response.function_call_arguments.done': {
208
+ const id = String(ev?.data?.id || ev?.data?.item_id || '');
209
+ const total = (toolArgs[id] || '').length;
210
+ console.log(` args✓ id=${id} (${total})`);
211
+ break;
212
+ }
213
+ case 'response.output_item.done': {
214
+ const item = ev?.data?.item || {};
215
+ const id = String(item?.id || '');
216
+ console.log(` tool✓ id=${id}`);
217
+ // Fallback path for providers不发 required_action:在 function_call 完成后立即提交工具输出
218
+ if (!sawRequiredAction && !submittedThisRound && (toolMeta[id]?.type === 'function_call')) {
219
+ const name = toolMeta[id]?.name || item?.name || '';
220
+ const argStr = item?.arguments || toolArgs[id] || '';
221
+ const outputs: ToolOutput[] = [{ tool_call_id: id, output: await executeTool(name, String(argStr)) }];
222
+ if (typeof stream.submitToolOutputs === 'function') {
223
+ console.log(` -> submitToolOutputs(fallback, ${outputs.length}) via stream [round ${round}]`);
224
+ await stream.submitToolOutputs({ tool_outputs: outputs, stream: true });
225
+ submittedThisRound = true;
226
+ round++;
227
+ if (round > maxRounds) throw new Error(`Exceeded maxRounds=${maxRounds}`);
228
+ }
229
+ }
230
+ break;
231
+ }
232
+ case 'response.required_action': {
233
+ const ra = ev?.data?.required_action || ev?.data; // SDK shape varies
234
+ const count = Array.isArray(ra?.submit_tool_outputs?.tool_calls) ? ra.submit_tool_outputs.tool_calls.length : 0;
235
+ console.log(` required_action submit_tool_outputs(${count}) [round ${round}]`);
236
+ sawRequiredAction = true;
237
+ await submitToolOutputs(ra);
238
+ round++;
239
+ if (round > maxRounds) throw new Error(`Exceeded maxRounds=${maxRounds}`);
240
+ break;
241
+ }
242
+ case 'response.completed': {
243
+ const u = ev?.data?.response?.usage || {};
244
+ const iu = Number(u?.input_tokens || 0);
245
+ const ou = Number(u?.output_tokens || 0);
246
+ const tt = Number(u?.total_tokens || 0);
247
+ console.log(` completed usage: in=${iu} out=${ou} total=${tt}`);
248
+ // Reset per-round flags to allow下一轮
249
+ submittedThisRound = false;
250
+ sawRequiredAction = false;
251
+ break;
252
+ }
253
+ case 'response.error': {
254
+ console.error(' error:', ev?.data?.error);
255
+ process.exitCode = 2;
256
+ break;
257
+ }
258
+ case 'response.done': {
259
+ const ms = Date.now() - start;
260
+ console.log(` done in ${ms} ms`);
261
+ return;
262
+ }
263
+ default: {
264
+ // Heartbeat or unknown event
265
+ const d = ev?.data;
266
+ if (d && typeof d === 'object' && d.type === 'heartbeat') {
267
+ // ignore
268
+ } else if (!raw) {
269
+ // print brief unknowns
270
+ const t = String(ev?.type || 'evt');
271
+ console.log(` ${t}`);
272
+ }
273
+ }
274
+ }
275
+ }
276
+ }
277
+
278
+ main().catch((e) => {
279
+ console.error('fatal:', e?.message || String(e));
280
+ process.exit(2);
281
+ });
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env node
2
+ // Quick llmswitch-core Chat filter runner: runStandardChatRequestFilters without starting server.
3
+ // Usage:
4
+ // node scripts/tools-dev/run-llmswitch-chat.mjs path/to/chat-request.json [/v1/chat|/v1/messages|/v1/responses]
5
+
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+ import url from 'url';
9
+ import { runStandardChatRequestFilters } from '../../sharedmodule/llmswitch-core/dist/conversion/index.js';
10
+
11
+ const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
12
+
13
+ async function main() {
14
+ const file = process.argv[2];
15
+ const endpoint = process.argv[3] || '/v1/chat/completions';
16
+
17
+ if (!file) {
18
+ console.error('Usage: node scripts/tools-dev/run-llmswitch-chat.mjs <payload.json> [endpoint]');
19
+ process.exit(1);
20
+ }
21
+
22
+ const abs = path.isAbsolute(file) ? file : path.join(process.cwd(), file);
23
+ const txt = fs.readFileSync(abs, 'utf8');
24
+ const raw = JSON.parse(txt);
25
+
26
+ // Allow passing either a raw chat body, or a provider-request snapshot with { endpoint, data: { body } }
27
+ let payload = raw;
28
+ if (raw && typeof raw === 'object' && raw.data && typeof raw.data === 'object' && raw.data.body) {
29
+ payload = raw.data.body;
30
+ }
31
+
32
+ const requestId = `req_${Date.now()}`;
33
+ const profile = {
34
+ id: 'test-profile',
35
+ incomingProtocol: 'openai-chat',
36
+ outgoingProtocol: 'openai-chat'
37
+ };
38
+
39
+ const context = {
40
+ requestId,
41
+ entryEndpoint: endpoint,
42
+ endpoint,
43
+ metadata: {}
44
+ };
45
+
46
+ const out = await runStandardChatRequestFilters(payload, profile, context);
47
+ process.stdout.write(JSON.stringify(out, null, 2) + '\n');
48
+ }
49
+
50
+ main().catch(err => {
51
+ console.error('Error running llmswitch filters:', err);
52
+ process.exit(1);
53
+ });
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env node
2
+ import { fileURLToPath, pathToFileURL } from 'node:url';
3
+ import path from 'node:path';
4
+
5
+ function parseArgs(argv) {
6
+ const out = { url: null, timeout: null, maxBytes: null, follow: true, headers: {} };
7
+ for (let i = 2; i < argv.length; i++) {
8
+ const a = argv[i];
9
+ if ((a === '--url' || a === '-u') && i + 1 < argv.length) { out.url = argv[++i]; continue; }
10
+ if ((a === '--timeout' || a === '-t') && i + 1 < argv.length) { out.timeout = Number(argv[++i]); continue; }
11
+ if (a === '--no-follow') { out.follow = false; continue; }
12
+ if ((a === '--max-bytes' || a === '-m') && i + 1 < argv.length) { out.maxBytes = Number(argv[++i]); continue; }
13
+ if ((a === '--header' || a === '-H') && i + 1 < argv.length) {
14
+ const kv = String(argv[++i]);
15
+ const idx = kv.indexOf(':');
16
+ if (idx > 0) { const k = kv.slice(0, idx).trim(); const v = kv.slice(idx + 1).trim(); if (k) out.headers[k] = v; }
17
+ continue;
18
+ }
19
+ if (a === '--help' || a === '-h') { out.help = true; }
20
+ }
21
+ return out;
22
+ }
23
+
24
+ function usage() {
25
+ console.log('Usage: node scripts/tools-dev/server-tools-dev/run-web-fetch.mjs --url <URL> [--timeout 12000] [--max-bytes 524288] [--no-follow] [--header "Key: Value"]');
26
+ }
27
+
28
+ async function importCoreFetcher() {
29
+ // Prefer local sharedmodule path if exists; fallback to installed package
30
+ const __filename = fileURLToPath(import.meta.url);
31
+ const repoRoot = path.resolve(path.dirname(__filename), '../..');
32
+ const local = path.resolve(repoRoot, 'sharedmodule/llmswitch-core/dist/tools/web-fetch-html.js');
33
+ try {
34
+ const mod = await import(pathToFileURL(local).href);
35
+ if (typeof mod?.fetchRawHtml === 'function') return mod.fetchRawHtml;
36
+ } catch {}
37
+ throw new Error('Cannot locate fetchRawHtml in sharedmodule/llmswitch-core/dist。请先构建 sharedmodule/llmswitch-core。');
38
+ }
39
+
40
+ async function main() {
41
+ const args = parseArgs(process.argv);
42
+ if (args.help || !args.url) { usage(); process.exit(args.help ? 0 : 1); }
43
+ const fetchRawHtml = await importCoreFetcher();
44
+ const res = await fetchRawHtml(args.url, {
45
+ timeoutMs: args.timeout || undefined,
46
+ followRedirects: args.follow,
47
+ maxBytes: args.maxBytes || undefined,
48
+ headers: Object.keys(args.headers).length ? args.headers : undefined,
49
+ });
50
+ if (res.ok) {
51
+ console.log('OK');
52
+ console.log(`status: ${res.status}`);
53
+ console.log(`content-type: ${res.contentType}`);
54
+ const preview = res.html ?? '';
55
+ console.log('--- html (first 2048 chars) ---');
56
+ console.log(preview.slice(0, 2048));
57
+ } else {
58
+ console.log('FAIL');
59
+ console.log(`error: ${res.error}`);
60
+ if (res.status) console.log(`status: ${res.status}`);
61
+ if (res.contentType) console.log(`content-type: ${res.contentType}`);
62
+ }
63
+ }
64
+
65
+ main().catch((e) => { console.error(e); process.exit(99); });
@@ -12,12 +12,18 @@ async function rmrf(p) {
12
12
 
13
13
  async function main() {
14
14
  const root = process.cwd();
15
+ const rawMode = String(process.env.BUILD_MODE || process.env.RCC_BUILD_MODE || 'release').toLowerCase();
16
+ const mode = rawMode === 'dev' ? 'dev' : 'release';
15
17
  const sharedDist = path.join(root, 'sharedmodule', 'llmswitch-core', 'dist');
16
18
  const legacyVendorDir = path.join(root, 'vendor', 'rcc-llmswitch-core');
17
19
  const scopedVendorDir = path.join(root, 'vendor', '@jsonstudio', 'llms');
18
20
 
19
- if (!await exists(sharedDist)) {
20
- console.error('[vendor-core] ERROR: 未找到 sharedmodule/llmswitch-core/dist');
21
+ // In release mode we rely on npm-installed `@jsonstudio/llms`, so the local sharedmodule dist
22
+ // is optional and must not block CI (where sharedmodule often doesn't exist).
23
+ // In dev mode, `node_modules/@jsonstudio/llms` is typically symlinked to sharedmodule/llmswitch-core,
24
+ // so we keep a hard requirement for the dist output.
25
+ if (mode === 'dev' && !await exists(sharedDist)) {
26
+ console.error('[vendor-core] ERROR: 未找到 sharedmodule/llmswitch-core/dist (BUILD_MODE=dev)');
21
27
  console.error('[vendor-core] 请先进入 sharedmodule/llmswitch-core 并运行 `npm run build`。');
22
28
  process.exit(2);
23
29
  }
@@ -31,7 +37,11 @@ async function main() {
31
37
  console.log('[vendor-core] removed legacy vendor/@jsonstudio/llms directory');
32
38
  }
33
39
 
34
- console.log('[vendor-core] sharedmodule/llmswitch-core/dist 将被直接引用,已停止生成 vendor 副本。');
40
+ if (mode === 'dev') {
41
+ console.log('[vendor-core] sharedmodule/llmswitch-core/dist 将被直接引用,已停止生成 vendor 副本。');
42
+ } else {
43
+ console.log('[vendor-core] BUILD_MODE=release: using npm-installed @jsonstudio/llms (no vendor copy).');
44
+ }
35
45
  }
36
46
 
37
47
  main().catch((err) => {
@@ -1,66 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Minimal Responses client using the same OpenAI SDK
4
- * semantics as tools/responses-debug-client, for testing
5
- * upstream /v1/responses SSE behaviour.
6
- */
7
-
8
- import OpenAI from 'openai';
9
-
10
- const baseURL = process.argv[2] || 'https://www.fakercode.top/v1';
11
- const apiKey =
12
- process.argv[3] ||
13
- process.env.FC_API_KEY ||
14
- process.env.OPENAI_API_KEY ||
15
- '';
16
-
17
- if (!apiKey) {
18
- console.error('FC_API_KEY / OPENAI_API_KEY is required');
19
- process.exit(1);
20
- }
21
-
22
- const client = new OpenAI({ apiKey, baseURL });
23
-
24
- const payload = {
25
- model: process.env.FC_MODEL || 'gpt-5.1',
26
- input: [
27
- {
28
- role: 'user',
29
- content: [
30
- {
31
- type: 'input_text',
32
- text: '用一句话说“你好”,不要解释。'
33
- }
34
- ]
35
- }
36
- ],
37
- stream: true
38
- };
39
-
40
- console.log('BASE_URL', baseURL);
41
- console.log('MODEL', payload.model);
42
-
43
- try {
44
- const stream = await client.responses.stream(payload);
45
- console.log('STREAM_OK');
46
- for await (const event of stream) {
47
- console.log('EVENT', JSON.stringify(event));
48
- }
49
- } catch (err) {
50
- console.log('STREAM_ERROR');
51
- console.log(
52
- JSON.stringify(
53
- {
54
- name: err?.name,
55
- message: err?.message,
56
- status: err?.status,
57
- code: err?.code,
58
- type: err?.type,
59
- data: err?.response?.data
60
- },
61
- null,
62
- 2
63
- )
64
- );
65
- process.exit(1);
66
- }
@@ -1,100 +0,0 @@
1
- #!/usr/bin/env node
2
- import fs from 'fs';
3
- import path from 'path';
4
- import os from 'os';
5
- import { pathToFileURL } from 'url';
6
-
7
- const HOME = os.homedir();
8
- const base = path.join(HOME, '.routecodex', 'codex-samples');
9
- const guidanceMod = path.resolve(process.cwd(), 'sharedmodule/llmswitch-core/dist/guidance/index.js');
10
-
11
- async function loadGuidance() {
12
- const mod = await import(pathToFileURL(guidanceMod).href);
13
- const { refineSystemToolGuidance, augmentOpenAITools, augmentAnthropicTools, buildSystemToolGuidance } = mod;
14
- return { refineSystemToolGuidance, augmentOpenAITools, augmentAnthropicTools, buildSystemToolGuidance };
15
- }
16
-
17
- function readJsonSafe(p) {
18
- try { return JSON.parse(fs.readFileSync(p, 'utf8')); } catch { return null; }
19
- }
20
-
21
- function collectFiles(dir) {
22
- const out = [];
23
- try {
24
- for (const name of fs.readdirSync(dir)) {
25
- const full = path.join(dir, name);
26
- const st = fs.statSync(full);
27
- if (st.isFile()) out.push(full);
28
- }
29
- } catch { /* ignore */ }
30
- return out;
31
- }
32
-
33
- function extractRequest(obj) {
34
- // Try common capture shapes
35
- if (obj && typeof obj === 'object') {
36
- if (obj.body && typeof obj.body === 'object') return obj.body;
37
- if (obj.data && typeof obj.data === 'object') return obj.data;
38
- }
39
- return obj;
40
- }
41
-
42
- function hasOpenAITools(tools) {
43
- return Array.isArray(tools) && tools.some(t => t && typeof t === 'object' && t.function && typeof t.function === 'object');
44
- }
45
-
46
- function hasAnthropicTools(tools) {
47
- return Array.isArray(tools) && tools.some(t => t && typeof t === 'object' && t.input_schema);
48
- }
49
-
50
- async function main() {
51
- const { refineSystemToolGuidance, augmentOpenAITools, augmentAnthropicTools } = await loadGuidance();
52
- const targets = [
53
- path.join(base, 'openai-chat'),
54
- path.join(base, 'responses-replay'),
55
- path.join(base, 'anth-replay')
56
- ];
57
-
58
- let total = 0, refined = 0, augmented = 0;
59
-
60
- for (const d of targets) {
61
- const files = collectFiles(d);
62
- for (const f of files) {
63
- const j = readJsonSafe(f);
64
- if (!j) continue;
65
- const req = extractRequest(j);
66
- if (!req || typeof req !== 'object') continue;
67
- total++;
68
- // Refine system/instructions
69
- try {
70
- if (Array.isArray(req.messages) && req.messages.length && req.messages[0]?.role === 'system' && typeof req.messages[0].content === 'string') {
71
- const before = req.messages[0].content || '';
72
- const after = refineSystemToolGuidance(before);
73
- if (after !== before) refined++;
74
- } else if (typeof req.instructions === 'string' && req.instructions) {
75
- const before = req.instructions;
76
- const after = refineSystemToolGuidance(before);
77
- if (after !== before) refined++;
78
- }
79
- } catch { /* ignore */ }
80
- // Augment tools
81
- try {
82
- if (hasOpenAITools(req.tools)) {
83
- const before = JSON.stringify(req.tools);
84
- const t = augmentOpenAITools(req.tools);
85
- const after = JSON.stringify(t);
86
- if (after !== before) augmented++;
87
- } else if (hasAnthropicTools(req.tools)) {
88
- const before = JSON.stringify(req.tools);
89
- const t = augmentAnthropicTools(req.tools);
90
- const after = JSON.stringify(t);
91
- if (after !== before) augmented++;
92
- }
93
- } catch { /* ignore */ }
94
- }
95
- }
96
-
97
- console.log(JSON.stringify({ base, scannedDirs: targets, total, refined, augmented }, null, 2));
98
- }
99
-
100
- main().catch((e) => { console.error(e); process.exit(1); });