swixter 0.1.10 → 0.1.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/dist/cli/index.js +510 -95
  2. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -14021,7 +14021,7 @@ var CONFIG_VERSION = "2.0.0", EXPORT_VERSION = "1.0.0";
14021
14021
  var init_versions2 = () => {};
14022
14022
 
14023
14023
  // src/constants/meta.ts
14024
- var APP_VERSION = "0.1.10";
14024
+ var APP_VERSION = "0.1.11";
14025
14025
  var init_meta = () => {};
14026
14026
 
14027
14027
  // src/constants/install.ts
@@ -14459,6 +14459,7 @@ var init_presets = __esm(() => {
14459
14459
  name: "MiniMax CN",
14460
14460
  displayName: "MiniMax (CN)",
14461
14461
  baseURL: "https://api.minimaxi.com/anthropic",
14462
+ baseURLChat: "https://api.minimaxi.com/v1",
14462
14463
  defaultModels: [
14463
14464
  "MiniMax-M2.7"
14464
14465
  ],
@@ -14474,6 +14475,7 @@ var init_presets = __esm(() => {
14474
14475
  name: "MiniMax Global",
14475
14476
  displayName: "MiniMax (Global)",
14476
14477
  baseURL: "https://api.minimax.io/anthropic",
14478
+ baseURLChat: "https://api.minimax.io/v1",
14477
14479
  defaultModels: [
14478
14480
  "MiniMax-M2.7"
14479
14481
  ],
@@ -18986,10 +18988,12 @@ import { join as join3, dirname as dirname4 } from "node:path";
18986
18988
  class CodexAdapter {
18987
18989
  name = "codex";
18988
18990
  configPath;
18989
- authPath;
18990
18991
  constructor() {
18991
- this.configPath = join3(homedir2(), ".codex", "config.toml");
18992
- this.authPath = join3(homedir2(), ".codex", "auth.json");
18992
+ const codexHome = join3(homedir2(), ".codex");
18993
+ this.configPath = join3(codexHome, "config.toml");
18994
+ }
18995
+ getProfileFilePath(profileName) {
18996
+ return join3(dirname4(this.configPath), `swixter-${profileName}.config.toml`);
18993
18997
  }
18994
18998
  async apply(profile) {
18995
18999
  try {
@@ -19019,15 +19023,17 @@ class CodexAdapter {
19019
19023
  config2.model_providers = {};
19020
19024
  }
19021
19025
  config2.model_providers[providerName] = await this.createProviderTable(profile, preset);
19022
- if (!config2.profiles) {
19023
- config2.profiles = {};
19024
- }
19025
- config2.profiles[profileName] = await this.createProfileTable(profile, providerName);
19026
- config2.profile = profileName;
19027
19026
  config2.model_provider = providerName;
19027
+ delete config2.profile;
19028
+ if (config2.profiles) {
19029
+ delete config2.profiles[profileName];
19030
+ if (Object.keys(config2.profiles).length === 0) {
19031
+ delete config2.profiles;
19032
+ }
19033
+ }
19028
19034
  const tomlContent = stringify(config2);
19029
19035
  await writeFile4(this.configPath, tomlContent, "utf-8");
19030
- await this.writeAuthJson(profile);
19036
+ await this.writeProfileFile(profile, providerName);
19031
19037
  } catch (error46) {
19032
19038
  throw new Error(`Failed to apply Codex configuration: ${error46 instanceof Error ? error46.message : String(error46)}`);
19033
19039
  }
@@ -19039,32 +19045,24 @@ class CodexAdapter {
19039
19045
  }
19040
19046
  const content = await readFile4(this.configPath, "utf-8");
19041
19047
  const config2 = parse5(content);
19042
- const profileName = `swixter-${profile.name}`;
19043
- if (config2.profile !== profileName) {
19048
+ const providerName = `swixter-${profile.name}`;
19049
+ if (config2.model_provider !== providerName) {
19044
19050
  return false;
19045
19051
  }
19046
- if (!config2.profiles || !config2.profiles[profileName]) {
19052
+ if (!config2.model_providers || !config2.model_providers[providerName]) {
19047
19053
  return false;
19048
19054
  }
19049
- const providerName = config2.profiles[profileName].model_provider;
19050
- if (!config2.model_providers || !config2.model_providers[providerName]) {
19055
+ const profileFilePath = this.getProfileFilePath(profile.name);
19056
+ if (!existsSync4(profileFilePath)) {
19051
19057
  return false;
19052
19058
  }
19053
- if (profile.apiKey) {
19054
- const envKey = await getEnvKey(profile);
19055
- if (existsSync4(this.authPath)) {
19056
- try {
19057
- const authContent = await readFile4(this.authPath, "utf-8");
19058
- const auth = JSON.parse(authContent);
19059
- if (auth[envKey] !== profile.apiKey) {
19060
- return false;
19061
- }
19062
- } catch {
19063
- return false;
19064
- }
19065
- } else {
19059
+ try {
19060
+ const profileFile = parse5(await readFile4(profileFilePath, "utf-8"));
19061
+ if (profileFile.model_provider !== providerName) {
19066
19062
  return false;
19067
19063
  }
19064
+ } catch {
19065
+ return false;
19068
19066
  }
19069
19067
  return true;
19070
19068
  } catch (error46) {
@@ -19076,8 +19074,7 @@ class CodexAdapter {
19076
19074
  const providerTable = {
19077
19075
  name: preset.displayName,
19078
19076
  base_url: profile.baseURL || baseUrl,
19079
- wire_api: "responses",
19080
- requires_openai_auth: true
19077
+ wire_api: "responses"
19081
19078
  };
19082
19079
  providerTable.env_key = await getEnvKey(profile);
19083
19080
  if (preset.headers) {
@@ -19085,45 +19082,21 @@ class CodexAdapter {
19085
19082
  }
19086
19083
  return providerTable;
19087
19084
  }
19088
- async createProfileTable(profile, providerName) {
19089
- const profileTable = {
19085
+ async writeProfileFile(profile, providerName) {
19086
+ const profileContent = {
19090
19087
  model_provider: providerName
19091
19088
  };
19092
19089
  const modelValue = getOpenAIModel(profile);
19093
19090
  if (modelValue) {
19094
- profileTable.model = modelValue;
19091
+ profileContent.model = modelValue;
19095
19092
  } else {
19096
19093
  const preset = await getPresetByIdAsync(profile.providerId);
19097
19094
  if (preset && preset.defaultModels && preset.defaultModels.length > 0) {
19098
- profileTable.model = preset.defaultModels[0];
19099
- }
19100
- }
19101
- return profileTable;
19102
- }
19103
- async writeAuthJson(profile) {
19104
- const envKey = await getEnvKey(profile);
19105
- let auth = {};
19106
- if (existsSync4(this.authPath)) {
19107
- try {
19108
- const content = await readFile4(this.authPath, "utf-8");
19109
- const parsed = JSON.parse(content);
19110
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
19111
- auth = parsed;
19112
- }
19113
- } catch {
19114
- auth = {};
19095
+ profileContent.model = preset.defaultModels[0];
19115
19096
  }
19116
19097
  }
19117
- if (profile.apiKey) {
19118
- auth[envKey] = profile.apiKey;
19119
- } else {
19120
- delete auth[envKey];
19121
- }
19122
- if (Object.keys(auth).length > 0) {
19123
- await writeFile4(this.authPath, JSON.stringify(auth, null, 2), "utf-8");
19124
- } else if (existsSync4(this.authPath)) {
19125
- await unlink(this.authPath);
19126
- }
19098
+ const profileFilePath = this.getProfileFilePath(profile.name);
19099
+ await writeFile4(profileFilePath, stringify(profileContent), "utf-8");
19127
19100
  }
19128
19101
  async getEnvExportCommands(profile) {
19129
19102
  const commands = await getEnvExportCommands(profile);
@@ -19134,6 +19107,12 @@ class CodexAdapter {
19134
19107
  return commands;
19135
19108
  }
19136
19109
  async remove(profileName) {
19110
+ const profileFilePath = this.getProfileFilePath(profileName);
19111
+ if (existsSync4(profileFilePath)) {
19112
+ try {
19113
+ await unlink(profileFilePath);
19114
+ } catch {}
19115
+ }
19137
19116
  if (!existsSync4(this.configPath)) {
19138
19117
  return;
19139
19118
  }
@@ -19141,20 +19120,23 @@ class CodexAdapter {
19141
19120
  const content = await readFile4(this.configPath, "utf-8");
19142
19121
  const config2 = parse5(content);
19143
19122
  const providerKey = `swixter-${profileName}`;
19144
- const profileKey = `swixter-${profileName}`;
19145
19123
  let modified = false;
19146
- let envKeyToRemove;
19147
19124
  if (config2.model_providers && config2.model_providers[providerKey]) {
19148
- envKeyToRemove = config2.model_providers[providerKey].env_key;
19149
19125
  delete config2.model_providers[providerKey];
19150
19126
  modified = true;
19151
19127
  }
19152
- if (config2.profiles && config2.profiles[profileKey]) {
19153
- delete config2.profiles[profileKey];
19128
+ if (config2.profiles && config2.profiles[providerKey]) {
19129
+ delete config2.profiles[providerKey];
19130
+ if (Object.keys(config2.profiles).length === 0) {
19131
+ delete config2.profiles;
19132
+ }
19154
19133
  modified = true;
19155
19134
  }
19156
- if (config2.profile === profileKey) {
19135
+ if (config2.profile === providerKey) {
19157
19136
  delete config2.profile;
19137
+ modified = true;
19138
+ }
19139
+ if (config2.model_provider === providerKey) {
19158
19140
  delete config2.model_provider;
19159
19141
  modified = true;
19160
19142
  }
@@ -19162,14 +19144,6 @@ class CodexAdapter {
19162
19144
  const tomlContent = stringify(config2);
19163
19145
  await writeFile4(this.configPath, tomlContent, "utf-8");
19164
19146
  }
19165
- if (envKeyToRemove && existsSync4(this.authPath)) {
19166
- try {
19167
- const authContent = await readFile4(this.authPath, "utf-8");
19168
- const auth = JSON.parse(authContent);
19169
- delete auth[envKeyToRemove];
19170
- await writeFile4(this.authPath, JSON.stringify(auth, null, 2), "utf-8");
19171
- } catch {}
19172
- }
19173
19147
  } catch (error46) {
19174
19148
  console.warn(`Failed to remove profile from Codex config: ${error46}`);
19175
19149
  }
@@ -19180,6 +19154,7 @@ var init_codex = __esm(() => {
19180
19154
  init_presets();
19181
19155
  init_model_helper();
19182
19156
  init_env_key_helper();
19157
+ init_env_key_helper();
19183
19158
  });
19184
19159
 
19185
19160
  // src/adapters/index.ts
@@ -25718,19 +25693,23 @@ function parseSSEEvents(chunk) {
25718
25693
  if (currentDataLines.length > 0) {
25719
25694
  const dataStr = currentDataLines.join(`
25720
25695
  `);
25721
- try {
25722
- const data = JSON.parse(dataStr);
25723
- events.push({ event: currentEvent, data });
25724
- } catch {}
25696
+ if (dataStr === "[DONE]") {
25697
+ events.push({ event: currentEvent, data: "[DONE]" });
25698
+ } else {
25699
+ try {
25700
+ const data = JSON.parse(dataStr);
25701
+ events.push({ event: currentEvent, data });
25702
+ } catch {}
25703
+ }
25725
25704
  }
25726
25705
  currentEvent = "";
25727
25706
  currentDataLines = [];
25728
25707
  }
25729
25708
  for (const line of lines) {
25730
- if (line.startsWith("event: ")) {
25731
- currentEvent = line.slice("event: ".length);
25732
- } else if (line.startsWith("data: ")) {
25733
- currentDataLines.push(line.slice("data: ".length));
25709
+ if (line.startsWith("event:")) {
25710
+ currentEvent = line.slice("event:".length).replace(/^ /, "");
25711
+ } else if (line.startsWith("data:")) {
25712
+ currentDataLines.push(line.slice("data:".length).replace(/^ /, ""));
25734
25713
  } else if (line === "") {
25735
25714
  flushEvent();
25736
25715
  }
@@ -25889,7 +25868,7 @@ function inferClientFormat(endpoint) {
25889
25868
  return "openai_chat";
25890
25869
  }
25891
25870
  if (endpoint.includes("/v1/responses")) {
25892
- return "anthropic_responses";
25871
+ return "openai_responses";
25893
25872
  }
25894
25873
  if (endpoint.includes("/anthropic/") || endpoint.includes("/v1/messages")) {
25895
25874
  return "anthropic_messages";
@@ -26412,6 +26391,446 @@ var init_openai_chat_to_anthropic2 = __esm(() => {
26412
26391
  });
26413
26392
  });
26414
26393
 
26394
+ // src/proxy/transform/request/openai-responses-to-openai-chat.ts
26395
+ function openaiResponsesToOpenAIChatRequest(body, _ctx) {
26396
+ const r2 = body;
26397
+ const chatBody = { model: r2.model };
26398
+ const messages2 = [];
26399
+ if (typeof r2.instructions === "string" && r2.instructions.length > 0) {
26400
+ messages2.push({ role: "system", content: r2.instructions });
26401
+ }
26402
+ if (Array.isArray(r2.input)) {
26403
+ for (const item of r2.input) {
26404
+ const converted = convertInputItem(item);
26405
+ if (Array.isArray(converted))
26406
+ messages2.push(...converted);
26407
+ else if (converted)
26408
+ messages2.push(converted);
26409
+ }
26410
+ } else if (typeof r2.input === "string" && r2.input.length > 0) {
26411
+ messages2.push({ role: "user", content: r2.input });
26412
+ }
26413
+ chatBody.messages = messages2;
26414
+ if (r2.max_output_tokens !== undefined)
26415
+ chatBody.max_tokens = r2.max_output_tokens;
26416
+ if (r2.temperature !== undefined)
26417
+ chatBody.temperature = r2.temperature;
26418
+ if (r2.top_p !== undefined)
26419
+ chatBody.top_p = r2.top_p;
26420
+ if (r2.stream !== undefined)
26421
+ chatBody.stream = r2.stream;
26422
+ if (r2.parallel_tool_calls !== undefined)
26423
+ chatBody.parallel_tool_calls = r2.parallel_tool_calls;
26424
+ if (Array.isArray(r2.tools)) {
26425
+ chatBody.tools = r2.tools.filter((t) => {
26426
+ const name = t.name;
26427
+ if (typeof name !== "string" || name.length === 0)
26428
+ return false;
26429
+ return TOOL_NAME_RE.test(name);
26430
+ }).map((t) => ({
26431
+ type: "function",
26432
+ function: {
26433
+ name: t.name,
26434
+ description: t.description,
26435
+ parameters: t.parameters && typeof t.parameters === "object" ? t.parameters : { type: "object", properties: {} }
26436
+ }
26437
+ }));
26438
+ }
26439
+ if (r2.tool_choice !== undefined)
26440
+ chatBody.tool_choice = convertToolChoice2(r2.tool_choice);
26441
+ const effort = r2.reasoning?.effort;
26442
+ if (typeof effort === "string")
26443
+ chatBody.reasoning_effort = effort;
26444
+ return { body: chatBody, targetEndpoint: "/v1/chat/completions" };
26445
+ }
26446
+ function convertInputItem(item) {
26447
+ switch (item.type) {
26448
+ case "message": {
26449
+ const role = item.role === "developer" ? "system" : item.role;
26450
+ return { role, content: flattenText(item.content) };
26451
+ }
26452
+ case "function_call": {
26453
+ return {
26454
+ role: "assistant",
26455
+ content: null,
26456
+ tool_calls: [{ id: item.call_id, type: "function", function: { name: item.name, arguments: item.arguments ?? "" } }]
26457
+ };
26458
+ }
26459
+ case "function_call_output": {
26460
+ return {
26461
+ role: "tool",
26462
+ tool_call_id: item.call_id,
26463
+ content: typeof item.output === "string" ? item.output : JSON.stringify(item.output ?? "")
26464
+ };
26465
+ }
26466
+ default:
26467
+ return null;
26468
+ }
26469
+ }
26470
+ function flattenText(content) {
26471
+ if (typeof content === "string")
26472
+ return content;
26473
+ if (!Array.isArray(content))
26474
+ return content;
26475
+ const parts = [];
26476
+ for (const part of content) {
26477
+ if (part.type === "input_text" || part.type === "output_text" || part.type === "text") {
26478
+ parts.push({ type: "text", text: part.text });
26479
+ } else {
26480
+ throw new Error(`openai_responses→openai_chat: unsupported content part type "${part.type}"`);
26481
+ }
26482
+ }
26483
+ if (parts.length === 1 && parts[0].type === "text") {
26484
+ return parts[0].text;
26485
+ }
26486
+ return parts;
26487
+ }
26488
+ function convertToolChoice2(tc) {
26489
+ if (typeof tc === "string")
26490
+ return tc;
26491
+ if (tc && typeof tc === "object") {
26492
+ const t = tc;
26493
+ if (t.type === "function" && t.name) {
26494
+ return { type: "function", function: { name: t.name } };
26495
+ }
26496
+ }
26497
+ return tc;
26498
+ }
26499
+ var TOOL_NAME_RE;
26500
+ var init_openai_responses_to_openai_chat = __esm(() => {
26501
+ TOOL_NAME_RE = /^(?!.*__)[a-zA-Z][a-zA-Z0-9_-]{0,63}$/;
26502
+ });
26503
+
26504
+ // src/proxy/transform/response/openai-chat-to-openai-responses.ts
26505
+ function openAIChatToOpenAIResponsesResponse(body, _ctx) {
26506
+ const chat = body;
26507
+ const choices = chat.choices;
26508
+ const choice = choices?.[0];
26509
+ const message = choice?.message;
26510
+ const output = [];
26511
+ if (message) {
26512
+ if (typeof message.content === "string" && message.content.length > 0) {
26513
+ output.push({
26514
+ type: "message",
26515
+ id: "msg_0",
26516
+ status: "completed",
26517
+ role: "assistant",
26518
+ content: [{ type: "output_text", text: message.content, annotations: [] }]
26519
+ });
26520
+ }
26521
+ if (Array.isArray(message.tool_calls)) {
26522
+ message.tool_calls.forEach((tc, i2) => {
26523
+ const fn = tc.function || {};
26524
+ output.push({
26525
+ type: "function_call",
26526
+ id: `fc_${i2}`,
26527
+ call_id: tc.id,
26528
+ name: fn.name,
26529
+ arguments: typeof fn.arguments === "string" ? fn.arguments : JSON.stringify(fn.arguments ?? ""),
26530
+ status: "completed"
26531
+ });
26532
+ });
26533
+ }
26534
+ }
26535
+ const usage = chat.usage;
26536
+ const inputTokens = usage?.prompt_tokens ?? 0;
26537
+ const outputTokens = usage?.completion_tokens ?? 0;
26538
+ const base = chat.id ? `resp_${chat.id}` : "";
26539
+ const id = base && base !== "resp_" ? base : `resp_${Date.now()}`;
26540
+ return {
26541
+ id,
26542
+ object: "response",
26543
+ status: mapStatus(choice?.finish_reason),
26544
+ model: chat.model ?? "unknown",
26545
+ output,
26546
+ usage: {
26547
+ input_tokens: inputTokens,
26548
+ output_tokens: outputTokens,
26549
+ total_tokens: usage?.total_tokens ?? inputTokens + outputTokens
26550
+ }
26551
+ };
26552
+ }
26553
+ function mapStatus(finishReason) {
26554
+ if (finishReason === "length")
26555
+ return "incomplete";
26556
+ return "completed";
26557
+ }
26558
+
26559
+ // src/proxy/transform/streaming/openai-chat-to-openai-responses.ts
26560
+ function createOpenAIChatToOpenAIResponsesStream(source, ctx) {
26561
+ const stream = source instanceof Uint8Array ? new ReadableStream({
26562
+ start(controller) {
26563
+ controller.enqueue(source);
26564
+ controller.close();
26565
+ }
26566
+ }) : source;
26567
+ return stream.pipeThrough(createSSETransformStream(new OpenAIChatToOpenAIResponsesStreamTransformer(ctx)));
26568
+ }
26569
+ var OpenAIChatToOpenAIResponsesStreamTransformer;
26570
+ var init_openai_chat_to_openai_responses = __esm(() => {
26571
+ init_base();
26572
+ init_transform();
26573
+ init_openai_responses_to_openai_chat();
26574
+ OpenAIChatToOpenAIResponsesStreamTransformer = class OpenAIChatToOpenAIResponsesStreamTransformer extends SSEStreamTransformer {
26575
+ responseId = "";
26576
+ model = "";
26577
+ created = false;
26578
+ textOutputIndex = -1;
26579
+ textStarted = false;
26580
+ textBuf = "";
26581
+ tools = new Map;
26582
+ nextOutputIndex = 0;
26583
+ usage = null;
26584
+ finished = false;
26585
+ convertEvent(event) {
26586
+ if (event.data === "[DONE]")
26587
+ return null;
26588
+ const data = event.data;
26589
+ if (data && data.id)
26590
+ this.responseId = `resp_${data.id}`;
26591
+ if (data && data.model)
26592
+ this.model = data.model;
26593
+ if (data && data.usage)
26594
+ this.usage = data.usage;
26595
+ const choices = data?.choices;
26596
+ const choice = choices?.[0];
26597
+ if (!choice)
26598
+ return null;
26599
+ const out = [];
26600
+ if (!this.created) {
26601
+ this.created = true;
26602
+ out.push({
26603
+ event: "response.created",
26604
+ data: { type: "response.created", response: this.responseShell("in_progress") }
26605
+ });
26606
+ }
26607
+ const delta = choice.delta;
26608
+ if (delta?.content && typeof delta.content === "string") {
26609
+ out.push(...this.handleText(delta.content));
26610
+ }
26611
+ if (Array.isArray(delta?.tool_calls)) {
26612
+ for (const tc of delta.tool_calls)
26613
+ out.push(...this.handleTool(tc));
26614
+ }
26615
+ if (choice.finish_reason && !this.finished) {
26616
+ out.push(...this.finish(choice.finish_reason));
26617
+ }
26618
+ return out;
26619
+ }
26620
+ responseShell(status) {
26621
+ return { id: this.responseId, object: "response", status, model: this.model, output: [] };
26622
+ }
26623
+ handleText(text) {
26624
+ this.textBuf += text;
26625
+ const out = [];
26626
+ if (this.textOutputIndex < 0)
26627
+ this.textOutputIndex = this.nextOutputIndex++;
26628
+ if (!this.textStarted) {
26629
+ this.textStarted = true;
26630
+ out.push({
26631
+ event: "response.output_item.added",
26632
+ data: {
26633
+ type: "response.output_item.added",
26634
+ output_index: this.textOutputIndex,
26635
+ item: { type: "message", id: "msg_0", status: "in_progress", role: "assistant", content: [] }
26636
+ }
26637
+ });
26638
+ out.push({
26639
+ event: "response.content_part.added",
26640
+ data: {
26641
+ type: "response.content_part.added",
26642
+ item_id: "msg_0",
26643
+ output_index: this.textOutputIndex,
26644
+ content_index: 0,
26645
+ part: { type: "output_text", text: "", annotations: [] }
26646
+ }
26647
+ });
26648
+ }
26649
+ out.push({
26650
+ event: "response.output_text.delta",
26651
+ data: {
26652
+ type: "response.output_text.delta",
26653
+ item_id: "msg_0",
26654
+ output_index: this.textOutputIndex,
26655
+ content_index: 0,
26656
+ delta: text
26657
+ }
26658
+ });
26659
+ return out;
26660
+ }
26661
+ handleTool(tc) {
26662
+ const idx = tc.index ?? 0;
26663
+ let st = this.tools.get(idx);
26664
+ if (!st) {
26665
+ st = {
26666
+ outputIndex: this.nextOutputIndex++,
26667
+ itemId: `fc_${idx}`,
26668
+ callId: tc.id ?? `call_${idx}`,
26669
+ name: "",
26670
+ argsBuf: "",
26671
+ announced: false
26672
+ };
26673
+ this.tools.set(idx, st);
26674
+ }
26675
+ if (tc.id)
26676
+ st.callId = tc.id;
26677
+ if (tc.function?.name)
26678
+ st.name = tc.function.name;
26679
+ const out = [];
26680
+ if (!st.announced && st.name) {
26681
+ st.announced = true;
26682
+ out.push({
26683
+ event: "response.output_item.added",
26684
+ data: {
26685
+ type: "response.output_item.added",
26686
+ output_index: st.outputIndex,
26687
+ item: {
26688
+ type: "function_call",
26689
+ id: st.itemId,
26690
+ call_id: st.callId,
26691
+ name: st.name,
26692
+ arguments: "",
26693
+ status: "in_progress"
26694
+ }
26695
+ }
26696
+ });
26697
+ }
26698
+ if (tc.function?.arguments) {
26699
+ st.argsBuf += tc.function.arguments;
26700
+ if (st.announced) {
26701
+ out.push({
26702
+ event: "response.function_call_arguments.delta",
26703
+ data: {
26704
+ type: "response.function_call_arguments.delta",
26705
+ item_id: st.itemId,
26706
+ output_index: st.outputIndex,
26707
+ delta: tc.function.arguments
26708
+ }
26709
+ });
26710
+ }
26711
+ }
26712
+ return out;
26713
+ }
26714
+ finish(_finishReason) {
26715
+ if (this.finished)
26716
+ return [];
26717
+ this.finished = true;
26718
+ const out = [];
26719
+ if (this.textStarted) {
26720
+ out.push({
26721
+ event: "response.output_text.done",
26722
+ data: {
26723
+ type: "response.output_text.done",
26724
+ item_id: "msg_0",
26725
+ output_index: this.textOutputIndex,
26726
+ content_index: 0,
26727
+ text: this.textBuf
26728
+ }
26729
+ });
26730
+ out.push({
26731
+ event: "response.content_part.done",
26732
+ data: {
26733
+ type: "response.content_part.done",
26734
+ item_id: "msg_0",
26735
+ output_index: this.textOutputIndex,
26736
+ content_index: 0,
26737
+ part: { type: "output_text", text: this.textBuf, annotations: [] }
26738
+ }
26739
+ });
26740
+ out.push({
26741
+ event: "response.output_item.done",
26742
+ data: {
26743
+ type: "response.output_item.done",
26744
+ output_index: this.textOutputIndex,
26745
+ item: {
26746
+ type: "message",
26747
+ id: "msg_0",
26748
+ status: "completed",
26749
+ role: "assistant",
26750
+ content: [{ type: "output_text", text: this.textBuf, annotations: [] }]
26751
+ }
26752
+ }
26753
+ });
26754
+ }
26755
+ const outputItems = [];
26756
+ if (this.textStarted) {
26757
+ outputItems.push({
26758
+ type: "message",
26759
+ id: "msg_0",
26760
+ status: "completed",
26761
+ role: "assistant",
26762
+ content: [{ type: "output_text", text: this.textBuf, annotations: [] }]
26763
+ });
26764
+ }
26765
+ for (const st of this.tools.values()) {
26766
+ if (!st.announced)
26767
+ continue;
26768
+ out.push({
26769
+ event: "response.function_call_arguments.done",
26770
+ data: {
26771
+ type: "response.function_call_arguments.done",
26772
+ item_id: st.itemId,
26773
+ output_index: st.outputIndex,
26774
+ arguments: st.argsBuf
26775
+ }
26776
+ });
26777
+ out.push({
26778
+ event: "response.output_item.done",
26779
+ data: {
26780
+ type: "response.output_item.done",
26781
+ output_index: st.outputIndex,
26782
+ item: {
26783
+ type: "function_call",
26784
+ id: st.itemId,
26785
+ call_id: st.callId,
26786
+ name: st.name,
26787
+ arguments: st.argsBuf,
26788
+ status: "completed"
26789
+ }
26790
+ }
26791
+ });
26792
+ outputItems.push({
26793
+ type: "function_call",
26794
+ id: st.itemId,
26795
+ call_id: st.callId,
26796
+ name: st.name,
26797
+ arguments: st.argsBuf,
26798
+ status: "completed"
26799
+ });
26800
+ }
26801
+ const u2 = this.usage ?? {};
26802
+ const inputTokens = u2.prompt_tokens ?? 0;
26803
+ const outputTokens = u2.completion_tokens ?? 0;
26804
+ out.push({
26805
+ event: "response.completed",
26806
+ data: {
26807
+ type: "response.completed",
26808
+ response: {
26809
+ id: this.responseId,
26810
+ object: "response",
26811
+ status: "completed",
26812
+ model: this.model,
26813
+ output: outputItems,
26814
+ usage: {
26815
+ input_tokens: inputTokens,
26816
+ output_tokens: outputTokens,
26817
+ total_tokens: u2.total_tokens ?? inputTokens + outputTokens
26818
+ }
26819
+ }
26820
+ }
26821
+ });
26822
+ return out;
26823
+ }
26824
+ };
26825
+ registerTransformer({
26826
+ clientFormat: "openai_responses",
26827
+ targetFormat: "openai_chat",
26828
+ requestTransform: openaiResponsesToOpenAIChatRequest,
26829
+ responseTransform: openAIChatToOpenAIResponsesResponse,
26830
+ streamTransform: (stream, ctx) => createOpenAIChatToOpenAIResponsesStream(stream, ctx)
26831
+ });
26832
+ });
26833
+
26415
26834
  // src/proxy/router.ts
26416
26835
  class ProxyRouter {
26417
26836
  routes = [];
@@ -26497,8 +26916,9 @@ class ProxyForwarder {
26497
26916
  defaultTimeout = 3000000;
26498
26917
  async forward(request, profile, timeoutMs) {
26499
26918
  const preset = await getPresetByIdAsync(profile.providerId);
26500
- const baseURL = profile.baseURL || preset?.baseURL || "";
26501
- const url2 = `${baseURL}${request.path}`;
26919
+ const baseURL = (profile.baseURL || preset?.baseURL || "").replace(/\/+$/, "");
26920
+ const path = baseURL.endsWith("/v1") && request.path.startsWith("/v1/") ? request.path.slice(3) : request.path;
26921
+ const url2 = `${baseURL}${path}`;
26502
26922
  const timeout = timeoutMs || this.defaultTimeout;
26503
26923
  const headers = Object.fromEntries(Object.entries(request.headers).filter(([key]) => {
26504
26924
  const normalizedKey = key.toLowerCase();
@@ -26806,14 +27226,7 @@ class ProxyHandler {
26806
27226
  if (this.isHealthRequest(request)) {
26807
27227
  return null;
26808
27228
  }
26809
- const token = this.getBearerToken(request);
26810
- if (token === SWIXTER_PROXY_AUTH_TOKEN) {
26811
- return null;
26812
- }
26813
- return new Response(JSON.stringify({ error: "Invalid or missing proxy authentication" }), {
26814
- status: 401,
26815
- headers: { "Content-Type": "application/json" }
26816
- });
27229
+ return null;
26817
27230
  }
26818
27231
  async handleChatCompletions(request) {
26819
27232
  return this.forwardToProvider(request, "chat");
@@ -27124,6 +27537,7 @@ class ProxyHandler {
27124
27537
  }
27125
27538
  var init_handler = __esm(() => {
27126
27539
  init_openai_chat_to_anthropic2();
27540
+ init_openai_chat_to_openai_responses();
27127
27541
  init_model_helper();
27128
27542
  init_forwarder();
27129
27543
  init_manager2();
@@ -30341,9 +30755,10 @@ async function cmdApply3() {
30341
30755
  console.log(` Provider: ${import_picocolors10.default.yellow(preset?.displayName)}`);
30342
30756
  console.log(` Config file: ${import_picocolors10.default.dim(adapter.configPath)}`);
30343
30757
  console.log();
30344
- console.log(import_picocolors10.default.bold("Run Codex now: ") + import_picocolors10.default.cyan("codex"));
30758
+ console.log(import_picocolors10.default.bold("Run Codex now: ") + import_picocolors10.default.cyan("swixter codex run"));
30345
30759
  console.log();
30346
- console.log(import_picocolors10.default.dim("Environment variables are automatically managed via auth.json."));
30760
+ const envKey = profile.envKey || preset?.env_key || "OPENAI_API_KEY";
30761
+ console.log(import_picocolors10.default.dim(`Or export your key first: export ${envKey}=<your-key> then run codex`));
30347
30762
  console.log();
30348
30763
  } else {
30349
30764
  console.log(import_picocolors10.default.yellow("⚠ Profile written, but verification failed"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swixter",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "CLI tool for managing AI coding assistant configurations - easily switch between providers (Claude Code, Codex, Continue) with Anthropic, Ollama, or custom APIs",
5
5
  "main": "dist/cli/index.js",
6
6
  "module": "dist/cli/index.js",