@love-moon/ai-sdk 0.2.39 → 0.2.40

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.
@@ -1,12 +1,39 @@
1
1
  import { CodexAppServerSession } from "./providers/codex-app-server-session.js";
2
+ import { CodexExecSession } from "./providers/codex-exec-session.js";
2
3
  import { ClaudeAgentSdkSession } from "./providers/claude-agent-sdk-session.js";
4
+ import { CopilotSdkSession } from "./providers/copilot-sdk-session.js";
3
5
  import { KimiCliSession } from "./providers/kimi-cli-session.js";
6
+ import { KimiPrintSession } from "./providers/kimi-print-session.js";
4
7
  import { OpencodeSdkSession } from "./providers/opencode-sdk-session.js";
5
8
  import { getExternalProviderDescriptor, resolveExternalBackend, } from "./external-provider-registry.js";
6
9
  export const DEFAULT_PROVIDER_VARIANT = "codex-app-server";
10
+ export const CODEX_EXEC_PROVIDER_VARIANT = "codex-exec";
7
11
  export const CLAUDE_PROVIDER_VARIANT = "claude-agent-sdk";
12
+ export const COPILOT_PROVIDER_VARIANT = "copilot-sdk";
8
13
  export const KIMI_PROVIDER_VARIANT = "kimi-cli-wire";
14
+ export const KIMI_PRINT_PROVIDER_VARIANT = "kimi-cli-print";
9
15
  export const OPENCODE_PROVIDER_VARIANT = "opencode-sdk";
16
+ function hasStructuredOutputPreference(options = {}) {
17
+ if (!options || typeof options !== "object") {
18
+ return false;
19
+ }
20
+ if (options.structuredOutput === true) {
21
+ return true;
22
+ }
23
+ if (options.jsonSchema && typeof options.jsonSchema === "object") {
24
+ return true;
25
+ }
26
+ const outputFormat = options.outputFormat ?? options.responseFormat;
27
+ if (typeof outputFormat === "string") {
28
+ const normalized = outputFormat.trim().toLowerCase();
29
+ return Boolean(normalized) && normalized !== "text";
30
+ }
31
+ if (outputFormat && typeof outputFormat === "object") {
32
+ const type = typeof outputFormat.type === "string" ? outputFormat.type.trim().toLowerCase() : "";
33
+ return type !== "text";
34
+ }
35
+ return false;
36
+ }
10
37
  function normalizeBuiltInBackendName(backend) {
11
38
  const normalized = String(backend || "").trim().toLowerCase();
12
39
  if (normalized === "code") {
@@ -25,14 +52,14 @@ function normalizeBuiltInBackendName(backend) {
25
52
  }
26
53
  export async function normalizeBackend(backend, options = {}) {
27
54
  const normalized = normalizeBuiltInBackendName(backend);
28
- if (normalized === "codex" || normalized === "claude" || normalized === "kimi" || normalized === "opencode") {
55
+ if (normalized === "codex" || normalized === "claude" || normalized === "copilot" || normalized === "kimi" || normalized === "opencode") {
29
56
  return normalized;
30
57
  }
31
58
  return await resolveExternalBackend(normalized, options);
32
59
  }
33
60
  export async function isSupportedBackend(backend, options = {}) {
34
61
  const normalized = await normalizeBackend(backend, options);
35
- if (normalized === "codex" || normalized === "claude" || normalized === "kimi" || normalized === "opencode") {
62
+ if (normalized === "codex" || normalized === "claude" || normalized === "copilot" || normalized === "kimi" || normalized === "opencode") {
36
63
  return true;
37
64
  }
38
65
  const descriptor = await getExternalProviderDescriptor(normalized, options);
@@ -43,14 +70,17 @@ export async function providerVariantForBackend(backend, options = {}) {
43
70
  if (normalized === "claude") {
44
71
  return CLAUDE_PROVIDER_VARIANT;
45
72
  }
73
+ if (normalized === "copilot") {
74
+ return COPILOT_PROVIDER_VARIANT;
75
+ }
46
76
  if (normalized === "kimi") {
47
- return KIMI_PROVIDER_VARIANT;
77
+ return hasStructuredOutputPreference(options) ? KIMI_PRINT_PROVIDER_VARIANT : KIMI_PROVIDER_VARIANT;
48
78
  }
49
79
  if (normalized === "opencode") {
50
80
  return OPENCODE_PROVIDER_VARIANT;
51
81
  }
52
82
  if (normalized === "codex") {
53
- return DEFAULT_PROVIDER_VARIANT;
83
+ return hasStructuredOutputPreference(options) ? CODEX_EXEC_PROVIDER_VARIANT : DEFAULT_PROVIDER_VARIANT;
54
84
  }
55
85
  const descriptor = await getExternalProviderDescriptor(normalized, options);
56
86
  if (descriptor?.variant) {
@@ -60,27 +90,36 @@ export async function providerVariantForBackend(backend, options = {}) {
60
90
  }
61
91
  export async function assertSupportedBackend(backend, options = {}) {
62
92
  const normalized = await normalizeBackend(backend, options);
63
- if (normalized === "codex" || normalized === "claude" || normalized === "kimi" || normalized === "opencode") {
93
+ if (normalized === "codex" || normalized === "claude" || normalized === "copilot" || normalized === "kimi" || normalized === "opencode") {
64
94
  return normalized;
65
95
  }
66
96
  const descriptor = await getExternalProviderDescriptor(normalized, options);
67
97
  if (descriptor) {
68
98
  return normalized;
69
99
  }
70
- throw new Error(`Unsupported AI SDK backend "${backend}". Built-in backends are codex app-server, claude agent-sdk, kimi cli wire, and opencode sdk. Set AISDK_PROVIDER_PATH to load external providers.`);
100
+ throw new Error(`Unsupported AI SDK backend "${backend}". Built-in backends are codex app-server/exec, claude agent-sdk, copilot sdk, kimi cli wire/print, and opencode sdk. Set AISDK_PROVIDER_PATH to load external providers.`);
71
101
  }
72
102
  export async function createLocalAiSession(backend, options = {}) {
73
103
  const normalized = await assertSupportedBackend(backend, options);
74
104
  if (normalized === "claude") {
75
105
  return new ClaudeAgentSdkSession(normalized, options);
76
106
  }
107
+ if (normalized === "copilot") {
108
+ return new CopilotSdkSession(normalized, options);
109
+ }
77
110
  if (normalized === "kimi") {
111
+ if (hasStructuredOutputPreference(options)) {
112
+ return new KimiPrintSession(normalized, options);
113
+ }
78
114
  return new KimiCliSession(normalized, options);
79
115
  }
80
116
  if (normalized === "opencode") {
81
117
  return new OpencodeSdkSession(normalized, options);
82
118
  }
83
119
  if (normalized === "codex") {
120
+ if (hasStructuredOutputPreference(options)) {
121
+ return new CodexExecSession(normalized, options);
122
+ }
84
123
  return new CodexAppServerSession(normalized, options);
85
124
  }
86
125
  const descriptor = await getExternalProviderDescriptor(normalized, options);
@@ -90,6 +129,9 @@ export async function createLocalAiSession(backend, options = {}) {
90
129
  return await descriptor.createSession(normalized, options);
91
130
  }
92
131
  export { CodexAppServerSession };
132
+ export { CodexExecSession };
93
133
  export { ClaudeAgentSdkSession };
134
+ export { CopilotSdkSession };
94
135
  export { KimiCliSession };
136
+ export { KimiPrintSession };
95
137
  export { OpencodeSdkSession };
package/dist/shared.d.ts CHANGED
@@ -13,5 +13,6 @@ export function loadYamlConfig(configFilePath: any): any;
13
13
  export function loadAllowCliList(configFilePath: any): any;
14
14
  export function loadEnvConfig(configFilePath: any): any;
15
15
  export function proxyToEnv(envConfig: any): {};
16
+ export function withoutCopilotGithubTokenEnv(env: any): any;
16
17
  export function serializeError(error: any): any;
17
18
  export function reviveError(payload: any): Error;
package/dist/shared.js CHANGED
@@ -61,32 +61,37 @@ export function parseCommandParts(commandLine) {
61
61
  const parts = [];
62
62
  let current = "";
63
63
  let quote = "";
64
- let escaping = false;
65
64
  let tokenStarted = false;
66
- for (const char of normalized) {
67
- if (escaping) {
68
- current += char;
69
- escaping = false;
70
- tokenStarted = true;
71
- continue;
72
- }
73
- if (char === "\\") {
74
- if (quote === "'") {
75
- current += char;
65
+ for (let index = 0; index < normalized.length; index += 1) {
66
+ const char = normalized[index];
67
+ const nextChar = normalized[index + 1];
68
+ if (quote === "'") {
69
+ if (char === "'") {
70
+ quote = "";
76
71
  }
77
72
  else {
78
- escaping = true;
73
+ current += char;
79
74
  }
80
75
  tokenStarted = true;
81
76
  continue;
82
77
  }
83
- if (quote) {
84
- if (char === quote) {
78
+ if (quote === "\"") {
79
+ if (char === "\"") {
85
80
  quote = "";
81
+ continue;
86
82
  }
87
- else {
88
- current += char;
83
+ if (char === "\\") {
84
+ if (nextChar === "\"" || nextChar === "\\") {
85
+ current += nextChar;
86
+ tokenStarted = true;
87
+ index += 1;
88
+ continue;
89
+ }
90
+ current += "\\";
91
+ tokenStarted = true;
92
+ continue;
89
93
  }
94
+ current += char;
90
95
  tokenStarted = true;
91
96
  continue;
92
97
  }
@@ -95,6 +100,17 @@ export function parseCommandParts(commandLine) {
95
100
  tokenStarted = true;
96
101
  continue;
97
102
  }
103
+ if (char === "\\") {
104
+ if (nextChar && (/\s/.test(nextChar) || nextChar === "\"" || nextChar === "'" || nextChar === "\\")) {
105
+ current += nextChar;
106
+ tokenStarted = true;
107
+ index += 1;
108
+ continue;
109
+ }
110
+ current += "\\";
111
+ tokenStarted = true;
112
+ continue;
113
+ }
98
114
  if (/\s/.test(char)) {
99
115
  if (tokenStarted) {
100
116
  parts.push(current);
@@ -106,10 +122,6 @@ export function parseCommandParts(commandLine) {
106
122
  current += char;
107
123
  tokenStarted = true;
108
124
  }
109
- if (escaping) {
110
- current += "\\";
111
- tokenStarted = true;
112
- }
113
125
  if (quote) {
114
126
  throw new Error(`Invalid command line: unterminated ${quote === "\"" ? "double" : "single"} quote`);
115
127
  }
@@ -175,6 +187,13 @@ export function proxyToEnv(envConfig) {
175
187
  }
176
188
  return env;
177
189
  }
190
+ export function withoutCopilotGithubTokenEnv(env) {
191
+ const next = env && typeof env === "object" ? { ...env } : {};
192
+ for (const key of ["COPILOT_GITHUB_TOKEN", "GH_TOKEN", "GITHUB_TOKEN"]) {
193
+ delete next[key];
194
+ }
195
+ return next;
196
+ }
178
197
  export function serializeError(error) {
179
198
  if (error instanceof Error) {
180
199
  const payload = {
@@ -6,6 +6,7 @@ export class CodexAppServerTransport extends EventEmitter<[never]> {
6
6
  command: string;
7
7
  args: string[];
8
8
  env: any;
9
+ ignoreCodexApiKey: boolean;
9
10
  child: import("child_process").ChildProcessWithoutNullStreams | null;
10
11
  stdoutReader: readline.Interface | null;
11
12
  stderrReader: readline.Interface | null;
@@ -36,6 +36,7 @@ export class CodexAppServerTransport extends EventEmitter {
36
36
  this.command = command;
37
37
  this.args = args;
38
38
  this.env = options.env && typeof options.env === "object" ? { ...options.env } : {};
39
+ this.ignoreCodexApiKey = options.ignoreCodexApiKey === true;
39
40
  this.child = null;
40
41
  this.stdoutReader = null;
41
42
  this.stderrReader = null;
@@ -87,13 +88,17 @@ export class CodexAppServerTransport extends EventEmitter {
87
88
  return;
88
89
  }
89
90
  this.log(`[codex-app-server] spawn ${[this.command, ...this.args].join(" ")} (cwd: ${this.cwd})`);
91
+ const env = {
92
+ ...process.env,
93
+ PWD: this.cwd,
94
+ ...this.env,
95
+ };
96
+ if (this.ignoreCodexApiKey) {
97
+ delete env.CODEX_API_KEY;
98
+ }
90
99
  const child = spawn(this.command, this.args, {
91
100
  cwd: this.cwd,
92
- env: {
93
- ...process.env,
94
- PWD: this.cwd,
95
- ...this.env,
96
- },
101
+ env,
97
102
  stdio: ["pipe", "pipe", "pipe"],
98
103
  });
99
104
  this.child = child;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@love-moon/ai-sdk",
3
- "version": "0.2.39",
3
+ "version": "0.2.40",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -17,6 +17,7 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "@anthropic-ai/claude-agent-sdk": "^0.2.72",
20
+ "@github/copilot-sdk": "^0.2.2",
20
21
  "@opencode-ai/sdk": "^1.2.25",
21
22
  "js-yaml": "^4.1.1",
22
23
  "zod": "^4.1.5"
@@ -25,5 +26,5 @@
25
26
  "@types/node": "^22.10.2",
26
27
  "typescript": "^5.6.3"
27
28
  },
28
- "gitCommitId": "30204c8"
29
+ "gitCommitId": "e08f8b6"
29
30
  }